Merge "Add new feature to let apps layout over status bar / system bar."
diff --git a/api/current.txt b/api/current.txt
index 233938b5..483283dc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23240,6 +23240,7 @@
     method public boolean dispatchUnhandledMove(android.view.View, int);
     method protected void dispatchVisibilityChanged(android.view.View, int);
     method public void dispatchWindowFocusChanged(boolean);
+    method public void dispatchWindowSystemUiVisiblityChanged(int);
     method public void dispatchWindowVisibilityChanged(int);
     method public void draw(android.graphics.Canvas);
     method protected void drawableStateChanged();
@@ -23353,6 +23354,7 @@
     method public int getVisibility();
     method public final int getWidth();
     method protected int getWindowAttachCount();
+    method public int getWindowSystemUiVisibility();
     method public android.os.IBinder getWindowToken();
     method public int getWindowVisibility();
     method public void getWindowVisibleDisplayFrame(android.graphics.Rect);
@@ -23456,6 +23458,7 @@
     method public boolean onTrackballEvent(android.view.MotionEvent);
     method protected void onVisibilityChanged(android.view.View, int);
     method public void onWindowFocusChanged(boolean);
+    method public void onWindowSystemUiVisibilityChanged(int);
     method protected void onWindowVisibilityChanged(int);
     method protected boolean overScrollBy(int, int, int, int, int, int, int, int, boolean);
     method public boolean performClick();
@@ -23473,6 +23476,7 @@
     method public boolean removeCallbacks(java.lang.Runnable);
     method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
+    method public void requestFitSystemWindows();
     method public final boolean requestFocus();
     method public final boolean requestFocus(int);
     method public boolean requestFocus(int, android.graphics.Rect);
@@ -23671,9 +23675,14 @@
     field public static final int SOUND_EFFECTS_ENABLED = 134217728; // 0x8000000
     field public static final deprecated int STATUS_BAR_HIDDEN = 1; // 0x1
     field public static final deprecated int STATUS_BAR_VISIBLE = 0; // 0x0
+    field public static final int SYSTEM_UI_FLAG_FULLSCREEN = 4; // 0x4
     field public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 2; // 0x2
+    field public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 1024; // 0x400
+    field public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512; // 0x200
+    field public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 256; // 0x100
     field public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 1; // 0x1
     field public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 0x0
+    field public static final int SYSTEM_UI_LAYOUT_FLAGS = 1536; // 0x600
     field public static final int TEXT_DIRECTION_ANY_RTL = 2; // 0x2
     field protected static int TEXT_DIRECTION_DEFAULT;
     field public static final int TEXT_DIRECTION_FIRST_STRONG = 1; // 0x1
@@ -24037,6 +24046,7 @@
     method public abstract void requestChildFocus(android.view.View, android.view.View);
     method public abstract boolean requestChildRectangleOnScreen(android.view.View, android.graphics.Rect, boolean);
     method public abstract void requestDisallowInterceptTouchEvent(boolean);
+    method public abstract void requestFitSystemWindows();
     method public abstract void requestLayout();
     method public abstract boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
     method public abstract void requestTransparentRegion(android.view.View);
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 24d3a6b..cff16ff 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -611,6 +611,10 @@
      * If the window hosting the ActionBar does not have the feature
      * {@link Window#FEATURE_ACTION_BAR_OVERLAY} it will resize application
      * content to fit the new space available.
+     *
+     * <p>If you are hiding the ActionBar through
+     * {@link View#SYSTEM_UI_FLAG_FULLSCREEN View.SYSTEM_UI_FLAG_FULLSCREEN},
+     * you should not call this function directly.
      */
     public abstract void show();
 
@@ -619,6 +623,12 @@
      * If the window hosting the ActionBar does not have the feature
      * {@link Window#FEATURE_ACTION_BAR_OVERLAY} it will resize application
      * content to fit the new space available.
+     *
+     * <p>Instead of calling this function directly, you can also cause an
+     * ActionBar using the overlay feature to hide through
+     * {@link View#SYSTEM_UI_FLAG_FULLSCREEN View.SYSTEM_UI_FLAG_FULLSCREEN}.
+     * Hiding the ActionBar through this system UI flag allows you to more
+     * seamlessly hide it in conjunction with other screen decorations.
      */
     public abstract void hide();
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6c964b0..81f3f6a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -765,7 +765,12 @@
      */
     static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400;
 
-    // note flag value 0x00000800 is now available for next flags...
+    /**
+     * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate
+     * that they are optional and should be skipped if the window has
+     * requested system UI flags that ignore those insets for layout.
+     */
+    static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800;
 
     /**
      * <p>This view doesn't show fading edges.</p>
@@ -1909,28 +1914,31 @@
     public static final int OVER_SCROLL_NEVER = 2;
 
     /**
-     * View has requested the system UI (status bar) to be visible (the default).
+     * Special constant for {@link #setSystemUiVisibility(int)}: View has
+     * requested the system UI (status bar) to be visible (the default).
      *
      * @see #setSystemUiVisibility(int)
      */
     public static final int SYSTEM_UI_FLAG_VISIBLE = 0;
 
     /**
-     * View has requested the system UI to enter an unobtrusive "low profile" mode.
+     * Flag for {@link #setSystemUiVisibility(int)}: View has requested the
+     * system UI to enter an unobtrusive "low profile" mode.
      *
-     * This is for use in games, book readers, video players, or any other "immersive" application
-     * where the usual system chrome is deemed too distracting. 
+     * <p>This is for use in games, book readers, video players, or any other
+     * "immersive" application where the usual system chrome is deemed too distracting. 
      *
-     * In low profile mode, the status bar and/or navigation icons may dim.
+     * <p>In low profile mode, the status bar and/or navigation icons may dim.
      *
      * @see #setSystemUiVisibility(int)
      */
     public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001;
 
     /**
-     * View has requested that the system navigation be temporarily hidden.
+     * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the
+     * system navigation be temporarily hidden.
      *
-     * This is an even less obtrusive state than that called for by
+     * <p>This is an even less obtrusive state than that called for by
      * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls
      * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause
      * those to disappear. This is useful (in conjunction with the
@@ -1938,14 +1946,92 @@
      * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN}
      * window flags) for displaying content using every last pixel on the display.
      *
-     * There is a limitation: because navigation controls are so important, the least user
-     * interaction will cause them to reappear immediately.
+     * <p>There is a limitation: because navigation controls are so important, the least user
+     * interaction will cause them to reappear immediately.  When this happens, both
+     * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically,
+     * so that both elements reappear at the same time.
      *
      * @see #setSystemUiVisibility(int)
      */
     public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002;
 
     /**
+     * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go
+     * into the normal fullscreen mode so that its content can take over the screen
+     * while still allowing the user to interact with the application.
+     *
+     * <p>This has the same visual effect as
+     * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN
+     * WindowManager.LayoutParams.FLAG_FULLSCREEN},
+     * meaning that non-critical screen decorations (such as the status bar) will be
+     * hidden while the user is in the View's window, focusing the experience on
+     * that content.  Unlike the window flag, if you are using ActionBar in
+     * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY
+     * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also
+     * hide the action bar.
+     *
+     * <p>This approach to going fullscreen is best used over the window flag when
+     * it is a transient state -- that is, the application does this at certain
+     * points in its user interaction where it wants to allow the user to focus
+     * on content, but not as a continuous state.  For situations where the application
+     * would like to simply stay full screen the entire time (such as a game that
+     * wants to take over the screen), the
+     * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag}
+     * is usually a better approach.  The state set here will be removed by the system
+     * in various situations (such as the user moving to another application) like
+     * the other system UI states.
+     *
+     * <p>When using this flag, the application should provide some easy facility
+     * for the user to go out of it.  A common example would be in an e-book
+     * reader, where tapping on the screen brings back whatever screen and UI
+     * decorations that had been hidden while the user was immersed in reading
+     * the book.
+     *
+     * @see #setSystemUiVisibility(int)
+     */
+    public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004;
+
+    /**
+     * Flag for {@link #setSystemUiVisibility(int)}: When using other layout
+     * flags, we would like a stable view of the content insets given to
+     * {@link #fitSystemWindows(Rect)}.  This means that the insets seen there
+     * will always represent the worst case that the application can expect
+     * as a continue state.  In practice this means with any of system bar,
+     * nav bar, and status bar shown, but not the space that would be needed
+     * for an input method.
+     *
+     * <p>If you are using ActionBar in
+     * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY
+     * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the
+     * insets it adds to those given to the application.
+     */
+    public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100;
+
+    /**
+     * Flag for {@link #setSystemUiVisibility(int)}: View would like its window
+     * to be layed out as if it has requested
+     * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't.  This
+     * allows it to avoid artifacts when switching in and out of that mode, at
+     * the expense that some of its user interface may be covered by screen
+     * decorations when they are shown.  You can perform layout of your inner
+     * UI elements to account for the navagation system UI through the
+     * {@link #fitSystemWindows(Rect)} method.
+     */
+    public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200;
+
+    /**
+     * Flag for {@link #setSystemUiVisibility(int)}: View would like its window
+     * to be layed out as if it has requested
+     * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't.  This
+     * allows it to avoid artifacts when switching in and out of that mode, at
+     * the expense that some of its user interface may be covered by screen
+     * decorations when they are shown.  You can perform layout of your inner
+     * UI elements to account for non-fullscreen system UI through the
+     * {@link #fitSystemWindows(Rect)} method.
+     */
+    public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400;
+
+    /**
      * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead.
      */
     public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE;
@@ -2055,17 +2141,6 @@
 
     /**
      * @hide
-     *
-     * NOTE: This flag may only be used in subtreeSystemUiVisibility, etc. etc.
-     *
-     * This hides HOME and RECENT and is provided for compatibility with interim implementations.
-     */
-    @Deprecated
-    public static final int STATUS_BAR_DISABLE_NAVIGATION = 
-            STATUS_BAR_DISABLE_HOME | STATUS_BAR_DISABLE_RECENT;
-
-    /**
-     * @hide
      */
     public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x0000FFFF;
 
@@ -2076,7 +2151,15 @@
      * @hide
      */
     public static final int SYSTEM_UI_CLEARABLE_FLAGS =
-            SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+            SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION
+            | SYSTEM_UI_FLAG_FULLSCREEN;
+
+    /**
+     * Flags that can impact the layout in relation to system UI.
+     */
+    public static final int SYSTEM_UI_LAYOUT_FLAGS =
+            SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+            | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
 
     /**
      * Find views that render the specified text.
@@ -4692,21 +4775,54 @@
     }
 
     /**
-     * Apply the insets for system windows to this view, if the FITS_SYSTEM_WINDOWS flag
-     * is set
+     * Called by the view hierarchy when the content insets for a window have
+     * changed, to allow it to adjust its content to fit within those windows.
+     * The content insets tell you the space that the status bar, input method,
+     * and other system windows infringe on the application's window.
      *
-     * @param insets Insets for system windows
+     * <p>You do not normally need to deal with this function, since the default
+     * window decoration given to applications takes care of applying it to the
+     * content of the window.  If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}
+     * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case,
+     * and your content can be placed under those system elements.  You can then
+     * use this method within your view hierarchy if you have parts of your UI
+     * which you would like to ensure are not being covered.
      *
-     * @return True if this view applied the insets, false otherwise
+     * <p>The default implementation of this method simply applies the content
+     * inset's to the view's padding.  This can be enabled through
+     * {@link #setFitsSystemWindows(boolean)}.  Alternatively, you can override
+     * the method and handle the insets however you would like.  Note that the
+     * insets provided by the framework are always relative to the far edges
+     * of the window, not accounting for the location of the called view within
+     * that window.  (In fact when this method is called you do not yet know
+     * where the layout will place the view, as it is done before layout happens.)
+     *
+     * <p>Note: unlike many View methods, there is no dispatch phase to this
+     * call.  If you are overriding it in a ViewGroup and want to allow the
+     * call to continue to your children, you must be sure to call the super
+     * implementation.
+     *
+     * @param insets Current content insets of the window.  Prior to
+     * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify
+     * the insets or else you and Android will be unhappy.
+     *
+     * @return Return true if this view applied the insets and it should not
+     * continue propagating further down the hierarchy, false otherwise.
      */
     protected boolean fitSystemWindows(Rect insets) {
         if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) {
-            mPaddingLeft = insets.left;
-            mPaddingTop = insets.top;
-            mPaddingRight = insets.right;
-            mPaddingBottom = insets.bottom;
-            requestLayout();
-            return true;
+            mUserPaddingStart = -1;
+            mUserPaddingEnd = -1;
+            mUserPaddingRelative = false;
+            if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0
+                    || mAttachInfo == null
+                    || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) {
+                internalSetPadding(insets.left, insets.top, insets.right, insets.bottom);
+                return true;
+            } else {
+                internalSetPadding(0, 0, 0, 0);
+                return false;
+            }
         }
         return false;
     }
@@ -4742,6 +4858,23 @@
     }
 
     /**
+     * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed.
+     */
+    public void requestFitSystemWindows() {
+        if (mParent != null) {
+            mParent.requestFitSystemWindows();
+        }
+    }
+
+    /**
+     * For use by PhoneWindow to make its own system window fitting optional.
+     * @hide
+     */
+    public void makeOptionalFitsSystemWindows() {
+        setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS);
+    }
+
+    /**
      * Returns the visibility status for this view.
      *
      * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
@@ -6118,19 +6251,19 @@
      * Private function to aggregate all per-view attributes in to the view
      * root.
      */
-    void dispatchCollectViewAttributes(int visibility) {
-        performCollectViewAttributes(visibility);
+    void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) {
+        performCollectViewAttributes(attachInfo, visibility);
     }
 
-    void performCollectViewAttributes(int visibility) {
-        if ((visibility & VISIBILITY_MASK) == VISIBLE && mAttachInfo != null) {
+    void performCollectViewAttributes(AttachInfo attachInfo, int visibility) {
+        if ((visibility & VISIBILITY_MASK) == VISIBLE) {
             if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) {
-                mAttachInfo.mKeepScreenOn = true;
+                attachInfo.mKeepScreenOn = true;
             }
-            mAttachInfo.mSystemUiVisibility |= mSystemUiVisibility;
+            attachInfo.mSystemUiVisibility |= mSystemUiVisibility;
             ListenerInfo li = mListenerInfo;
             if (li != null && li.mOnSystemUiVisibilityChangeListener != null) {
-                mAttachInfo.mHasSystemUiListeners = true;
+                attachInfo.mHasSystemUiListeners = true;
             }
         }
     }
@@ -10126,7 +10259,7 @@
             mAttachInfo.mScrollContainers.add(this);
             mPrivateFlags |= SCROLL_CONTAINER_ADDED;
         }
-        performCollectViewAttributes(visibility);
+        performCollectViewAttributes(mAttachInfo, visibility);
         onAttachedToWindow();
 
         ListenerInfo li = mListenerInfo;
@@ -13982,6 +14115,35 @@
     }
 
     /**
+     * Returns the current system UI visibility that is currently set for
+     * the entire window.  This is the combination of the
+     * {@link #setSystemUiVisibility(int)} values supplied by all of the
+     * views in the window.
+     */
+    public int getWindowSystemUiVisibility() {
+        return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0;
+    }
+
+    /**
+     * Override to find out when the window's requested system UI visibility
+     * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}.
+     * This is different from the callbacks recieved through
+     * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)}
+     * in that this is only telling you about the local request of the window,
+     * not the actual values applied by the system.
+     */
+    public void onWindowSystemUiVisibilityChanged(int visible) {
+    }
+
+    /**
+     * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down
+     * the view hierarchy.
+     */
+    public void dispatchWindowSystemUiVisiblityChanged(int visible) {
+        onWindowSystemUiVisibilityChanged(visible);
+    }
+
+    /**
      * Set a listener to receive callbacks when the visibility of the system bar changes.
      * @param l  The {@link OnSystemUiVisibilityChangeListener} to receive callbacks.
      */
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 30d6ec7..d5c783f 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -918,7 +918,20 @@
             }
         }
     }
-    
+
+    /**
+     * @hide
+     */
+    @Override
+    public void makeOptionalFitsSystemWindows() {
+        super.makeOptionalFitsSystemWindows();
+        final int count = mChildrenCount;
+        final View[] children = mChildren;
+        for (int i = 0; i < count; i++) {
+            children[i].makeOptionalFitsSystemWindows();
+        }
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -1017,13 +1030,16 @@
     }
 
     @Override
-    void dispatchCollectViewAttributes(int visibility) {
-        visibility |= mViewFlags&VISIBILITY_MASK;
-        super.dispatchCollectViewAttributes(visibility);
-        final int count = mChildrenCount;
-        final View[] children = mChildren;
-        for (int i = 0; i < count; i++) {
-            children[i].dispatchCollectViewAttributes(visibility);
+    void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) {
+        if ((visibility & VISIBILITY_MASK) == VISIBLE) {
+            super.dispatchCollectViewAttributes(attachInfo, visibility);
+            final int count = mChildrenCount;
+            final View[] children = mChildren;
+            for (int i = 0; i < count; i++) {
+                final View child = children[i];
+                child.dispatchCollectViewAttributes(attachInfo,
+                        visibility | (child.mViewFlags&VISIBILITY_MASK));
+            }
         }
     }
 
@@ -1239,6 +1255,18 @@
     }
 
     @Override
+    public void dispatchWindowSystemUiVisiblityChanged(int visible) {
+        super.dispatchWindowSystemUiVisiblityChanged(visible);
+
+        final int count = mChildrenCount;
+        final View[] children = mChildren;
+        for (int i=0; i <count; i++) {
+            final View child = children[i];
+            child.dispatchWindowSystemUiVisiblityChanged(visible);
+        }
+    }
+
+    @Override
     public void dispatchSystemUiVisibilityChanged(int visible) {
         super.dispatchSystemUiVisibilityChanged(visible);
 
@@ -2244,12 +2272,12 @@
         super.dispatchAttachedToWindow(info, visibility);
         mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
 
-        visibility |= mViewFlags & VISIBILITY_MASK;
-
         final int count = mChildrenCount;
         final View[] children = mChildren;
         for (int i = 0; i < count; i++) {
-            children[i].dispatchAttachedToWindow(info, visibility);
+            final View child = children[i];
+            child.dispatchAttachedToWindow(info,
+                    visibility | (child.mViewFlags&VISIBILITY_MASK));
         }
     }
 
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 8395f1b..75e9151 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -271,4 +271,10 @@
      * @hide
      */
     public void childHasTransientStateChanged(View child, boolean hasTransientState);
+
+    /**
+     * Ask that a new dispatch of {@link View#fitSystemWindows(Rect)
+     * View.fitSystemWindows(Rect)} be performed.
+     */
+    public void requestFitSystemWindows();
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4d589d7..d72f3b7 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -223,6 +223,7 @@
     long mLastTraversalFinishedTimeNanos;
     long mLastDrawFinishedTimeNanos;
     boolean mWillDrawSoon;
+    boolean mFitSystemWindowsRequested;
     boolean mLayoutRequested;
     boolean mFirst;
     boolean mReportNextDraw;
@@ -230,6 +231,7 @@
     boolean mNewSurfaceNeeded;
     boolean mHasHadWindowFocus;
     boolean mLastWasImTarget;
+    int mLastSystemUiVisibility;
 
     // Pool of queued input events.
     private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
@@ -263,6 +265,8 @@
     final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
             = new ViewTreeObserver.InternalInsetsInfo();
 
+    final Rect mFitSystemWindowsInsets = new Rect();
+
     final Configuration mLastConfiguration = new Configuration();
     final Configuration mPendingConfiguration = new Configuration();
 
@@ -539,6 +543,8 @@
                 }
                 try {
                     mOrigWindowType = mWindowAttributes.type;
+                    mAttachInfo.mRecomputeGlobalAttributes = true;
+                    collectViewAttributes();
                     res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,
                             getHostVisibility(), mAttachInfo.mContentInsets,
                             mInputChannel);
@@ -786,6 +792,15 @@
     /**
      * {@inheritDoc}
      */
+    public void requestFitSystemWindows() {
+        checkThread();
+        mFitSystemWindowsRequested = true;
+        scheduleTraversals();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public void requestLayout() {
         checkThread();
         mLayoutRequested = true;
@@ -974,6 +989,100 @@
         }
     }
 
+    private boolean collectViewAttributes() {
+        final View.AttachInfo attachInfo = mAttachInfo;
+        if (attachInfo.mRecomputeGlobalAttributes) {
+            //Log.i(TAG, "Computing view hierarchy attributes!");
+            attachInfo.mRecomputeGlobalAttributes = false;
+            boolean oldScreenOn = attachInfo.mKeepScreenOn;
+            int oldVis = attachInfo.mSystemUiVisibility;
+            boolean oldHasSystemUiListeners = attachInfo.mHasSystemUiListeners;
+            attachInfo.mKeepScreenOn = false;
+            attachInfo.mSystemUiVisibility = 0;
+            attachInfo.mHasSystemUiListeners = false;
+            mView.dispatchCollectViewAttributes(attachInfo, 0);
+            if (attachInfo.mKeepScreenOn != oldScreenOn
+                    || attachInfo.mSystemUiVisibility != oldVis
+                    || attachInfo.mHasSystemUiListeners != oldHasSystemUiListeners) {
+                WindowManager.LayoutParams params = mWindowAttributes;
+                if (attachInfo.mKeepScreenOn) {
+                    params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+                }
+                params.subtreeSystemUiVisibility = attachInfo.mSystemUiVisibility;
+                params.hasSystemUiListeners = attachInfo.mHasSystemUiListeners;
+                mView.dispatchWindowSystemUiVisiblityChanged(attachInfo.mSystemUiVisibility);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
+            final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
+        int childWidthMeasureSpec;
+        int childHeightMeasureSpec;
+        boolean windowSizeMayChange = false;
+
+        if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
+                "Measuring " + host + " in display " + desiredWindowWidth
+                + "x" + desiredWindowHeight + "...");
+
+        boolean goodMeasure = false;
+        if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
+            // On large screens, we don't want to allow dialogs to just
+            // stretch to fill the entire width of the screen to display
+            // one line of text.  First try doing the layout at a smaller
+            // size to see if it will fit.
+            final DisplayMetrics packageMetrics = res.getDisplayMetrics();
+            res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
+            int baseSize = 0;
+            if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
+                baseSize = (int)mTmpValue.getDimension(packageMetrics);
+            }
+            if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
+            if (baseSize != 0 && desiredWindowWidth > baseSize) {
+                childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
+                childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
+                host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+                if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
+                        + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
+                if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
+                    goodMeasure = true;
+                } else {
+                    // Didn't fit in that size... try expanding a bit.
+                    baseSize = (baseSize+desiredWindowWidth)/2;
+                    if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
+                            + baseSize);
+                    childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
+                    host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+                    if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
+                            + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
+                    if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
+                        if (DEBUG_DIALOG) Log.v(TAG, "Good!");
+                        goodMeasure = true;
+                    }
+                }
+            }
+        }
+
+        if (!goodMeasure) {
+            childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
+            childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
+            host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+            if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
+                windowSizeMayChange = true;
+            }
+        }
+
+        if (DBG) {
+            System.out.println("======================================");
+            System.out.println("performTraversals -- after measure");
+            host.debug();
+        }
+
+        return windowSizeMayChange;
+    }
+
     private void performTraversals() {
         // cache mView since it is used so much below...
         final View host = mView;
@@ -995,8 +1104,6 @@
 
         int desiredWindowWidth;
         int desiredWindowHeight;
-        int childWidthMeasureSpec;
-        int childHeightMeasureSpec;
 
         final View.AttachInfo attachInfo = mAttachInfo;
 
@@ -1057,15 +1164,14 @@
             attachInfo.mHasWindowFocus = false;
             attachInfo.mWindowVisibility = viewVisibility;
             attachInfo.mRecomputeGlobalAttributes = false;
-            attachInfo.mKeepScreenOn = false;
-            attachInfo.mSystemUiVisibility = 0;
             viewVisibilityChanged = false;
             mLastConfiguration.setTo(host.getResources().getConfiguration());
+            mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
             host.dispatchAttachedToWindow(attachInfo, 0);
+            mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
+            host.fitSystemWindows(mFitSystemWindowsInsets);
             //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
 
-            host.fitSystemWindows(mAttachInfo.mContentInsets);
-
         } else {
             desiredWindowWidth = frame.width();
             desiredWindowHeight = frame.height();
@@ -1093,7 +1199,8 @@
 
         boolean insetsChanged = false;
 
-        if (mLayoutRequested && !mStopped) {
+        boolean layoutRequested = mLayoutRequested && !mStopped;
+        if (layoutRequested) {
             // Execute enqueued actions on every layout in case a view that was detached
             // enqueued an action after being detached
             getRunQueue().executeActions(attachInfo.mHandler);
@@ -1134,79 +1241,12 @@
             }
 
             // Ask host how big it wants to be
-            if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
-                    "Measuring " + host + " in display " + desiredWindowWidth
-                    + "x" + desiredWindowHeight + "...");
-
-            boolean goodMeasure = false;
-            if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
-                // On large screens, we don't want to allow dialogs to just
-                // stretch to fill the entire width of the screen to display
-                // one line of text.  First try doing the layout at a smaller
-                // size to see if it will fit.
-                final DisplayMetrics packageMetrics = res.getDisplayMetrics();
-                res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
-                int baseSize = 0;
-                if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
-                    baseSize = (int)mTmpValue.getDimension(packageMetrics);
-                }
-                if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
-                if (baseSize != 0 && desiredWindowWidth > baseSize) {
-                    childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
-                    childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
-                    host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
-                    if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
-                            + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
-                    if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
-                        goodMeasure = true;
-                    } else {
-                        // Didn't fit in that size... try expanding a bit.
-                        baseSize = (baseSize+desiredWindowWidth)/2;
-                        if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
-                                + baseSize);
-                        childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
-                        host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
-                        if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
-                                + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
-                        if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
-                            if (DEBUG_DIALOG) Log.v(TAG, "Good!");
-                            goodMeasure = true;
-                        }
-                    }
-                }
-            }
-
-            if (!goodMeasure) {
-                childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
-                childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
-                host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
-                if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
-                    windowSizeMayChange = true;
-                }
-            }
-
-            if (DBG) {
-                System.out.println("======================================");
-                System.out.println("performTraversals -- after measure");
-                host.debug();
-            }
+            windowSizeMayChange |= measureHierarchy(host, lp, res,
+                    desiredWindowWidth, desiredWindowHeight);
         }
 
-        if (attachInfo.mRecomputeGlobalAttributes && host.mAttachInfo != null) {
-            //Log.i(TAG, "Computing view hierarchy attributes!");
-            attachInfo.mRecomputeGlobalAttributes = false;
-            boolean oldScreenOn = attachInfo.mKeepScreenOn;
-            int oldVis = attachInfo.mSystemUiVisibility;
-            boolean oldHasSystemUiListeners = attachInfo.mHasSystemUiListeners;
-            attachInfo.mKeepScreenOn = false;
-            attachInfo.mSystemUiVisibility = 0;
-            attachInfo.mHasSystemUiListeners = false;
-            host.dispatchCollectViewAttributes(0);
-            if (attachInfo.mKeepScreenOn != oldScreenOn
-                    || attachInfo.mSystemUiVisibility != oldVis
-                    || attachInfo.mHasSystemUiListeners != oldHasSystemUiListeners) {
-                params = lp;
-            }
+        if (collectViewAttributes()) {
+            params = lp;
         }
         if (attachInfo.mForceReportNewAttributes) {
             attachInfo.mForceReportNewAttributes = false;
@@ -1245,7 +1285,28 @@
             }
         }
 
-        boolean windowShouldResize = mLayoutRequested && windowSizeMayChange
+        if (mFitSystemWindowsRequested) {
+            mFitSystemWindowsRequested = false;
+            mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
+            host.fitSystemWindows(mFitSystemWindowsInsets);
+            if (mLayoutRequested) {
+                // Short-circuit catching a new layout request here, so
+                // we don't need to go through two layout passes when things
+                // change due to fitting system windows, which can happen a lot.
+                windowSizeMayChange |= measureHierarchy(host, lp,
+                        mView.getContext().getResources(),
+                        desiredWindowWidth, desiredWindowHeight);
+            }
+        }
+
+        if (layoutRequested) {
+            // Clear this now, so that if anything requests a layout in the
+            // rest of this function we will catch it and re-run a full
+            // layout pass.
+            mLayoutRequested = false;
+        }
+
+        boolean windowShouldResize = layoutRequested && windowSizeMayChange
             && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
                 || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
                         frame.width() < desiredWindowWidth && frame.width() != mWidth)
@@ -1285,15 +1346,6 @@
             boolean hadSurface = mSurface.isValid();
 
             try {
-                int fl = 0;
-                if (params != null) {
-                    fl = params.flags;
-                    if (attachInfo.mKeepScreenOn) {
-                        params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
-                    }
-                    params.subtreeSystemUiVisibility = attachInfo.mSystemUiVisibility;
-                    params.hasSystemUiListeners = attachInfo.mHasSystemUiListeners;
-                }
                 if (DEBUG_LAYOUT) {
                     Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
                             host.getMeasuredHeight() + ", params=" + params);
@@ -1302,10 +1354,6 @@
                 final int surfaceGenerationId = mSurface.getGenerationId();
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
 
-                if (params != null) {
-                    params.flags = fl;
-                }
-
                 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
                         + " content=" + mPendingContentInsets.toShortString()
                         + " visible=" + mPendingVisibleInsets.toShortString()
@@ -1323,7 +1371,9 @@
                 visibleInsetsChanged = !mPendingVisibleInsets.equals(
                         mAttachInfo.mVisibleInsets);
                 if (contentInsetsChanged) {
-                    if (mWidth > 0 && mHeight > 0 &&
+                    if (mWidth > 0 && mHeight > 0 && lp != null &&
+                            ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility)
+                                    & View.SYSTEM_UI_LAYOUT_FLAGS) == 0 &&
                             mSurface != null && mSurface.isValid() &&
                             !mAttachInfo.mTurnOffWindowResizeAnim &&
                             mAttachInfo.mHardwareRenderer != null &&
@@ -1390,10 +1440,16 @@
                         }
                     }
                     mAttachInfo.mContentInsets.set(mPendingContentInsets);
-                    host.fitSystemWindows(mAttachInfo.mContentInsets);
                     if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
                             + mAttachInfo.mContentInsets);
                 }
+                if (contentInsetsChanged || mLastSystemUiVisibility !=
+                        mAttachInfo.mSystemUiVisibility || mFitSystemWindowsRequested) {
+                    mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
+                    mFitSystemWindowsRequested = false;
+                    mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
+                    host.fitSystemWindows(mFitSystemWindowsInsets);
+                }
                 if (visibleInsetsChanged) {
                     mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
                     if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
@@ -1547,8 +1603,8 @@
                         (relayoutResult&WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
                 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
                         || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
-                    childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
-                    childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
+                    int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
+                    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
     
                     if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed!  mWidth="
                             + mWidth + " measuredWidth=" + host.getMeasuredWidth()
@@ -1586,12 +1642,12 @@
                         host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
                     }
     
-                    mLayoutRequested = true;
+                    layoutRequested = true;
                 }
             }
         }
 
-        final boolean didLayout = mLayoutRequested && !mStopped;
+        final boolean didLayout = layoutRequested && !mStopped;
         boolean triggerGlobalLayoutListener = didLayout
                 || attachInfo.mRecomputeGlobalAttributes;
         if (didLayout) {
@@ -3579,9 +3635,6 @@
         if (mView == null) return;
         if (args.localChanges != 0) {
             if (mAttachInfo != null) {
-                mAttachInfo.mSystemUiVisibility =
-                        (mAttachInfo.mSystemUiVisibility & ~args.localChanges) |
-                                (args.localValue & args.localChanges);
                 mAttachInfo.mRecomputeGlobalAttributes = true;
             }
             mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index a99ac03..b0e90db 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -75,6 +75,16 @@
      * over how the Action Bar is displayed, such as letting application content scroll beneath
      * an Action Bar with a transparent background or otherwise displaying a transparent/translucent
      * Action Bar over application content.
+     *
+     * <p>This mode is especially useful with {@link View#SYSTEM_UI_FLAG_FULLSCREEN
+     * View.SYSTEM_UI_FLAG_FULLSCREEN}, which allows you to seamlessly hide the
+     * action bar in conjunction with other screen decorations.
+     *
+     * <p>As of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}, when an
+     * ActionBar is in this mode it will adjust the insets provided to
+     * {@link View#fitSystemWindows(android.graphics.Rect) View.fitSystemWindows(Rect)}
+     * to include the content covered by the action bar, so you can do layout within
+     * that space.
      */
     public static final int FEATURE_ACTION_BAR_OVERLAY = 9;
     /**
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index f3486bd..3115eff 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -21,6 +21,7 @@
 import com.android.internal.view.menu.SubMenuBuilder;
 import com.android.internal.widget.ActionBarContainer;
 import com.android.internal.widget.ActionBarContextView;
+import com.android.internal.widget.ActionBarOverlayLayout;
 import com.android.internal.widget.ActionBarView;
 import com.android.internal.widget.ScrollingTabContainerView;
 
@@ -47,6 +48,7 @@
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.Window;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.SpinnerAdapter;
@@ -69,7 +71,9 @@
     private Activity mActivity;
     private Dialog mDialog;
 
+    private ActionBarOverlayLayout mOverlayLayout;
     private ActionBarContainer mContainerView;
+    private ViewGroup mTopVisibilityView;
     private ActionBarView mActionView;
     private ActionBarContextView mContextView;
     private ActionBarContainer mSplitView;
@@ -100,6 +104,8 @@
     final Handler mHandler = new Handler();
     Runnable mTabSelector;
 
+    private int mCurWindowVisibility = View.VISIBLE;
+
     private Animator mCurrentShowAnim;
     private Animator mCurrentModeAnim;
     private boolean mShowHideAnimationEnabled;
@@ -110,12 +116,12 @@
         public void onAnimationEnd(Animator animation) {
             if (mContentView != null) {
                 mContentView.setTranslationY(0);
-                mContainerView.setTranslationY(0);
+                mTopVisibilityView.setTranslationY(0);
             }
             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                 mSplitView.setVisibility(View.GONE);
             }
-            mContainerView.setVisibility(View.GONE);
+            mTopVisibilityView.setVisibility(View.GONE);
             mContainerView.setTransitioning(false);
             mCurrentShowAnim = null;
             completeDeferredDestroyActionMode();
@@ -126,7 +132,7 @@
         @Override
         public void onAnimationEnd(Animator animation) {
             mCurrentShowAnim = null;
-            mContainerView.requestLayout();
+            mTopVisibilityView.requestLayout();
         }
     };
 
@@ -147,11 +153,21 @@
 
     private void init(View decor) {
         mContext = decor.getContext();
+        mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
+                com.android.internal.R.id.action_bar_overlay_layout);
+        if (mOverlayLayout != null) {
+            mOverlayLayout.setActionBar(this);
+        }
         mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
         mContextView = (ActionBarContextView) decor.findViewById(
                 com.android.internal.R.id.action_context_bar);
         mContainerView = (ActionBarContainer) decor.findViewById(
                 com.android.internal.R.id.action_bar_container);
+        mTopVisibilityView = (ViewGroup)decor.findViewById(
+                com.android.internal.R.id.top_action_bar);
+        if (mTopVisibilityView == null) {
+            mTopVisibilityView = mContainerView;
+        }
         mSplitView = (ActionBarContainer) decor.findViewById(
                 com.android.internal.R.id.split_action_bar);
 
@@ -190,11 +206,22 @@
         }
         final boolean isInTabMode = getNavigationMode() == NAVIGATION_MODE_TABS;
         if (mTabScrollView != null) {
-            mTabScrollView.setVisibility(isInTabMode ? View.VISIBLE : View.GONE);
+            if (isInTabMode) {
+                mTabScrollView.setVisibility(View.VISIBLE);
+                if (mOverlayLayout != null) {
+                    mOverlayLayout.requestFitSystemWindows();
+                }
+            } else {
+                mTabScrollView.setVisibility(View.GONE);
+            }
         }
         mActionView.setCollapsable(!mHasEmbeddedTabs && isInTabMode);
     }
 
+    public boolean hasNonEmbeddedTabs() {
+        return !mHasEmbeddedTabs && getNavigationMode() == NAVIGATION_MODE_TABS;
+    }
+
     private void ensureTabsExist() {
         if (mTabScrollView != null) {
             return;
@@ -206,8 +233,14 @@
             tabScroller.setVisibility(View.VISIBLE);
             mActionView.setEmbeddedTabView(tabScroller);
         } else {
-            tabScroller.setVisibility(getNavigationMode() == NAVIGATION_MODE_TABS ?
-                    View.VISIBLE : View.GONE);
+            if (getNavigationMode() == NAVIGATION_MODE_TABS) {
+                tabScroller.setVisibility(View.VISIBLE);
+                if (mOverlayLayout != null) {
+                    mOverlayLayout.requestFitSystemWindows();
+                }
+            } else {
+                tabScroller.setVisibility(View.GONE);
+            }
             mContainerView.setTabContainer(tabScroller);
         }
         mTabScrollView = tabScroller;
@@ -221,6 +254,10 @@
         }
     }
 
+    public void setWindowVisibility(int visibility) {
+        mCurWindowVisibility = visibility;
+    }
+
     /**
      * Enables or disables animation between show/hide states.
      * If animation is disabled using this method, animations in progress
@@ -396,7 +433,12 @@
             animateToMode(true);
             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                 // TODO animate this
-                mSplitView.setVisibility(View.VISIBLE);
+                if (mSplitView.getVisibility() != View.VISIBLE) {
+                    mSplitView.setVisibility(View.VISIBLE);
+                    if (mOverlayLayout != null) {
+                        mOverlayLayout.requestFitSystemWindows();
+                    }
+                }
             }
             mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
             mActionMode = mode;
@@ -530,28 +572,29 @@
 
     @Override
     public void show() {
-        show(true);
+        show(true, false);
     }
 
-    void show(boolean markHiddenBeforeMode) {
+    public void show(boolean markHiddenBeforeMode, boolean alwaysAnimate) {
         if (mCurrentShowAnim != null) {
             mCurrentShowAnim.end();
         }
-        if (mContainerView.getVisibility() == View.VISIBLE) {
+        if (mTopVisibilityView.getVisibility() == View.VISIBLE) {
             if (markHiddenBeforeMode) mWasHiddenBeforeMode = false;
             return;
         }
-        mContainerView.setVisibility(View.VISIBLE);
+        mTopVisibilityView.setVisibility(View.VISIBLE);
 
-        if (mShowHideAnimationEnabled) {
-            mContainerView.setAlpha(0);
+        if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
+                || alwaysAnimate)) {
+            mTopVisibilityView.setAlpha(0);
             AnimatorSet anim = new AnimatorSet();
-            AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 1));
+            AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView, "alpha", 1));
             if (mContentView != null) {
                 b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
-                        -mContainerView.getHeight(), 0));
-                mContainerView.setTranslationY(-mContainerView.getHeight());
-                b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0));
+                        -mTopVisibilityView.getHeight(), 0));
+                mTopVisibilityView.setTranslationY(-mTopVisibilityView.getHeight());
+                b.with(ObjectAnimator.ofFloat(mTopVisibilityView, "translationY", 0));
             }
             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                 mSplitView.setAlpha(0);
@@ -562,7 +605,7 @@
             mCurrentShowAnim = anim;
             anim.start();
         } else {
-            mContainerView.setAlpha(1);
+            mTopVisibilityView.setAlpha(1);
             mContainerView.setTranslationY(0);
             mShowListener.onAnimationEnd(null);
         }
@@ -570,23 +613,28 @@
 
     @Override
     public void hide() {
+        hide(false);
+    }
+
+    public void hide(boolean alwaysAnimate) {
         if (mCurrentShowAnim != null) {
             mCurrentShowAnim.end();
         }
-        if (mContainerView.getVisibility() == View.GONE) {
+        if (mTopVisibilityView.getVisibility() == View.GONE) {
             return;
         }
 
-        if (mShowHideAnimationEnabled) {
-            mContainerView.setAlpha(1);
+        if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
+                || alwaysAnimate)) {
+            mTopVisibilityView.setAlpha(1);
             mContainerView.setTransitioning(true);
             AnimatorSet anim = new AnimatorSet();
-            AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 0));
+            AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView, "alpha", 0));
             if (mContentView != null) {
                 b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
-                        0, -mContainerView.getHeight()));
-                b.with(ObjectAnimator.ofFloat(mContainerView, "translationY",
-                        -mContainerView.getHeight()));
+                        0, -mTopVisibilityView.getHeight()));
+                b.with(ObjectAnimator.ofFloat(mTopVisibilityView, "translationY",
+                        -mTopVisibilityView.getHeight()));
             }
             if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) {
                 mSplitView.setAlpha(1);
@@ -601,12 +649,12 @@
     }
 
     public boolean isShowing() {
-        return mContainerView.getVisibility() == View.VISIBLE;
+        return mTopVisibilityView.getVisibility() == View.VISIBLE;
     }
 
     void animateToMode(boolean toActionMode) {
         if (toActionMode) {
-            show(false);
+            show(false, false);
         }
         if (mCurrentModeAnim != null) {
             mCurrentModeAnim.end();
@@ -980,6 +1028,11 @@
                 mTabScrollView.setVisibility(View.GONE);
                 break;
         }
+        if (oldMode != mode && !mHasEmbeddedTabs) {
+            if (mOverlayLayout != null) {
+                mOverlayLayout.requestFitSystemWindows();
+            }
+        }
         mActionView.setNavigationMode(mode);
         switch (mode) {
             case NAVIGATION_MODE_TABS:
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 6e36fdb..294d4c4 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -30,7 +30,7 @@
     void disable(int state);
     void animateExpand();
     void animateCollapse();
-    void setSystemUiVisibility(int vis);
+    void setSystemUiVisibility(int vis, int mask);
     void topAppWindowChanged(boolean menuVisible);
     void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
     void setHardKeyboardStatus(boolean available, boolean enabled);
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 118e541..c64f170 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -44,7 +44,7 @@
             int uid, int initialPid, String message);
     void onClearAllNotifications();
     void onNotificationClear(String pkg, String tag, int id);
-    void setSystemUiVisibility(int vis);
+    void setSystemUiVisibility(int vis, int mask);
     void setHardKeyboardEnabled(boolean enabled);
     void toggleRecentApps();
     void preloadRecentApps();
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
new file mode 100644
index 0000000..5f36bb6
--- /dev/null
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import com.android.internal.app.ActionBarImpl;
+
+import android.animation.LayoutTransition;
+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.view.ViewTreeObserver;
+import android.widget.FrameLayout;
+
+/**
+ * Special layout for the containing of an overlay action bar (and its
+ * content) to correctly handle fitting system windows when the content
+ * has request that its layout ignore them.
+ */
+public class ActionBarOverlayLayout extends FrameLayout {
+    private int mActionBarHeight;
+    private ActionBarImpl mActionBar;
+    private int mWindowVisibility = View.VISIBLE;
+    private View mContent;
+    private View mActionBarTop;
+    private ActionBarContainer mContainerView;
+    private ActionBarView mActionView;
+    private View mActionBarBottom;
+    private int mLastSystemUiVisibility;
+    private final Rect mZeroRect = new Rect(0, 0, 0, 0);
+
+    static final int[] mActionBarSizeAttr = new int [] {
+            com.android.internal.R.attr.actionBarSize
+    };
+
+    public ActionBarOverlayLayout(Context context) {
+        super(context);
+        init(context);
+    }
+
+    public ActionBarOverlayLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context);
+    }
+
+    private void init(Context context) {
+        TypedArray ta = getContext().getTheme().obtainStyledAttributes(mActionBarSizeAttr);
+        mActionBarHeight = ta.getDimensionPixelSize(0, 0);
+        ta.recycle();
+    }
+
+    public void setActionBar(ActionBarImpl impl) {
+        mActionBar = impl;
+        if (getWindowToken() != null) {
+            // This is being initialized after being added to a window;
+            // make sure to update all state now.
+            mActionBar.setWindowVisibility(mWindowVisibility);
+            if (mLastSystemUiVisibility != 0) {
+                int newVis = mLastSystemUiVisibility;
+                onWindowSystemUiVisibilityChanged(newVis);
+                requestFitSystemWindows();
+            }
+        }
+    }
+
+    @Override
+    public void onWindowSystemUiVisibilityChanged(int visible) {
+        super.onWindowSystemUiVisibilityChanged(visible);
+        pullChildren();
+        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) {
+            if (mActionBar != null) {
+                if (barVisible) mActionBar.show(true, true);
+                else mActionBar.hide(true);
+                requestFitSystemWindows();
+            }
+        }
+    }
+
+    @Override
+    protected void onWindowVisibilityChanged(int visibility) {
+        super.onWindowVisibilityChanged(visibility);
+        mWindowVisibility = visibility;
+        if (mActionBar != null) {
+            mActionBar.setWindowVisibility(visibility);
+        }
+    }
+
+    private boolean applyInsets(View view, Rect insets, boolean left, boolean top,
+            boolean bottom, boolean right) {
+        boolean changed = false;
+        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams)view.getLayoutParams();
+        if (left && lp.leftMargin != insets.left) {
+            changed = true;
+            lp.leftMargin = insets.left;
+        }
+        if (top && lp.topMargin != insets.top) {
+            changed = true;
+            lp.topMargin = insets.top;
+        }
+        if (right && lp.rightMargin != insets.right) {
+            changed = true;
+            lp.rightMargin = insets.right;
+        }
+        if (bottom && lp.bottomMargin != insets.bottom) {
+            changed = true;
+            lp.bottomMargin = insets.bottom;
+        }
+        return changed;
+    }
+
+    @Override
+    protected boolean fitSystemWindows(Rect insets) {
+        pullChildren();
+
+        final int vis = getWindowSystemUiVisibility();
+        final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
+
+        // The top and bottom action bars are always within the content area.
+        boolean changed = applyInsets(mActionBarTop, insets, true, true, false, true);
+        changed |= applyInsets(mActionBarBottom, insets, true, false, true, true);
+
+        // If the window has not requested system UI layout flags, we need to
+        // make sure its content is not being covered by system UI...  though it
+        // will still be covered by the action bar since they have requested it to
+        // overlay.
+        if ((vis & SYSTEM_UI_LAYOUT_FLAGS) == 0) {
+            changed |= applyInsets(mContent, insets, true, true, true, true);
+            // The insets are now consumed.
+            insets.set(0, 0, 0, 0);
+        } else {
+            changed |= applyInsets(mContent, mZeroRect, true, true, true, true);
+        }
+
+
+        if (stable || mActionBarTop.getVisibility() == VISIBLE) {
+            // The action bar creates additional insets for its content to use.
+            insets.top += mActionBarHeight;
+        }
+
+        if (mActionBar != null && mActionBar.hasNonEmbeddedTabs()) {
+            View tabs = mContainerView.getTabContainer();
+            if (stable || (tabs != null && tabs.getVisibility() == VISIBLE)) {
+                // If tabs are not embedded, adjust insets to account for them.
+                insets.top += mActionBarHeight;
+            }
+        }
+
+        if (mActionView.isSplitActionBar()) {
+            if (stable || (mActionBarBottom != null
+                    && mActionBarBottom.getVisibility() == VISIBLE)) {
+                // If action bar is split, adjust buttom insets for it.
+                insets.bottom += mActionBarHeight;
+            }
+        }
+
+        if (changed) {
+            requestLayout();
+        }
+
+        return super.fitSystemWindows(insets);
+    }
+
+    void pullChildren() {
+        if (mContent == null) {
+            mContent = findViewById(com.android.internal.R.id.content);
+            mActionBarTop = findViewById(com.android.internal.R.id.top_action_bar);
+            mContainerView = (ActionBarContainer)findViewById(
+                    com.android.internal.R.id.action_bar_container);
+            mActionView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
+            mActionBarBottom = findViewById(com.android.internal.R.id.split_action_bar);
+        }
+    }
+}
diff --git a/core/res/res/layout-xlarge/screen_action_bar_overlay.xml b/core/res/res/layout-xlarge/screen_action_bar_overlay.xml
index 89f0d89..f2a1ea1 100644
--- a/core/res/res/layout-xlarge/screen_action_bar_overlay.xml
+++ b/core/res/res/layout-xlarge/screen_action_bar_overlay.xml
@@ -19,31 +19,39 @@
 the Action Bar enabled overlaying application content.
 -->
 
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:fitsSystemWindows="true">
+<com.android.internal.widget.ActionBarOverlayLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/action_bar_overlay_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
     <FrameLayout android:id="@android:id/content"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
-    <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="?android:attr/actionBarStyle"
-        android:gravity="top">
-        <com.android.internal.widget.ActionBarView
-            android:id="@+id/action_bar"
+    <LinearLayout android:id="@+id/top_action_bar"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:layout_gravity="top">
+        <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            style="?android:attr/actionBarStyle" />
-        <com.android.internal.widget.ActionBarContextView
-            android:id="@+id/action_context_bar"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:visibility="gone"
-            style="?android:attr/actionModeStyle" />
-    </com.android.internal.widget.ActionBarContainer>
-    <ImageView android:src="?android:attr/windowContentOverlay"
-               android:scaleType="fitXY"
-               android:layout_width="match_parent"
-               android:layout_height="wrap_content"
-               android:layout_below="@id/action_bar_container" />
-</RelativeLayout>
+            android:layout_alignParentTop="true"
+            style="?android:attr/actionBarStyle"
+            android:gravity="top">
+            <com.android.internal.widget.ActionBarView
+                android:id="@+id/action_bar"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                style="?android:attr/actionBarStyle" />
+            <com.android.internal.widget.ActionBarContextView
+                android:id="@+id/action_context_bar"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:visibility="gone"
+                style="?android:attr/actionModeStyle" />
+        </com.android.internal.widget.ActionBarContainer>
+        <ImageView android:src="?android:attr/windowContentOverlay"
+                   android:scaleType="fitXY"
+                   android:layout_width="match_parent"
+                   android:layout_height="wrap_content" />
+    </LinearLayout>
+</com.android.internal.widget.ActionBarOverlayLayout>
diff --git a/core/res/res/layout/screen_action_bar_overlay.xml b/core/res/res/layout/screen_action_bar_overlay.xml
index 2a8c7c3..20a7db1 100644
--- a/core/res/res/layout/screen_action_bar_overlay.xml
+++ b/core/res/res/layout/screen_action_bar_overlay.xml
@@ -19,14 +19,16 @@
 the Action Bar enabled overlaying application content.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.internal.widget.ActionBarOverlayLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/action_bar_overlay_layout"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
+    android:layout_height="match_parent">
     <FrameLayout android:id="@android:id/content"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
-    <LinearLayout android:layout_width="match_parent"
+    <LinearLayout android:id="@+id/top_action_bar"
+                  android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   android:layout_gravity="top">
         <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
@@ -50,8 +52,7 @@
         <ImageView android:src="?android:attr/windowContentOverlay"
                    android:scaleType="fitXY"
                    android:layout_width="match_parent"
-                   android:layout_height="wrap_content"
-                   android:layout_below="@id/action_bar_container" />
+                   android:layout_height="wrap_content" />
     </LinearLayout>
     <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
                   android:layout_width="match_parent"
@@ -60,4 +61,4 @@
                   style="?android:attr/actionBarSplitStyle"
                   android:visibility="gone"
                   android:gravity="center"/>
-</FrameLayout>
+</com.android.internal.widget.ActionBarOverlayLayout>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7b4f50b..5af4f72 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -34,6 +34,7 @@
   <java-symbol type="id" name="account_type" />
   <java-symbol type="id" name="action_bar" />
   <java-symbol type="id" name="action_bar_container" />
+  <java-symbol type="id" name="action_bar_overlay_layout" />
   <java-symbol type="id" name="action_bar_title" />
   <java-symbol type="id" name="action_bar_subtitle" />
   <java-symbol type="id" name="action_context_bar" />
@@ -183,6 +184,7 @@
   <java-symbol type="id" name="to_common" />
   <java-symbol type="id" name="to_org" />
   <java-symbol type="id" name="to_org_unit" />
+  <java-symbol type="id" name="top_action_bar" />
   <java-symbol type="id" name="topPanel" />
   <java-symbol type="id" name="up" />
   <java-symbol type="id" name="value" />
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 23222f2..2fb61b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -119,7 +119,7 @@
         createAndAddWindows();
 
         disable(switches[0]);
-        setSystemUiVisibility(switches[1]);
+        setSystemUiVisibility(switches[1], 0xffffffff);
         topAppWindowChanged(switches[2] != 0);
         // StatusBarManagerService has a back up of IME token and it's restored here.
         setImeWindowStatus(binders.get(0), switches[3], switches[4]);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 37ab58a..f88a3cc9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -89,7 +89,7 @@
         public void disable(int state);
         public void animateExpand();
         public void animateCollapse();
-        public void setSystemUiVisibility(int vis);
+        public void setSystemUiVisibility(int vis, int mask);
         public void topAppWindowChanged(boolean visible);
         public void setImeWindowStatus(IBinder token, int vis, int backDisposition);
         public void setHardKeyboardStatus(boolean available, boolean enabled);
@@ -165,10 +165,10 @@
         }
     }
 
-    public void setSystemUiVisibility(int vis) {
+    public void setSystemUiVisibility(int vis, int mask) {
         synchronized (mList) {
             mHandler.removeMessages(MSG_SET_SYSTEMUI_VISIBILITY);
-            mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, vis, 0, null).sendToTarget();
+            mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, vis, mask, null).sendToTarget();
         }
     }
 
@@ -279,7 +279,7 @@
                     }
                     break;
                 case MSG_SET_SYSTEMUI_VISIBILITY:
-                    mCallbacks.setSystemUiVisibility(msg.arg1);
+                    mCallbacks.setSystemUiVisibility(msg.arg1, msg.arg2);
                     break;
                 case MSG_TOP_APP_WINDOW_CHANGED:
                     mCallbacks.topAppWindowChanged(msg.arg1 != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 6574c7d..5582b0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -139,7 +139,7 @@
                 setLowProfile(false, false, false);
 
                 try {
-                    mBarService.setSystemUiVisibility(0);
+                    mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
                 } catch (android.os.RemoteException ex) {
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 7c679b2..dc2953e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1471,12 +1471,13 @@
     }
 
     @Override // CommandQueue
-    public void setSystemUiVisibility(int vis) {
-        final int old = mSystemUiVisibility;
-        final int diff = vis ^ old;
+    public void setSystemUiVisibility(int vis, int mask) {
+        final int oldVal = mSystemUiVisibility;
+        final int newVal = (oldVal&~mask) | (vis&mask);
+        final int diff = newVal ^ oldVal;
 
         if (diff != 0) {
-            mSystemUiVisibility = vis;
+            mSystemUiVisibility = newVal;
 
             if (0 != (diff & View.SYSTEM_UI_FLAG_LOW_PROFILE)) {
                 final boolean lightsOut = (0 != (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE));
@@ -1495,9 +1496,9 @@
     public void setLightsOn(boolean on) {
         Log.v(TAG, "setLightsOn(" + on + ")");
         if (on) {
-            setSystemUiVisibility(mSystemUiVisibility & ~View.SYSTEM_UI_FLAG_LOW_PROFILE);
+            setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
         } else {
-            setSystemUiVisibility(mSystemUiVisibility | View.SYSTEM_UI_FLAG_LOW_PROFILE);
+            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 2491d18..27bc972 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -594,7 +594,7 @@
                         mBarContents.setVisibility(View.VISIBLE);
 
                         try {
-                            mBarService.setSystemUiVisibility(View.STATUS_BAR_VISIBLE);
+                            mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
                         } catch (RemoteException ex) {
                             // system process dead
                         }
@@ -1165,14 +1165,20 @@
     }
 
     @Override // CommandQueue
-    public void setSystemUiVisibility(int vis) {
-        if (vis != mSystemUiVisibility) {
-            mSystemUiVisibility = vis;
+    public void setSystemUiVisibility(int vis, int mask) {
+        final int oldVal = mSystemUiVisibility;
+        final int newVal = (oldVal&~mask) | (vis&mask);
+        final int diff = newVal ^ oldVal;
 
-            mHandler.removeMessages(MSG_HIDE_CHROME);
-            mHandler.removeMessages(MSG_SHOW_CHROME);
-            mHandler.sendEmptyMessage(0 == (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) 
-                    ? MSG_SHOW_CHROME : MSG_HIDE_CHROME);
+        if (diff != 0) {
+            mSystemUiVisibility = newVal;
+
+            if (0 != (diff & View.SYSTEM_UI_FLAG_LOW_PROFILE)) {
+                mHandler.removeMessages(MSG_HIDE_CHROME);
+                mHandler.removeMessages(MSG_SHOW_CHROME);
+                mHandler.sendEmptyMessage(0 == (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) 
+                        ? MSG_SHOW_CHROME : MSG_HIDE_CHROME);
+            }
 
             notifyUiVisibilityChanged();
         }
@@ -1187,9 +1193,9 @@
 
         Slog.v(TAG, "setLightsOn(" + on + ")");
         if (on) {
-            setSystemUiVisibility(mSystemUiVisibility & ~View.SYSTEM_UI_FLAG_LOW_PROFILE);
+            setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
         } else {
-            setSystemUiVisibility(mSystemUiVisibility | View.SYSTEM_UI_FLAG_LOW_PROFILE);
+            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE);
         }
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 301dbf5..c3c49b0 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -2829,6 +2829,9 @@
         if (mContentParent == null) {
             mContentParent = generateLayout(mDecor);
 
+            // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
+            mDecor.makeOptionalFitsSystemWindows();
+
             mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
             if (mTitleView != null) {
                 if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 6214086..fb1e106 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -230,6 +230,13 @@
     static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
     static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
 
+    /**
+     * These are the system UI flags that, when changing, can cause the layout
+     * of the screen to change.
+     */
+    static final int SYSTEM_UI_CHANGING_LAYOUT =
+            View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
+
     // Useful scan codes.
     private static final int SW_LID = 0x00;
     private static final int BTN_MOUSE = 0x110;
@@ -391,6 +398,8 @@
     // that area of the display from all other windows.
     int mRestrictedScreenLeft, mRestrictedScreenTop;
     int mRestrictedScreenWidth, mRestrictedScreenHeight;
+    // For applications requesting stable content insets, these are them.
+    int mStableLeft, mStableTop, mStableRight, mStableBottom;
     // During layout, the current screen borders with all outer decoration
     // (status bar, input method dock) accounted for.
     int mCurLeft, mCurTop, mCurRight, mCurBottom;
@@ -1958,10 +1967,15 @@
                         // When the user taps down, we re-show the nav bar.
                         boolean changed = false;
                         synchronized (mLock) {
-                            // Any user activity always causes us to show the navigation controls,
-                            // if they had been hidden.
-                            int newVal = mResettingSystemUiFlags
-                                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+                            // Any user activity always causes us to show the
+                            // navigation controls, if they had been hidden.
+                            // We also clear the low profile and only content
+                            // flags so that tapping on the screen will atomically
+                            // restore all currently hidden screen decorations.
+                            int newVal = mResettingSystemUiFlags |
+                                    View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
+                                    View.SYSTEM_UI_FLAG_LOW_PROFILE |
+                                    View.SYSTEM_UI_FLAG_FULLSCREEN;
                             if (mResettingSystemUiFlags != newVal) {
                                 mResettingSystemUiFlags = newVal;
                                 changed = true;
@@ -1969,14 +1983,15 @@
                             // We don't allow the system's nav bar to be hidden
                             // again for 1 second, to prevent applications from
                             // spamming us and keeping it from being shown.
-                            newVal = mForceClearedSystemUiFlags
-                                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+                            newVal = mForceClearedSystemUiFlags |
+                                    View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
                             if (mForceClearedSystemUiFlags != newVal) {
                                 mForceClearedSystemUiFlags = newVal;
                                 changed = true;
                                 mHandler.postDelayed(new Runnable() {
                                     @Override public void run() {
                                         synchronized (mLock) {
+                                            // Clear flags.
                                             mForceClearedSystemUiFlags &=
                                                     ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
                                         }
@@ -2017,17 +2032,33 @@
 
     public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
         final int fl = attrs.flags;
-        
+
         if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
                 == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
-            contentInset.set(mCurLeft, mCurTop,
-                    (mRestrictedScreenLeft+mRestrictedScreenWidth) - mCurRight,
-                    (mRestrictedScreenTop+mRestrictedScreenHeight) - mCurBottom);
-        } else {
-            contentInset.setEmpty();
+            int availRight, availBottom;
+            if ((attrs.systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
+                availRight = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+                availBottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+            } else {
+                availRight = mRestrictedScreenLeft + mRestrictedScreenWidth;
+                availBottom = mRestrictedScreenTop + mRestrictedScreenHeight;
+            }
+            if ((attrs.systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
+                contentInset.set(mStableLeft, mStableTop,
+                        availRight - mStableRight, availBottom - mStableBottom);
+            } else if ((attrs.systemUiVisibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
+                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)) == 0) {
+                contentInset.set(mCurLeft, mCurTop,
+                        availRight - mCurRight, availBottom - mCurBottom);
+            } else {
+                contentInset.set(mCurLeft, mCurTop,
+                        availRight - mCurRight, availBottom - mCurBottom);
+            }
+            return;
         }
+        contentInset.setEmpty();
     }
-    
+
     /** {@inheritDoc} */
     public void beginLayoutLw(int displayWidth, int displayHeight, int displayRotation) {
         mUnrestrictedScreenLeft = mUnrestrictedScreenTop = 0;
@@ -2036,10 +2067,10 @@
         mRestrictedScreenLeft = mRestrictedScreenTop = 0;
         mRestrictedScreenWidth = displayWidth;
         mRestrictedScreenHeight = displayHeight;
-        mDockLeft = mContentLeft = mCurLeft = 0;
-        mDockTop = mContentTop = mCurTop = 0;
-        mDockRight = mContentRight = mCurRight = displayWidth;
-        mDockBottom = mContentBottom = mCurBottom = displayHeight;
+        mDockLeft = mContentLeft = mStableLeft = mCurLeft = 0;
+        mDockTop = mContentTop = mStableTop = mCurTop = 0;
+        mDockRight = mContentRight = mStableRight = mCurRight = displayWidth;
+        mDockBottom = mContentBottom = mStableBottom = mCurBottom = displayHeight;
         mDockLayer = 0x10000000;
 
         // start with the current dock rect, which will be (0,0,displayWidth,displayHeight)
@@ -2081,6 +2112,7 @@
                     // Portrait screen; nav bar goes on bottom.
                     mTmpNavigationFrame.set(0, displayHeight-mNavigationBarHeight,
                             displayWidth, displayHeight);
+                    mStableBottom = mTmpNavigationFrame.top;
                     if (navVisible) {
                         mDockBottom = mTmpNavigationFrame.top;
                         mRestrictedScreenHeight = mDockBottom - mDockTop;
@@ -2094,6 +2126,7 @@
                     // Landscape screen; nav bar goes to the right.
                     mTmpNavigationFrame.set(displayWidth-mNavigationBarWidth, 0,
                             displayWidth, displayHeight);
+                    mStableRight = mTmpNavigationFrame.left;
                     if (navVisible) {
                         mDockRight = mTmpNavigationFrame.left;
                         mRestrictedScreenWidth = mDockRight - mDockLeft;
@@ -2125,11 +2158,23 @@
             pf.bottom = df.bottom = vf.bottom = mDockBottom;
 
             mStatusBar.computeFrameLw(pf, df, vf, vf);
+            final Rect r = mStatusBar.getFrameLw();
+
+            // Compute the stable dimensions whether or not the status bar is hidden.
+            if (mStatusBarCanHide) {
+                if (mDockTop == r.top) mStableTop = r.bottom;
+                else if (mDockBottom == r.bottom) mStableBottom = r.top;
+            } else {
+                if (mStableTop == r.top) {
+                    mStableTop = r.bottom;
+                } else if (mStableBottom == r.bottom) {
+                    mStableBottom = r.top;
+                }
+            }
 
             if (mStatusBar.isVisibleLw()) {
                 // If the status bar is hidden, we don't want to cause
                 // windows behind it to scroll.
-                final Rect r = mStatusBar.getFrameLw();
                 if (mStatusBarCanHide) {
                     // Status bar may go away, so the screen area it occupies
                     // is available to apps but just covering them when the
@@ -2229,7 +2274,8 @@
 
         final int fl = attrs.flags;
         final int sim = attrs.softInputMode;
-        
+        final int sysUiFl = win.getSystemUiVisibility();
+
         final Rect pf = mTmpParentFrame;
         final Rect df = mTmpDisplayFrame;
         final Rect cf = mTmpContentFrame;
@@ -2250,7 +2296,8 @@
             final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
 
             if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
-                    == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
+                    == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)
+                    && (sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
                 if (DEBUG_LAYOUT)
                     Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() 
                             + "): IN_SCREEN, INSET_DECOR, !FULLSCREEN");
@@ -2286,6 +2333,17 @@
                                         "Laying out status bar window: (%d,%d - %d,%d)",
                                         pf.left, pf.top, pf.right, pf.bottom));
                         }
+                    } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
+                            && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+                            && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+                        // Asking for layout as if the nav bar is hidden, lets the
+                        // application extend into the unrestricted screen area.  We
+                        // only do this for application windows to ensure no window that
+                        // can be above the nav bar can do this.
+                        pf.left = df.left = mUnrestrictedScreenLeft;
+                        pf.top = df.top = mUnrestrictedScreenTop;
+                        pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+                        pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
                     } else {
                         pf.left = df.left = mRestrictedScreenLeft;
                         pf.top = df.top = mRestrictedScreenTop;
@@ -2303,6 +2361,14 @@
                         cf.right = mContentRight;
                         cf.bottom = mContentBottom;
                     }
+                    if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
+                        // If app is requesting a stable layout, don't let the
+                        // content insets go below the stable values.
+                        if (cf.left < mStableLeft) cf.left = mStableLeft;
+                        if (cf.top < mStableTop) cf.top = mStableTop;
+                        if (cf.right > mStableRight) cf.right = mStableRight;
+                        if (cf.bottom > mStableBottom) cf.bottom = mStableBottom;
+                    }
                     if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
                         vf.left = mCurLeft;
                         vf.top = mCurTop;
@@ -2312,7 +2378,9 @@
                         vf.set(cf);
                     }
                 }
-            } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) {
+            } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0 || (sysUiFl
+                    & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
                 if (DEBUG_LAYOUT)
                     Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN");
                 // A window that has requested to fill the entire screen just
@@ -2327,7 +2395,6 @@
                     pf.bottom = df.bottom = cf.bottom = hasNavBar
                                           ? mRestrictedScreenTop+mRestrictedScreenHeight
                                           : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
-
                     if (DEBUG_LAYOUT) {
                         Log.v(TAG, String.format(
                                     "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
@@ -2359,6 +2426,21 @@
                     pf.right = df.right = cf.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
                     pf.bottom = df.bottom = cf.bottom
                             = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+                } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
+                        && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+                        && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+                    // Asking for layout as if the nav bar is hidden, lets the
+                    // application extend into the unrestricted screen area.  We
+                    // only do this for application windows to ensure no window that
+                    // can be above the nav bar can do this.
+                    // XXX This assumes that an app asking for this will also
+                    // ask for layout in only content.  We can't currently figure out
+                    // what the screen would be if only laying out to hide the nav bar.
+                    pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
+                    pf.top = df.top = cf.top = mUnrestrictedScreenTop;
+                    pf.right = df.right = cf.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+                    pf.bottom = df.bottom = cf.bottom
+                            = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
                 } else {
                     pf.left = df.left = cf.left = mRestrictedScreenLeft;
                     pf.top = df.top = cf.top = mRestrictedScreenTop;
@@ -2366,6 +2448,14 @@
                     pf.bottom = df.bottom = cf.bottom
                             = mRestrictedScreenTop+mRestrictedScreenHeight;
                 }
+                if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
+                    // If app is requesting a stable layout, don't let the
+                    // content insets go below the stable values.
+                    if (cf.left < mStableLeft) cf.left = mStableLeft;
+                    if (cf.top < mStableTop) cf.top = mStableTop;
+                    if (cf.right > mStableRight) cf.right = mStableRight;
+                    if (cf.bottom > mStableBottom) cf.bottom = mStableBottom;
+                }
                 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
                     vf.left = mCurLeft;
                     vf.top = mCurTop;
@@ -2526,7 +2616,8 @@
                     Log.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
                             + " lp.flags=0x" + Integer.toHexString(lp.flags));
                 }
-                topIsFullscreen = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
+                topIsFullscreen = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0
+                        || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
                 // The subtle difference between the window for mTopFullscreenOpaqueWindowState
                 // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window
                 // has the FLAG_FULLSCREEN set.  Not sure if there is another way that to be the
@@ -2591,7 +2682,7 @@
             }
         }
 
-        if ((updateSystemUiVisibilityLw()&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0) {
+        if ((updateSystemUiVisibilityLw()&SYSTEM_UI_CHANGING_LAYOUT) != 0) {
             // If the navigation bar has been hidden or shown, we need to do another
             // layout pass to update that window.
             changes |= FINISH_LAYOUT_REDO_LAYOUT;
@@ -2638,7 +2729,7 @@
 
     public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
         mFocusedWindow = newFocus;
-        if ((updateSystemUiVisibilityLw()&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0) {
+        if ((updateSystemUiVisibilityLw()&SYSTEM_UI_CHANGING_LAYOUT) != 0) {
             // If the navigation bar has been hidden or shown, we need to do another
             // layout pass to update that window.
             return FINISH_LAYOUT_REDO_LAYOUT;
@@ -3998,7 +4089,7 @@
                     }
                     if (mStatusBarService != null) {
                         try {
-                            mStatusBarService.setSystemUiVisibility(visibility);
+                            mStatusBarService.setSystemUiVisibility(visibility, 0xffffffff);
                             mStatusBarService.topAppWindowChanged(needsMenu);
                         } catch (RemoteException e) {
                             // not much to be done
@@ -4065,6 +4156,10 @@
                 pw.print(","); pw.print(mRestrictedScreenTop);
                 pw.print(") "); pw.print(mRestrictedScreenWidth);
                 pw.print("x"); pw.println(mRestrictedScreenHeight);
+        pw.print(prefix); pw.print("mStable=("); pw.print(mStableLeft);
+                pw.print(","); pw.print(mStableTop);
+                pw.print(")-("); pw.print(mStableRight);
+                pw.print(","); pw.print(mStableBottom); pw.println(")");
         pw.print(prefix); pw.print("mCur=("); pw.print(mCurLeft);
                 pw.print(","); pw.print(mCurTop);
                 pw.print(")-("); pw.print(mCurRight);
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 6452be7..8429086 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -292,27 +292,27 @@
         }
     }
 
-    public void setSystemUiVisibility(int vis) {
+    public void setSystemUiVisibility(int vis, int mask) {
         // also allows calls from window manager which is in this process.
         enforceStatusBarService();
 
         if (SPEW) Slog.d(TAG, "setSystemUiVisibility(0x" + Integer.toHexString(vis) + ")");
 
         synchronized (mLock) {
-            updateUiVisibilityLocked(vis);
+            updateUiVisibilityLocked(vis, mask);
             disableLocked(vis & StatusBarManager.DISABLE_MASK, mSysUiVisToken,
                     "WindowManager.LayoutParams");
         }
     }
 
-    private void updateUiVisibilityLocked(final int vis) {
+    private void updateUiVisibilityLocked(final int vis, final int mask) {
         if (mSystemUiVisibility != vis) {
             mSystemUiVisibility = vis;
             mHandler.post(new Runnable() {
                     public void run() {
                         if (mBar != null) {
                             try {
-                                mBar.setSystemUiVisibility(vis);
+                                mBar.setSystemUiVisibility(vis, mask);
                             } catch (RemoteException ex) {
                             }
                         }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index a91e716..a2dfd91 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -2648,7 +2648,8 @@
                 }
                 flagChanges = win.mAttrs.flags ^= attrs.flags;
                 attrChanges = win.mAttrs.copyFrom(attrs);
-                if ((attrChanges&WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) {
+                if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED
+                        | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) {
                     win.mLayoutNeeded = true;
                 }
             }