bluetooth tethering

Change-Id: Id6d5fb1922facc7013abc29214d3e1141995b767
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 859353a..4da0bac 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -344,7 +344,8 @@
         mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) ||
                                   !mTethering.isDunRequired()) &&
                                  (mTethering.getTetherableUsbRegexs().length != 0 ||
-                                  mTethering.getTetherableWifiRegexs().length != 0) &&
+                                  mTethering.getTetherableWifiRegexs().length != 0 ||
+                                  mTethering.getTetherableBluetoothRegexs().length != 0) &&
                                  mTethering.getUpstreamIfaceRegexs().length != 0);
 
     }
@@ -1676,6 +1677,15 @@
         }
     }
 
+    public String[] getTetherableBluetoothRegexs() {
+        enforceTetherAccessPermission();
+        if (isTetheringSupported()) {
+            return mTethering.getTetherableBluetoothRegexs();
+        } else {
+            return new String[0];
+        }
+    }
+
     // TODO - move iface listing, queries, etc to new module
     // javadoc from interface
     public String[] getTetherableIfaces() {
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index c452590..249c32b 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -128,11 +128,12 @@
                                     Slog.e(TAG, String.format(
                                             "Error handling '%s'", event), ex);
                                 }
-                            }
-                            try {
-                                mResponseQueue.put(event);
-                            } catch (InterruptedException ex) {
-                                Slog.e(TAG, "Failed to put response onto queue", ex);
+                            } else {
+                                try {
+                                    mResponseQueue.put(event);
+                                } catch (InterruptedException ex) {
+                                    Slog.e(TAG, "Failed to put response onto queue", ex);
+                                }
                             }
                         } catch (NumberFormatException nfe) {
                             Slog.w(TAG, String.format("Bad msg (%s)", event));
@@ -209,6 +210,7 @@
      */
     public synchronized ArrayList<String> doCommand(String cmd)
             throws NativeDaemonConnectorException  {
+        mResponseQueue.clear();
         sendCommand(cmd);
 
         ArrayList<String> response = new ArrayList<String>();
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index acedd26..949b874 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -19,8 +19,8 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.bluetooth.BluetoothPan;
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -32,7 +32,6 @@
 import android.net.IConnectivityManager;
 import android.net.INetworkManagementEventObserver;
 import android.net.NetworkInfo;
-import android.net.NetworkUtils;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.HandlerThread;
@@ -53,6 +52,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.Set;
 /**
  * @hide
@@ -75,6 +75,7 @@
     // TODO - remove both of these - should be part of interface inspection/selection stuff
     private String[] mTetherableUsbRegexs;
     private String[] mTetherableWifiRegexs;
+    private String[] mTetherableBluetoothRegexs;
     private String[] mUpstreamIfaceRegexs;
 
     private Looper mLooper;
@@ -94,6 +95,8 @@
     private static final String DHCP_DEFAULT_RANGE1_STOP  = "192.168.42.254";
     private static final String DHCP_DEFAULT_RANGE2_START = "192.168.43.2";
     private static final String DHCP_DEFAULT_RANGE2_STOP  = "192.168.43.254";
+    private static final String DHCP_DEFAULT_RANGE3_START = "192.168.44.9";
+    private static final String DHCP_DEFAULT_RANGE3_STOP  = "192.168.44.254";
 
     private String[] mDnsServers;
     private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
@@ -153,11 +156,13 @@
         mDhcpRange = context.getResources().getStringArray(
                 com.android.internal.R.array.config_tether_dhcp_range);
         if ((mDhcpRange.length == 0) || (mDhcpRange.length % 2 ==1)) {
-            mDhcpRange = new String[4];
+            mDhcpRange = new String[6];
             mDhcpRange[0] = DHCP_DEFAULT_RANGE1_START;
             mDhcpRange[1] = DHCP_DEFAULT_RANGE1_STOP;
             mDhcpRange[2] = DHCP_DEFAULT_RANGE2_START;
             mDhcpRange[3] = DHCP_DEFAULT_RANGE2_STOP;
+            mDhcpRange[4] = DHCP_DEFAULT_RANGE3_START;
+            mDhcpRange[5] = DHCP_DEFAULT_RANGE3_STOP;
         }
         mDunRequired = false; // resample when we turn on
 
@@ -165,6 +170,8 @@
                 com.android.internal.R.array.config_tether_usb_regexs);
         mTetherableWifiRegexs = context.getResources().getStringArray(
                 com.android.internal.R.array.config_tether_wifi_regexs);
+        mTetherableBluetoothRegexs = context.getResources().getStringArray(
+                com.android.internal.R.array.config_tether_bluetooth_regexs);
         mUpstreamIfaceRegexs = context.getResources().getStringArray(
                 com.android.internal.R.array.config_tether_upstream_regexs);
 
@@ -183,6 +190,8 @@
         } else if (isUsb(iface)) {
             found = true;
             usb = true;
+        } else if (isBluetooth(iface)) {
+            found = true;
         }
         if (found == false) return;
 
@@ -217,6 +226,12 @@
         return false;
     }
 
+    public boolean isBluetooth(String iface) {
+        for (String regex : mTetherableBluetoothRegexs) {
+            if (iface.matches(regex)) return true;
+        }
+        return false;
+    }
     public void interfaceAdded(String iface) {
         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
         INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
@@ -229,6 +244,9 @@
             found = true;
             usb = true;
         }
+        if (isBluetooth(iface)) {
+            found = true;
+        }
         if (found == false) {
             if (DEBUG) Log.d(TAG, iface + " is not a tetherable iface, ignoring");
             return;
@@ -324,13 +342,14 @@
 
         boolean wifiTethered = false;
         boolean usbTethered = false;
+        boolean bluetoothTethered = false;
 
         synchronized (mIfaces) {
             Set ifaces = mIfaces.keySet();
             for (Object iface : ifaces) {
                 TetherInterfaceSM sm = mIfaces.get(iface);
                 if (sm != null) {
-                    if(sm.isErrored()) {
+                    if (sm.isErrored()) {
                         erroredList.add((String)iface);
                     } else if (sm.isAvailable()) {
                         availableList.add((String)iface);
@@ -339,6 +358,8 @@
                             usbTethered = true;
                         } else if (isWifi((String)iface)) {
                             wifiTethered = true;
+                      } else if (isBluetooth((String)iface)) {
+                            bluetoothTethered = true;
                         }
                         activeList.add((String)iface);
                     }
@@ -359,13 +380,19 @@
         }
 
         if (usbTethered) {
-            if (wifiTethered) {
+            if (wifiTethered || bluetoothTethered) {
                 showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
             } else {
                 showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_usb);
             }
         } else if (wifiTethered) {
-            showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_wifi);
+            if (bluetoothTethered) {
+                showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
+            } else {
+                showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_wifi);
+            }
+        } else if (bluetoothTethered) {
+            showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_bluetooth);
         } else {
             clearTetheredNotification();
         }
@@ -396,7 +423,7 @@
         CharSequence message = r.getText(com.android.internal.R.string.
                 tethered_notification_message);
 
-        if(mTetheredNotification == null) {
+        if (mTetheredNotification == null) {
             mTetheredNotification = new Notification();
             mTetheredNotification.when = 0;
         }
@@ -471,7 +498,7 @@
         }
     }
 
-    // toggled when we enter/leave the fully teathered state
+    // toggled when we enter/leave the fully tethered state
     private boolean enableUsbRndis(boolean enabled) {
         if (DEBUG) Log.d(TAG, "enableUsbRndis(" + enabled + ")");
         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
@@ -554,6 +581,10 @@
         return mTetherableWifiRegexs;
     }
 
+    public String[] getTetherableBluetoothRegexs() {
+        return mTetherableBluetoothRegexs;
+    }
+
     public String[] getUpstreamIfaceRegexs() {
         return mUpstreamIfaceRegexs;
     }