am 6da062a9: Merge "DO NOT MERGE: Clean up USB notifications:" into gingerbread

* commit '6da062a96c6f8126aad450a937144fab4333488f':
  DO NOT MERGE: Clean up USB notifications:
diff --git a/core/java/android/hardware/UsbManager.java b/core/java/android/hardware/UsbManager.java
index eb394c1..18790d2 100644
--- a/core/java/android/hardware/UsbManager.java
+++ b/core/java/android/hardware/UsbManager.java
@@ -27,32 +27,12 @@
  */
 public class UsbManager {
    /**
-     * Broadcast Action:  A broadcast for USB connected events.
-     *
-     * The extras bundle will name/value pairs with the name of the function
-     * and a value of either {@link #USB_FUNCTION_ENABLED} or {@link #USB_FUNCTION_DISABLED}.
-     * Possible USB function names include {@link #USB_FUNCTION_MASS_STORAGE},
-     * {@link #USB_FUNCTION_ADB}, {@link #USB_FUNCTION_RNDIS} and {@link #USB_FUNCTION_MTP}.
-     */
-    public static final String ACTION_USB_CONNECTED =
-            "android.hardware.action.USB_CONNECTED";
-
-   /**
-     * Broadcast Action:  A broadcast for USB disconnected events.
-     */
-    public static final String ACTION_USB_DISCONNECTED =
-            "android.hardware.action.USB_DISCONNECTED";
-
-   /**
      * Broadcast Action:  A sticky broadcast for USB state change events.
      *
-     * This is a sticky broadcast for clients that are interested in both USB connect and
-     * disconnect events.  If you are only concerned with one or the other, you can use
-     * {@link #ACTION_USB_CONNECTED} or {@link #ACTION_USB_DISCONNECTED} to avoid receiving
-     * unnecessary broadcasts.  The boolean {@link #USB_CONNECTED} extra indicates whether
-     * USB is connected or disconnected.
-     * The extras bundle will also contain name/value pairs with the name of the function
-     * and a value of either {@link #USB_FUNCTION_ENABLED} or {@link #USB_FUNCTION_DISABLED}.
+     * This is a sticky broadcast for clients that includes USB connected/disconnected state,
+     * the USB configuration that is currently set and a bundle containing name/value pairs
+     * with the names of the functions and a value of either {@link #USB_FUNCTION_ENABLED}
+     * or {@link #USB_FUNCTION_DISABLED}.
      * Possible USB function names include {@link #USB_FUNCTION_MASS_STORAGE},
      * {@link #USB_FUNCTION_ADB}, {@link #USB_FUNCTION_RNDIS} and {@link #USB_FUNCTION_MTP}.
      */
@@ -66,38 +46,44 @@
     public static final String USB_CONNECTED = "connected";
 
     /**
+     * Integer extra containing currently set USB configuration.
+     * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
+     */
+    public static final String USB_CONFIGURATION = "configuration";
+
+    /**
      * Name of the USB mass storage USB function.
-     * Used in extras for the {@link #ACTION_USB_CONNECTED} broadcast
+     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      */
     public static final String USB_FUNCTION_MASS_STORAGE = "mass_storage";
 
     /**
      * Name of the adb USB function.
-     * Used in extras for the {@link #ACTION_USB_CONNECTED} broadcast
+     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      */
     public static final String USB_FUNCTION_ADB = "adb";
 
     /**
      * Name of the RNDIS ethernet USB function.
-     * Used in extras for the {@link #ACTION_USB_CONNECTED} broadcast
+     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      */
     public static final String USB_FUNCTION_RNDIS = "rndis";
 
     /**
      * Name of the MTP USB function.
-     * Used in extras for the {@link #ACTION_USB_CONNECTED} broadcast
+     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      */
     public static final String USB_FUNCTION_MTP = "mtp";
 
     /**
      * Value indicating that a USB function is enabled.
-     * Used in extras for the {@link #ACTION_USB_CONNECTED} broadcast
+     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      */
     public static final String USB_FUNCTION_ENABLED = "enabled";
 
     /**
      * Value indicating that a USB function is disabled.
-     * Used in extras for the {@link #ACTION_USB_CONNECTED} broadcast
+     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      */
     public static final String USB_FUNCTION_DISABLED = "disabled";
 
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 25dc52e..6640ab7 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -358,8 +358,6 @@
                 boolean adbEnabled = (UsbManager.USB_FUNCTION_ENABLED.equals(
                                     extras.getString(UsbManager.USB_FUNCTION_ADB)));
                 updateAdbNotification(usbConnected && adbEnabled);
-            } else if (action.equals(UsbManager.ACTION_USB_DISCONNECTED)) {
-                updateAdbNotification(false);
             } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
diff --git a/services/java/com/android/server/UsbService.java b/services/java/com/android/server/UsbService.java
index ad400bf..672c95e 100644
--- a/services/java/com/android/server/UsbService.java
+++ b/services/java/com/android/server/UsbService.java
@@ -40,15 +40,33 @@
     private static final String TAG = UsbService.class.getSimpleName();
     private static final boolean LOG = false;
 
-    private static final String USB_CONFIGURATION_MATCH = "DEVPATH=/devices/virtual/switch/usb_configuration";
-    private static final String USB_FUNCTIONS_MATCH = "DEVPATH=/devices/virtual/usb_composite/";
-    private static final String USB_CONFIGURATION_PATH = "/sys/class/switch/usb_configuration/state";
-    private static final String USB_COMPOSITE_CLASS_PATH = "/sys/class/usb_composite";
+    private static final String USB_CONNECTED_MATCH =
+            "DEVPATH=/devices/virtual/switch/usb_connected";
+    private static final String USB_CONFIGURATION_MATCH =
+            "DEVPATH=/devices/virtual/switch/usb_configuration";
+    private static final String USB_FUNCTIONS_MATCH =
+            "DEVPATH=/devices/virtual/usb_composite/";
+    private static final String USB_CONNECTED_PATH =
+            "/sys/class/switch/usb_connected/state";
+    private static final String USB_CONFIGURATION_PATH =
+            "/sys/class/switch/usb_configuration/state";
+    private static final String USB_COMPOSITE_CLASS_PATH =
+            "/sys/class/usb_composite";
 
     private static final int MSG_UPDATE = 0;
 
-    private int mUsbConfig = 0;
-    private int mPreviousUsbConfig = 0;
+    // Delay for debouncing USB disconnects.
+    // We often get rapid connect/disconnect events when enabling USB functions,
+    // which need debouncing.
+    private static final int UPDATE_DELAY = 1000;
+
+    // current connected and configuration state
+    private int mConnected;
+    private int mConfiguration;
+
+    // last broadcasted connected and configuration state
+    private int mLastConnected = -1;
+    private int mLastConfiguration = -1;
 
     // lists of enabled and disabled USB functions
     private final ArrayList<String> mEnabledFunctions = new ArrayList<String>();
@@ -58,8 +76,6 @@
 
     private final Context mContext;
 
-    private PowerManagerService mPowerManager;
-
     private final UEventObserver mUEventObserver = new UEventObserver() {
         @Override
         public void onUEvent(UEventObserver.UEvent event) {
@@ -68,16 +84,23 @@
             }
 
             synchronized (this) {
-                String switchState = event.get("SWITCH_STATE");
-                if (switchState != null) {
+                String name = event.get("SWITCH_NAME");
+                String state = event.get("SWITCH_STATE");
+                if (name != null && state != null) {
                     try {
-                        int newConfig = Integer.parseInt(switchState);
-                        if (newConfig != mUsbConfig) {
-                            mPreviousUsbConfig = mUsbConfig;
-                            mUsbConfig = newConfig;
+                        int intState = Integer.parseInt(state);
+                        if ("usb_connected".equals(name)) {
+                            mConnected = intState;
                             // trigger an Intent broadcast
                             if (mSystemReady) {
-                                update();
+                                // debounce disconnects
+                                update(mConnected == 0);
+                            }
+                        } else if ("usb_configuration".equals(name)) {
+                            mConfiguration = intState;
+                            // trigger an Intent broadcast
+                            if (mSystemReady) {
+                                update(mConnected == 0);
                             }
                         }
                     } catch (NumberFormatException e) {
@@ -111,6 +134,7 @@
         mContext = context;
         init();  // set initial status
 
+        mUEventObserver.startObserving(USB_CONNECTED_MATCH);
         mUEventObserver.startObserving(USB_CONFIGURATION_MATCH);
         mUEventObserver.startObserving(USB_FUNCTIONS_MATCH);
     }
@@ -119,10 +143,15 @@
         char[] buffer = new char[1024];
 
         try {
-            FileReader file = new FileReader(USB_CONFIGURATION_PATH);
+            FileReader file = new FileReader(USB_CONNECTED_PATH);
             int len = file.read(buffer, 0, 1024);
-            mPreviousUsbConfig = mUsbConfig = Integer.valueOf((new String(buffer, 0, len)).trim());
+            file.close();
+            mConnected = Integer.valueOf((new String(buffer, 0, len)).trim());
 
+            file = new FileReader(USB_CONFIGURATION_PATH);
+            len = file.read(buffer, 0, 1024);
+            file.close();
+            mConfiguration = Integer.valueOf((new String(buffer, 0, len)).trim());
         } catch (FileNotFoundException e) {
             Slog.w(TAG, "This kernel does not have USB configuration switch support");
         } catch (Exception e) {
@@ -135,6 +164,7 @@
                 File file = new File(files[i], "enable");
                 FileReader reader = new FileReader(file);
                 int len = reader.read(buffer, 0, 1024);
+                reader.close();
                 int value = Integer.valueOf((new String(buffer, 0, len)).trim());
                 String functionName = files[i].getName();
                 if (value == 1) {
@@ -152,13 +182,14 @@
 
     void systemReady() {
         synchronized (this) {
-            update();
+            update(false);
             mSystemReady = true;
         }
     }
 
-    private final void update() {
-        mHandler.sendEmptyMessage(MSG_UPDATE);
+    private final void update(boolean delayed) {
+        mHandler.removeMessages(MSG_UPDATE);
+        mHandler.sendEmptyMessageDelayed(MSG_UPDATE, delayed ? UPDATE_DELAY : 0);
     }
 
     private final Handler mHandler = new Handler() {
@@ -177,31 +208,26 @@
             switch (msg.what) {
                 case MSG_UPDATE:
                     synchronized (this) {
-                        final ContentResolver cr = mContext.getContentResolver();
+                        if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) {
 
-                        if (Settings.Secure.getInt(cr,
-                                Settings.Secure.DEVICE_PROVISIONED, 0) == 0) {
-                            Slog.i(TAG, "Device not provisioned, skipping USB broadcast");
-                            return;
-                        }
-                        // Send an Intent containing connected/disconnected state
-                        // and the enabled/disabled state of all USB functions
-                        Intent intent;
-                        boolean usbConnected = (mUsbConfig != 0);
-                        if (usbConnected) {
-                            intent = new Intent(UsbManager.ACTION_USB_CONNECTED);
+                            final ContentResolver cr = mContext.getContentResolver();
+                            if (Settings.Secure.getInt(cr,
+                                    Settings.Secure.DEVICE_PROVISIONED, 0) == 0) {
+                                Slog.i(TAG, "Device not provisioned, skipping USB broadcast");
+                                return;
+                            }
+
+                            mLastConnected = mConnected;
+                            mLastConfiguration = mConfiguration;
+
+                            // send a sticky broadcast containing current USB state
+                            Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
+                            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+                            intent.putExtra(UsbManager.USB_CONNECTED, mConnected != 0);
+                            intent.putExtra(UsbManager.USB_CONFIGURATION, mConfiguration);
                             addEnabledFunctions(intent);
-                        } else {
-                            intent = new Intent(UsbManager.ACTION_USB_DISCONNECTED);
+                            mContext.sendStickyBroadcast(intent);
                         }
-                        mContext.sendBroadcast(intent);
-
-                        // send a sticky broadcast for clients interested in both connect and disconnect
-                        intent = new Intent(UsbManager.ACTION_USB_STATE);
-                        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-                        intent.putExtra(UsbManager.USB_CONNECTED, usbConnected);
-                        addEnabledFunctions(intent);
-                        mContext.sendStickyBroadcast(intent);
                     }
                     break;
             }
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 5712e60..7652a26 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -111,14 +111,6 @@
     private boolean mUsbMassStorageOff;  // track the status of USB Mass Storage
     private boolean mUsbConnected;       // track the status of USB connection
 
-    // mUsbHandler message
-    static final int USB_STATE_CHANGE = 1;
-    static final int USB_DISCONNECTED = 0;
-    static final int USB_CONNECTED = 1;
-
-    // Time to delay before processing USB disconnect events
-    static final long USB_DISCONNECT_DELAY = 1000;
-
     public Tethering(Context context, Looper looper) {
         mContext = context;
         mLooper = looper;
@@ -429,25 +421,12 @@
         }
     }
 
-    private Handler mUsbHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            mUsbConnected = (msg.arg1 == USB_CONNECTED);
-            updateUsbStatus();
-        }
-    };
-
     private class StateReceiver extends BroadcastReceiver {
         public void onReceive(Context content, Intent intent) {
             String action = intent.getAction();
             if (action.equals(UsbManager.ACTION_USB_STATE)) {
-                // process connect events immediately, but delay handling disconnects
-                // to debounce USB configuration changes
-                boolean connected = intent.getExtras().getBoolean(UsbManager.USB_CONNECTED);
-                Message msg = Message.obtain(mUsbHandler, USB_STATE_CHANGE,
-                        (connected ? USB_CONNECTED : USB_DISCONNECTED), 0);
-                mUsbHandler.removeMessages(USB_STATE_CHANGE);
-                mUsbHandler.sendMessageDelayed(msg, connected ? 0 : USB_DISCONNECT_DELAY);
+                mUsbConnected = intent.getExtras().getBoolean(UsbManager.USB_CONNECTED);
+                updateUsbStatus();
             } else if (action.equals(Intent.ACTION_MEDIA_SHARED)) {
                 mUsbMassStorageOff = false;
                 updateUsbStatus();