Make disable() work.

Change-Id: I93fea37e777b3e04fe7f9171d5b84821587c24f5
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 8905268..9499d82 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -87,7 +87,7 @@
      */
     public void expand() {
         try {
-            mService.activate();
+            mService.expand();
         } catch (RemoteException ex) {
             // system process is dead anyway.
             throw new RuntimeException(ex);
@@ -99,7 +99,7 @@
      */
     public void collapse() {
         try {
-            mService.deactivate();
+            mService.collapse();
         } catch (RemoteException ex) {
             // system process is dead anyway.
             throw new RuntimeException(ex);
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 2a5ae15..65628b0 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -23,5 +23,6 @@
 {
     void setIcon(int index, in StatusBarIcon icon);
     void removeIcon(int index);
+    void disable(int state);
 }
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 0a9c8da..ba63eaff 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -23,8 +23,8 @@
 /** @hide */
 interface IStatusBarService
 {
-    void activate();
-    void deactivate();
+    void expand();
+    void collapse();
     void toggle();
     void disable(int what, IBinder token, String pkg);
     void setIcon(String slot, String iconPackage, int iconId, int iconLevel);
diff --git a/packages/StatusBarPhone/src/com/android/policy/statusbar/phone/CommandQueue.java b/packages/StatusBarPhone/src/com/android/policy/statusbar/phone/CommandQueue.java
index 3357e10..90f17d5 100644
--- a/packages/StatusBarPhone/src/com/android/policy/statusbar/phone/CommandQueue.java
+++ b/packages/StatusBarPhone/src/com/android/policy/statusbar/phone/CommandQueue.java
@@ -24,6 +24,12 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
 
+/**
+ * This class takes the functions from IStatusBar that come in on
+ * binder pool threads and posts messages to get them onto the main
+ * thread, and calls onto Callbacks.  It also takes care of
+ * coalescing these calls so they don't stack up.
+ */
 class CommandQueue extends IStatusBar.Stub {
     private static final String TAG = "StatusBar.CommandQueue";
 
@@ -34,6 +40,8 @@
     private static final int OP_SET_ICON = 1;
     private static final int OP_REMOVE_ICON = 2;
 
+    private static final int MSG_DISABLE = 0x00020000;
+
     private StatusBarIconList mList;
     private Callbacks mCallbacks;
     private Handler mHandler = new H();
@@ -46,6 +54,7 @@
         public void updateIcon(String slot, int index, int viewIndex,
                 StatusBarIcon old, StatusBarIcon icon);
         public void removeIcon(String slot, int index, int viewIndex);
+        public void disable(int state);
     }
 
     public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -69,13 +78,20 @@
         }
     }
 
+    public void disable(int state) {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_DISABLE);
+            mHandler.obtainMessage(MSG_DISABLE, state, 0, null).sendToTarget();
+        }
+    }
+
     private final class H extends Handler {
         public void handleMessage(Message msg) {
-            int what = msg.what & MSG_MASK;
+            final int what = msg.what & MSG_MASK;
             switch (what) {
                 case MSG_ICON: {
-                    int index = msg.what & INDEX_MASK;
-                    int viewIndex = mList.getViewIndex(index);
+                    final int index = msg.what & INDEX_MASK;
+                    final int viewIndex = mList.getViewIndex(index);
                     switch (msg.arg1) {
                         case OP_SET_ICON: {
                             StatusBarIcon icon = (StatusBarIcon)msg.obj;
@@ -96,7 +112,10 @@
                             break;
                     }
                     break;
-               }
+                }
+                case MSG_DISABLE:
+                    mCallbacks.disable(msg.arg1);
+                    break;
             }
         }
     }
diff --git a/packages/StatusBarPhone/src/com/android/policy/statusbar/phone/PhoneStatusBarService.java b/packages/StatusBarPhone/src/com/android/policy/statusbar/phone/PhoneStatusBarService.java
index 8291d70..6ae632b 100644
--- a/packages/StatusBarPhone/src/com/android/policy/statusbar/phone/PhoneStatusBarService.java
+++ b/packages/StatusBarPhone/src/com/android/policy/statusbar/phone/PhoneStatusBarService.java
@@ -101,7 +101,7 @@
             switch (event.getKeyCode()) {
             case KeyEvent.KEYCODE_BACK:
                 if (!down) {
-                    //TODO PhoneStatusBarService.this.deactivate();
+                    //TODO PhoneStatusBarService.this.collapse();
                 }
                 return true;
             }
@@ -329,6 +329,42 @@
         Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
         mStatusIcons.removeViewAt(viewIndex);
     }
+
+    /**
+     * State is one or more of the DISABLE constants from StatusBarManager.
+     */
+    public void disable(int state) {
+        final int old = mDisabled;
+        final int diff = state ^ old;
+        mDisabled = state;
+
+        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
+            if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
+                Slog.d(TAG, "DISABLE_EXPAND: yes");
+                animateCollapse();
+            }
+        }
+        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+            if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+                if (mTicking) {
+                    mTicker.halt();
+                } else {
+                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
+                }
+            } else {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+                if (!mExpandedVisible) {
+                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
+                }
+            }
+        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+            if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+                Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes");
+                mTicker.halt();
+            }
+        }
+    }
     
     /**
      * All changes to the status bar and notifications funnel through here and are batched.
@@ -854,7 +890,7 @@
                 // the stack trace isn't very helpful here.  Just log the exception message.
                 Slog.w(TAG, "Sending contentIntent failed: " + e);
             }
-            //deactivate();
+            //collapse();
         }
     }
 
@@ -1224,7 +1260,7 @@
         if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
             if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
                 Slog.d(TAG, "DISABLE_EXPAND: yes");
-                animateCollapse();
+                //animateCollapse();
             }
         }
         if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
@@ -1261,7 +1297,7 @@
             String action = intent.getAction();
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
                     || Intent.ACTION_SCREEN_OFF.equals(action)) {
-                //deactivate();
+                //collapse();
             }
             else if (Telephony.Intents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
                 updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false),
diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java
index 11ebd0f..3169fe0 100755
--- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1541,7 +1541,7 @@
             if (sbs != null) {
                 try {
                     // Make sure the window shade is hidden.
-                    sbs.deactivate();
+                    sbs.collapse();
                 } catch (RemoteException e) {
                 }
             }
diff --git a/services/java/com/android/server/status/StatusBarManagerService.java b/services/java/com/android/server/status/StatusBarManagerService.java
index 0f5f2ac..1752f26 100644
--- a/services/java/com/android/server/status/StatusBarManagerService.java
+++ b/services/java/com/android/server/status/StatusBarManagerService.java
@@ -28,6 +28,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.Binder;
+import android.os.Handler;
 import android.os.SystemClock;
 import android.util.Slog;
 
@@ -43,49 +44,30 @@
 
 
 /**
- * The public (ok, semi-public) service for the status bar.
- * <p>
- * This interesting thing to note about this class is that most of the methods that
- * are called from other classes just post a message, and everything else is batched
- * and coalesced into a series of calls to methods that all start with "perform."
- * There are two reasons for this.  The first is that some of the methods (activate/deactivate)
- * are on IStatusBarService, so they're called from the thread pool and they need to make their
- * way onto the UI thread.  The second is that the message queue is stopped while animations
- * are happening in order to make for smoother transitions.
- * <p>
- * Each icon is either an icon or an icon and a notification.  They're treated mostly
- * separately throughout the code, although they both use the same key, which is assigned
- * when they are created.
+ * A note on locking:  We rely on the fact that calls onto mBar are oneway or
+ * if they are local, that they just enqueue messages to not deadlock.
  */
 public class StatusBarManagerService extends IStatusBarService.Stub
 {
     static final String TAG = "StatusBar";
-    static final boolean SPEW = false;
+    static final boolean SPEW = true;
 
     public static final String ACTION_STATUSBAR_START
             = "com.android.internal.policy.statusbar.START";
 
-    static final int EXPANDED_LEAVE_ALONE = -10000;
-    static final int EXPANDED_FULL_OPEN = -10001;
+    final Context mContext;
+    Handler mHandler = new Handler();
+    NotificationCallbacks mNotificationCallbacks;
+    IStatusBar mBar;
+    StatusBarIconList mIcons = new StatusBarIconList();
+    private UninstallReceiver mUninstallReceiver;
 
-    private static final int MSG_ANIMATE = 1000;
-    private static final int MSG_ANIMATE_REVEAL = 1001;
+    // expanded notifications
+    NotificationViewList mNotificationData = new NotificationViewList();
 
-    private static final int OP_ADD_ICON = 1;
-    private static final int OP_UPDATE_ICON = 2;
-    private static final int OP_REMOVE_ICON = 3;
-    private static final int OP_SET_VISIBLE = 4;
-    private static final int OP_EXPAND = 5;
-    private static final int OP_TOGGLE = 6;
-    private static final int OP_DISABLE = 7;
-    private class PendingOp {
-        IBinder key;
-        int code;
-        IconData iconData;
-        NotificationData notificationData;
-        boolean visible;
-        int integer;
-    }
+    // for disabling the status bar
+    ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
+    int mDisabled = 0;
 
     private class DisableRecord implements IBinder.DeathRecipient {
         String pkg;
@@ -106,23 +88,6 @@
         void onPanelRevealed();
     }
 
-    final Context mContext;
-    Object mQueueLock = new Object();
-    ArrayList<PendingOp> mQueue = new ArrayList<PendingOp>();
-    NotificationCallbacks mNotificationCallbacks;
-    IStatusBar mBar;
-    
-    // icons
-    StatusBarIconList mIcons = new StatusBarIconList();
-    private UninstallReceiver mUninstallReceiver;
-
-    // expanded notifications
-    NotificationViewList mNotificationData = new NotificationViewList();
-
-    // for disabling the status bar
-    ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
-    int mDisabled = 0;
-
     /**
      * Construct the service, add the status bar view to the window manager
      */
@@ -154,11 +119,11 @@
     // ================================================================================
     // From IStatusBarService
     // ================================================================================
-    public void activate() {
+    public void expand() {
         enforceExpandStatusBar();
     }
 
-    public void deactivate() {
+    public void collapse() {
         enforceExpandStatusBar();
     }
 
@@ -168,18 +133,29 @@
 
     public void disable(int what, IBinder token, String pkg) {
         enforceStatusBar();
-        synchronized (mNotificationCallbacks) {
-            // This is a little gross, but I think it's safe as long as nobody else
-            // synchronizes on mNotificationCallbacks.  It's important that the the callback
-            // and the pending op get done in the correct order and not interleaved with
-            // other calls, otherwise they'll get out of sync.
-            int net;
-            synchronized (mDisableRecords) {
-                manageDisableListLocked(what, token, pkg);
-                net = gatherDisableActionsLocked();
-                mNotificationCallbacks.onSetDisabled(net);
+
+        // It's important that the the callback and the call to mBar get done
+        // in the same order when multiple threads are calling this function
+        // so they are paired correctly.  The messages on the handler will be
+        // handled in the order they were enqueued, but will be outside the lock.
+        synchronized (mDisableRecords) {
+            manageDisableListLocked(what, token, pkg);
+            final int net = gatherDisableActionsLocked();
+            Slog.d(TAG, "disable... net=0x" + Integer.toHexString(net));
+            if (net != mDisabled) {
+                mDisabled = net;
+                mHandler.post(new Runnable() {
+                        public void run() {
+                            mNotificationCallbacks.onSetDisabled(net);
+                        }
+                    });
+                if (mBar != null) {
+                    try {
+                        mBar.disable(net);
+                    } catch (RemoteException ex) {
+                    }
+                }
             }
-            //addPendingOp(OP_DISABLE, net);
         }
     }
 
@@ -196,7 +172,6 @@
             //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon);
             mIcons.setIcon(index, icon);
 
-            // Tell the client.  If it fails, it'll restart soon and we'll sync up.
             if (mBar != null) {
                 try {
                     mBar.setIcon(index, icon);
@@ -223,7 +198,6 @@
             if (icon.visible != visible) {
                 icon.visible = visible;
 
-                // Tell the client.  If it fails, it'll restart soon and we'll sync up.
                 if (mBar != null) {
                     try {
                         mBar.setIcon(index, icon);
@@ -245,7 +219,6 @@
 
             mIcons.removeIcon(index);
 
-            // Tell the client.  If it fails, it'll restart soon and we'll sync up.
             if (mBar != null) {
                 try {
                     mBar.removeIcon(index);
@@ -289,8 +262,7 @@
     // lock on mDisableRecords
     void manageDisableListLocked(int what, IBinder token, String pkg) {
         if (SPEW) {
-            Slog.d(TAG, "manageDisableList what=0x" + Integer.toHexString(what)
-                    + " pkg=" + pkg);
+            Slog.d(TAG, "manageDisableList what=0x" + Integer.toHexString(what) + " pkg=" + pkg);
         }
         // update the list
         synchronized (mDisableRecords) {
@@ -361,18 +333,6 @@
             mIcons.dump(pw);
         }
         
-        synchronized (mQueueLock) {
-            pw.println("Current Status Bar state:");
-            final int N = mQueue.size();
-            pw.println("  mQueue.size=" + N);
-            for (int i=0; i<N; i++) {
-                PendingOp op = mQueue.get(i);
-                pw.println("    [" + i + "] key=" + op.key + " code=" + op.code + " visible="
-                        + op.visible);
-                pw.println("           iconData=" + op.iconData);
-                pw.println("           notificationData=" + op.notificationData);
-            }
-        }
         synchronized (mNotificationData) {
             int N = mNotificationData.ongoingCount();
             pw.println("  ongoingCount.size=" + N);
@@ -419,47 +379,12 @@
         }
     }
 
-    void performDisableActions(int net) {
-        /*
-        int old = mDisabled;
-        int diff = net ^ old;
-        mDisabled = net;
-
-        // act accordingly
-        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
-            if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
-                Slog.d(TAG, "DISABLE_EXPAND: yes");
-                //animateCollapse();
-            }
-        }
-        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-            if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
-                if (mTicking) {
-                    //mTicker.halt();
-                } else {
-                    setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
-                }
-            } else {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
-                if (!mExpandedVisible) {
-                    setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
-                }
-            }
-        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-            if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-                //mTicker.halt();
-            }
-        }
-        */
-    }
-
     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
                     || Intent.ACTION_SCREEN_OFF.equals(action)) {
-                deactivate();
+                collapse();
             }
             /*
             else if (Telephony.Intents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {