Plumb lights out mode through from the window manager to the status bar running in the system ui process.

Lights out mode itself isn't implemented.

Change-Id: Ieeef0eb9ae5be23000f770e74e8ee66472f4c673
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 4501bd7..e884af8 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -30,5 +30,6 @@
     void disable(int state);
     void animateExpand();
     void animateCollapse();
+    void setLightsOn(boolean on);
 }
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 2307669..07cc43e 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -30,11 +30,13 @@
     void setIcon(String slot, String iconPackage, int iconId, int iconLevel);
     void setIconVisibility(String slot, boolean visible);
     void removeIcon(String slot);
+    void setActiveWindowIsFullscreen(boolean fullscreen);
 
     // ---- Methods below are for use by the status bar policy services ----
     // You need the STATUS_BAR_SERVICE permission
     void registerStatusBar(IStatusBar callbacks, out StatusBarIconList iconList,
-            out List<IBinder> notificationKeys, out List<StatusBarNotification> notifications);
+            out List<IBinder> notificationKeys, out List<StatusBarNotification> notifications,
+            out boolean[] lightsOn);
     void onPanelRevealed();
     void onNotificationClick(String pkg, String tag, int id);
     void onNotificationError(String pkg, String tag, int id,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 2c0af65..3ef12f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -52,6 +52,8 @@
     private static final int OP_EXPAND = 1;
     private static final int OP_COLLAPSE = 2;
 
+    private static final int MSG_SET_LIGHTS_ON = 0x00070000;
+
     private StatusBarIconList mList;
     private Callbacks mCallbacks;
     private Handler mHandler = new H();
@@ -75,6 +77,7 @@
         public void disable(int state);
         public void animateExpand();
         public void animateCollapse();
+        public void setLightsOn(boolean on);
     }
 
     public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -143,6 +146,13 @@
         }
     }
 
+    public void setLightsOn(boolean on) {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_SET_LIGHTS_ON);
+            mHandler.obtainMessage(MSG_SET_LIGHTS_ON, on ? 1 : 0, 0, null).sendToTarget();
+        }
+    }
+
     private final class H extends Handler {
         public void handleMessage(Message msg) {
             final int what = msg.what & MSG_MASK;
@@ -194,6 +204,10 @@
                     } else {
                         mCallbacks.animateCollapse();
                     }
+                    break;
+                case MSG_SET_LIGHTS_ON:
+                    mCallbacks.setLightsOn(msg.arg1 != 0);
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
index 48243ff..e945981 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
@@ -1011,6 +1011,15 @@
         return false;
     }
 
+    public void setLightsOn(boolean on) {
+        if (!on) {
+            // All we do for "lights out" mode on a phone is hide the status bar,
+            // which the window manager does.  But we do need to hide the windowshade
+            // on our own.
+            animateCollapse();
+        }
+    }
+
     private class Launcher implements View.OnClickListener {
         private PendingIntent mIntent;
         private String mPkg;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
index a64c3e7..695fdba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
@@ -72,12 +72,16 @@
         mCommandQueue = new CommandQueue(this, iconList);
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        boolean[] lightsOn = new boolean[1];
         try {
-            mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications);
+            mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,
+                    lightsOn);
         } catch (RemoteException ex) {
             // If the system process isn't there we're doomed anyway.
         }
 
+        setLightsOn(lightsOn[0]);
+
         // Set up the initial icon state
         int N = iconList.size();
         int viewIndex = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
index 6f74924..b33af99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
@@ -56,8 +56,6 @@
 
     private static final int MAX_IMAGE_LEVEL = 10000;
 
-
-
     int mIconSize;
 
     H mHandler = new H();
@@ -493,6 +491,14 @@
         mHandler.sendEmptyMessage(H.MSG_CLOSE_SYSTEM_PANEL);
     }
 
+    public void setLightsOn(boolean on) {
+        //Slog.d(TAG, "setLightsOn on=" + on);
+        if (!on) {
+            animateCollapse();
+        }
+        // TODO: implement lights out mode
+    }
+
     public void notificationIconsClicked(View v) {
         if (DEBUG) Slog.d(TAG, "clicked notification icons");
         mHandler.removeMessages(H.MSG_CLOSE_SYSTEM_PANEL);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 6e5db2b..7009c65 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -177,6 +177,7 @@
     Context mContext;
     IWindowManager mWindowManager;
     LocalPowerManager mPowerManager;
+    IStatusBarService mStatusBarService;
     Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
 
     // Vibrator pattern for haptic feedback of a long press.
@@ -263,6 +264,7 @@
     static final Rect mTmpVisibleFrame = new Rect();
     
     WindowState mTopFullscreenOpaqueWindowState;
+    boolean mTopIsFullscreen;
     boolean mForceStatusBar;
     boolean mHideLockScreen;
     boolean mDismissKeyguard;
@@ -1555,8 +1557,8 @@
     /** {@inheritDoc} */
     public int finishAnimationLw() {
         int changes = 0;
-        
-        boolean hiding = false;
+
+        boolean topIsFullscreen = false;
         if (mStatusBar != null) {
             if (localLOGV) Log.i(TAG, "force=" + mForceStatusBar
                     + " top=" + mTopFullscreenOpaqueWindowState);
@@ -1564,18 +1566,22 @@
                 if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar");
                 if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
             } else if (mTopFullscreenOpaqueWindowState != null) {
-                //Log.i(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
-                //        + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
-                //Log.i(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs());
-                WindowManager.LayoutParams lp =
-                    mTopFullscreenOpaqueWindowState.getAttrs();
-                boolean hideStatusBar =
-                    (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
-                if (hideStatusBar) {
+                final WindowManager.LayoutParams lp = mTopFullscreenOpaqueWindowState.getAttrs();
+                if (localLOGV) {
+                    Log.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
+                            + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
+                    Log.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
+                            + " lp.flags=0x" + Integer.toHexString(lp.flags));
+                }
+                topIsFullscreen = (lp.flags & WindowManager.LayoutParams.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
+                // case though.
+                if (topIsFullscreen) {
                     if (mStatusBarCanHide) {
                         if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar");
                         if (mStatusBar.hideLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
-                        hiding = true;
                     } else if (localLOGV) {
                         Log.v(TAG, "Preventing status bar from hiding by policy");
                     }
@@ -1586,21 +1592,36 @@
             }
         }
         
-        if (changes != 0 && hiding) {
-            IStatusBarService sbs = IStatusBarService.Stub.asInterface(ServiceManager.getService("statusbar"));
-            if (sbs != null) {
-                try {
-                    // Make sure the window shade is hidden.
-                    sbs.collapse();
-                } catch (RemoteException e) {
-                }
-            }
+        if (topIsFullscreen != mTopIsFullscreen) {
+            final boolean topIsFullscreenF = topIsFullscreen;
+            mTopIsFullscreen = topIsFullscreen;
+            mHandler.post(new Runnable() {
+                    public void run() {
+                        if (mStatusBarService == null) {
+                            // This is the one that can not go away, but it doesn't come up
+                            // before the window manager does, so don't fail if it doesn't
+                            // exist. This works as long as no fullscreen windows come up
+                            // before the status bar service does.
+                            mStatusBarService = IStatusBarService.Stub.asInterface(
+                                    ServiceManager.getService("statusbar"));
+                        }
+                        final IStatusBarService sbs = mStatusBarService;
+                        if (mStatusBarService != null) {
+                            try {
+                                sbs.setActiveWindowIsFullscreen(topIsFullscreenF);
+                            } catch (RemoteException e) {
+                                // This should be impossible because we're in the same process.
+                                mStatusBarService = null;
+                            }
+                        }
+                    }
+                });
         }
 
         // Hide the key guard if a visible window explicitly specifies that it wants to be displayed
         // when the screen is locked
         if (mKeyguard != null) {
-            if (localLOGV) Log.v(TAG, "finishLayoutLw::mHideKeyguard="+mHideLockScreen);
+            if (localLOGV) Log.v(TAG, "finishAnimationLw::mHideKeyguard="+mHideLockScreen);
             if (mDismissKeyguard && !mKeyguardMediator.isSecure()) {
                 if (mKeyguard.hideLw(true)) {
                     changes |= FINISH_LAYOUT_REDO_LAYOUT
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 717c309..dc86eeb 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -68,6 +68,10 @@
     ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
     int mDisabled = 0;
 
+    Object mLock = new Object();
+    // We usually call it lights out mode, but double negatives are annoying
+    boolean mLightsOn = true;
+
     private class DisableRecord implements IBinder.DeathRecipient {
         String pkg;
         int what;
@@ -242,6 +246,30 @@
         }
     }
 
+    public void setActiveWindowIsFullscreen(boolean fullscreen) {
+        // We could get away with a separate permission here, but STATUS_BAR is
+        // signatureOrSystem which is probably good enough.  There is no public API
+        // for this, so the question is a security issue, not an API compatibility issue.
+        enforceStatusBar();
+
+        final boolean lightsOn = !fullscreen;
+        synchronized (mLock) {
+            if (mLightsOn != lightsOn) {
+                mLightsOn = lightsOn;
+                mHandler.post(new Runnable() {
+                        public void run() {
+                            if (mBar != null) {
+                                try {
+                                    mBar.setLightsOn(lightsOn);
+                                } catch (RemoteException ex) {
+                                }
+                            }
+                        }
+                    });
+            }
+        }
+    }
+
     private void enforceStatusBar() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR,
                 "StatusBarManagerService");
@@ -262,7 +290,8 @@
     // Callbacks from the status bar service.
     // ================================================================================
     public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,
-            List<IBinder> notificationKeys, List<StatusBarNotification> notifications) {
+            List<IBinder> notificationKeys, List<StatusBarNotification> notifications,
+            boolean lightsOn[]) {
         enforceStatusBarService();
 
         Slog.i(TAG, "registerStatusBar bar=" + bar);
@@ -276,6 +305,9 @@
                 notifications.add(e.getValue());
             }
         }
+        synchronized (mLock) {
+            lightsOn[0] = mLightsOn;
+        }
     }
 
     /**
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index b6a090f..94b010b 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -23,6 +23,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -7038,6 +7039,9 @@
                         frame.right >= mCompatibleScreenFrame.right &&
                         frame.bottom >= mCompatibleScreenFrame.bottom;
             } else {
+                if ((mAttrs.flags & FLAG_FULLSCREEN) != 0) {
+                    return true;
+                }
                 return frame.left <= 0 && frame.top <= 0
                         && frame.right >= screenWidth
                         && frame.bottom >= screenHeight;
diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
index b665d2f..e31711e 100644
--- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
@@ -60,20 +60,19 @@
     }
 
     private Test[] mTests = new Test[] {
-        new Test("Hide") {
+        new Test("Hide (FLAG_FULLSCREEN)") {
             public void run() {
                 Window win = getWindow();
-                WindowManager.LayoutParams winParams = win.getAttributes();
-                winParams.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
-                win.setAttributes(winParams);
+                win.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+                        WindowManager.LayoutParams.FLAG_FULLSCREEN);
+                Log.d(TAG, "flags=" + Integer.toHexString(win.getAttributes().flags));
             }
         },
-        new Test("Show") {
+        new Test("Show (~FLAG_FULLSCREEN)") {
             public void run() {
                 Window win = getWindow();
-                WindowManager.LayoutParams winParams = win.getAttributes();
-                winParams.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;
-                win.setAttributes(winParams);
+                win.setFlags(0, WindowManager.LayoutParams.FLAG_FULLSCREEN);
+                Log.d(TAG, "flags=" + Integer.toHexString(win.getAttributes().flags));
             }
         },
         new Test("Immersive: Enter") {