visibility ("lights out") API.

1. Views may setSystemUiVisibility() to recommend that
the system chrome (status bar or other UI) show or hide
itself.  (This functionality was previously available only
via the FLAG_FULLSCREEN window flag for some SystemUI
implementations.)

2. Views may register a OnSystemUiVisibilityChangedListener
on a view, and find out when the system UI actually
appears or disappears, allowing apps to coordinate the
appearance of their own UI if desired.

Bug: 3241144
Change-Id: Ia1758d94099182d49a1e3688ea2738ae4995b829
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 469bbaa..6d5fd2c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -48,6 +48,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.util.AttributeSet;
@@ -1697,6 +1698,20 @@
     public static final int OVER_SCROLL_NEVER = 2;
 
     /**
+     * View has requested the status bar to be visible (the default).
+     *
+     * @see setSystemUiVisibility
+     */
+    public static final int STATUS_BAR_VISIBLE = 0;
+
+    /**
+     * View has requested the status bar to be visible (the default).
+     *
+     * @see setSystemUiVisibility
+     */
+    public static final int STATUS_BAR_HIDDEN = 0x00000001;
+
+    /**
      * Controls the over-scroll mode for this view.
      * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)},
      * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS},
@@ -1735,6 +1750,12 @@
     int mPrivateFlags;
 
     /**
+     * This view's request for the visibility of the status bar.
+     * @hide
+     */
+    int mSystemUiVisibility;
+
+    /**
      * Count of how many windows this view has been attached to.
      */
     int mWindowAttachCount;
@@ -2037,6 +2058,8 @@
 
     private OnDragListener mOnDragListener;
 
+    private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
+
     /**
      * The application environment this view lives in.
      * This field should be made private, so it is hidden from the SDK.
@@ -4706,17 +4729,22 @@
     }
 
     void performCollectViewAttributes(int visibility) {
-        //noinspection PointlessBitwiseExpression
-        if (((visibility | mViewFlags) & (VISIBILITY_MASK | KEEP_SCREEN_ON))
-                == (VISIBLE | KEEP_SCREEN_ON)) {
-            mAttachInfo.mKeepScreenOn = true;
+        if ((visibility & VISIBILITY_MASK) == VISIBLE) {
+            if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) {
+                mAttachInfo.mKeepScreenOn = true;
+            }
+            mAttachInfo.mSystemUiVisibility |= mSystemUiVisibility;
+            if (mOnSystemUiVisibilityChangeListener != null) {
+                mAttachInfo.mHasSystemUiListeners = true;
+            }
         }
     }
 
     void needGlobalAttributesUpdate(boolean force) {
-        AttachInfo ai = mAttachInfo;
+        final AttachInfo ai = mAttachInfo;
         if (ai != null) {
-            if (ai.mKeepScreenOn || force) {
+            if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0)
+                    || ai.mHasSystemUiListeners) {
                 ai.mRecomputeGlobalAttributes = true;
             }
         }
@@ -5301,7 +5329,7 @@
         }
 
         if ((changed & KEEP_SCREEN_ON) != 0) {
-            if (mParent != null) {
+            if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
                 mParent.recomputeViewAttributes(this);
             }
         }
@@ -10618,6 +10646,40 @@
     }
 
     /**
+     * Request that the visibility of the status bar be changed.
+     */
+    public void setSystemUiVisibility(int visibility) {
+        if (visibility != mSystemUiVisibility) {
+            mSystemUiVisibility = visibility;
+            if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
+                mParent.recomputeViewAttributes(this);
+            }
+        }
+    }
+
+    /**
+     * Returns the status bar visibility that this view has requested.
+     */
+    public int getSystemUiVisibility(int visibility) {
+        return mSystemUiVisibility;
+    }
+
+    public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) {
+        mOnSystemUiVisibilityChangeListener = l;
+        if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
+            mParent.recomputeViewAttributes(this);
+        }
+    }
+
+    /**
+     */
+    public void dispatchSystemUiVisibilityChanged(int visibility) {
+        if (mOnSystemUiVisibilityChangeListener != null) {
+            mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange(visibility);
+        }
+    }
+
+    /**
      * !!! TODO: real docs
      *
      * The base class implementation makes the shadow the same size and appearance
@@ -11307,6 +11369,22 @@
         void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo);
     }
 
+    /**
+     * Interface definition for a callback to be invoked when the status bar changes
+     * visibility.
+     *
+     * @see #setOnSystemUiVisibilityChangeListener
+     */
+    public interface OnSystemUiVisibilityChangeListener {
+        /**
+         * Called when the status bar changes visibility because of a call to
+         * {@link #setSystemUiVisibility}.
+         *
+         * @param visibility {@link #STATUS_BAR_VISIBLE} or {@link #STATUS_BAR_HIDDEN}.
+         */
+        public void onSystemUiVisibilityChange(int visibility);
+    }
+
     private final class UnsetPressedState implements Runnable {
         public void run() {
             setPressed(false);
@@ -11525,6 +11603,17 @@
         boolean mKeepScreenOn;
 
         /**
+         * Bitwise-or of all of the values that views have passed to setSystemUiVisibility().
+         */
+        int mSystemUiVisibility;
+
+        /**
+         * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener
+         * attached.
+         */
+        boolean mHasSystemUiListeners;
+
+        /**
          * Set if the visibility of any views has changed.
          */
         boolean mViewVisibilityChanged;