Update Tethering.

Adds telephony support, async model, multiple tethered iface suport,
better notifications, device config.

bug:2413855
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index d435df5..badb767 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -125,13 +125,21 @@
 
     /**
      * @hide
+     * gives a String[]
      */
-    public static final String EXTRA_AVAILABLE_TETHER_COUNT = "availableCount";
+    public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
 
     /**
      * @hide
+     * gives a String[]
      */
-    public static final String EXTRA_ACTIVE_TETHER_COUNT = "activeCount";
+    public static final String EXTRA_ACTIVE_TETHER = "activeArray";
+
+    /**
+     * @hide
+     * gives a String[]
+     */
+    public static final String EXTRA_ERRORED_TETHER = "erroredArray";
 
     /**
      * The Default Mobile data connection.  When active, all data traffic
@@ -400,4 +408,37 @@
             return false;
         }
     }
+
+    /**
+     * {@hide}
+     */
+    public boolean isTetheringSupported() {
+        try {
+            return mService.isTetheringSupported();
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * {@hide}
+     */
+    public String[] getTetherableUsbRegexs() {
+        try {
+            return mService.getTetherableUsbRegexs();
+        } catch (RemoteException e) {
+            return new String[0];
+        }
+    }
+
+    /**
+     * {@hide}
+     */
+    public String[] getTetherableWifiRegexs() {
+        try {
+            return mService.getTetherableWifiRegexs();
+        } catch (RemoteException e) {
+            return new String[0];
+        }
+    }
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index caa3f2b..508e9c3a 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -55,7 +55,13 @@
 
     boolean untether(String iface);
 
+    boolean isTetheringSupported();
+
     String[] getTetherableIfaces();
 
     String[] getTetheredIfaces();
+
+    String[] getTetherableUsbRegexs();
+
+    String[] getTetherableWifiRegexs();
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7b52f7f..14e27eb 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2210,6 +2210,12 @@
         public static final String NETWORK_PREFERENCE = "network_preference";
 
         /**
+         * Used to disable Tethering on a device - defaults to true
+         * @hide
+         */
+        public static final String TETHER_SUPPORTED = "tether_supported";
+
+        /**
          * No longer supported.
          */
         public static final String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
diff --git a/core/java/com/android/internal/app/TetherActivity.java b/core/java/com/android/internal/app/TetherActivity.java
index cb268b3..a48ccf9 100644
--- a/core/java/com/android/internal/app/TetherActivity.java
+++ b/core/java/com/android/internal/app/TetherActivity.java
@@ -32,16 +32,19 @@
 import android.util.Log;
 
 /**
- * This activity is shown to the user for him/her to connect/disconnect a Tether
- * connection.  It will display notification when a suitable connection is made
- * to allow the tether to be setup.  A second notification will be show when a
- * tether is active, allowing the user to manage tethered connections.
+ * This activity is shown to the user in two cases: when a connection is possible via
+ * a usb tether and when any type of tether is connected.  In the connecting case
+ * It allows them to start a USB tether.  In the Tethered/disconnecting case it
+ * will disconnect all tethers.
  */
 public class TetherActivity extends AlertActivity implements
         DialogInterface.OnClickListener {
 
     private static final int POSITIVE_BUTTON = AlertDialog.BUTTON1;
 
+    // count of the number of tethered connections at activity create time.
+    private int mTethered;
+
     /* Used to detect when the USB cable is unplugged, so we can call finish() */
     private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() {
         @Override
@@ -52,8 +55,6 @@
         }
     };
 
-    private boolean mWantTethering;
-
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -61,17 +62,18 @@
         // determine if we advertise tethering or untethering
         ConnectivityManager cm =
                 (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
-        if (cm.getTetheredIfaces().length > 0) {
-            mWantTethering = false;
-        } else if (cm.getTetherableIfaces().length > 0) {
-            mWantTethering = true;
-        } else {
+        mTethered = cm.getTetheredIfaces().length;
+        int tetherable = cm.getTetherableIfaces().length;
+        if ((mTethered == 0) && (tetherable == 0)) {
             finish();
             return;
         }
 
-        // Set up the "dialog"
-        if (mWantTethering == true) {
+        // Set up the dialog
+        // if we have a tethered connection we put up a "Do you want to Disconect" dialog
+        // otherwise we must have a tetherable interface (else we'd return above)
+        // and so we want to put up the "do you want to connect" dialog
+        if (mTethered == 0) {
             mAlertParams.mIconId = com.android.internal.R.drawable.ic_dialog_usb;
             mAlertParams.mTitle = getString(com.android.internal.R.string.tether_title);
             mAlertParams.mMessage = getString(com.android.internal.R.string.tether_message);
@@ -114,17 +116,36 @@
      * {@inheritDoc}
      */
     public void onClick(DialogInterface dialog, int which) {
+        boolean error =  false;
 
         if (which == POSITIVE_BUTTON) {
-            ConnectivityManager connManager =
+            ConnectivityManager cm =
                     (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
             // start/stop tethering
-            if (mWantTethering) {
-                if (!connManager.tether("ppp0")) {
+            String[] tethered = cm.getTetheredIfaces();
+
+            if (tethered.length == 0) {
+                String[] tetherable = cm.getTetherableIfaces();
+                String[] usbRegexs = cm.getTetherableUsbRegexs();
+                for (String t : tetherable) {
+                    for (String r : usbRegexs) {
+                        if (t.matches(r)) {
+                            if (!cm.tether(t))
+                                error = true;
+                            break;
+                        }
+                    }
+                }
+                if (error) {
                     showTetheringError();
                 }
             } else {
-                if (!connManager.untether("ppp0")) {
+                for (String t : tethered) {
+                    if (!cm.untether("ppp0")) {
+                        error = true;
+                    }
+                }
+                if (error) {
                     showUnTetheringError();
                 }
             }
@@ -134,7 +155,12 @@
     }
 
     private void handleTetherStateChanged(Intent intent) {
-        finish();
+        // determine if we advertise tethering or untethering
+        ConnectivityManager cm =
+                (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
+        if (mTethered != cm.getTetheredIfaces().length) {
+            finish();
+        }
     }
 
     private void showTetheringError() {
diff --git a/core/java/com/android/internal/util/HierarchicalStateMachine.java b/core/java/com/android/internal/util/HierarchicalStateMachine.java
index a1c5078..b4af79c 100644
--- a/core/java/com/android/internal/util/HierarchicalStateMachine.java
+++ b/core/java/com/android/internal/util/HierarchicalStateMachine.java
@@ -1021,7 +1021,7 @@
      * @param msg that couldn't be handled.
      */
     protected void unhandledMessage(Message msg) {
-        Log.e(TAG, "unhandledMessage: msg.what=" + msg.what);
+        Log.e(TAG, mName + " - unhandledMessage: msg.what=" + msg.what);
     }
 
     /**
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 40c78f7..5d561b8 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -70,6 +70,22 @@
         <item>"0,1"</item>
     </string-array>
 
+    <!-- List of regexpressions describing the interface (if any) that represent tetherable
+         USB interfaces.  If the device doesn't want to support tething over USB this should
+         be empty.  An example would be "usb.*" -->
+    <string-array translatable="false" name="config_tether_usb_regexs">
+    </string-array>
+
+    <!-- List of regexpressions describing the interface (if any) that represent tetherable
+         Wifi interfaces.  If the device doesn't want to support tethering over Wifi this
+         should be empty.  An example would be "softap.*" -->
+    <string-array translatable="false" name="config_tether_wifi_regexs">
+    </string-array>
+
+    <!-- Dhcp range (min, max) to use for tethering purposes -->
+    <string-array name="config_tether_dhcp_range">
+    </string-array>
+
     <!-- Flag indicating whether the keyguard should be bypassed when
          the slider is open.  This can be set or unset depending how easily
          the slider can be opened (for example, in a pocket or purse). -->