Non persistent adapter service

Change-Id: Ib13d5c77416e58161df0e04d7a15ec0dddbde8b5

Conflicts:

	core/java/android/bluetooth/BluetoothInputDevice.java

Conflicts:

	core/java/com/android/internal/app/ShutdownThread.java
	services/java/com/android/server/SystemServer.java

Conflicts:

	services/java/com/android/server/SystemServer.java
	services/java/com/android/server/pm/ShutdownThread.java
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index c59a5aa..bf5f175 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -108,6 +108,36 @@
     private IBluetoothA2dp mService;
     private BluetoothAdapter mAdapter;
 
+    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+            new IBluetoothStateChangeCallback.Stub() {
+                public void onBluetoothStateChange(boolean up) {
+                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+                    if (!up) {
+                        if (DBG) Log.d(TAG,"Unbinding service...");
+                        synchronized (mConnection) {
+                            try {
+                                mService = null;
+                                mContext.unbindService(mConnection);
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    } else {
+                        synchronized (mConnection) {
+                            try {
+                                if (mService == null) {
+                                    if (DBG) Log.d(TAG,"Binding service...");
+                                    if (!mContext.bindService(new Intent(IBluetoothA2dp.class.getName()), mConnection, 0)) {
+                                        Log.e(TAG, "Could not bind to Bluetooth A2DP Service");
+                                    }
+                                }
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    }
+                }
+        };
     /**
      * Create a BluetoothA2dp proxy object for interacting with the local
      * Bluetooth A2DP service.
@@ -117,6 +147,15 @@
         mContext = context;
         mServiceListener = l;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
         if (!context.bindService(new Intent(IBluetoothA2dp.class.getName()), mConnection, 0)) {
             Log.e(TAG, "Could not bind to Bluetooth A2DP Service");
         }
@@ -124,8 +163,30 @@
 
     /*package*/ void close() {
         mServiceListener = null;
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (Exception e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
+        synchronized (mConnection) {
+            if (mService != null) {
+                try {
+                    mService = null;
+                    mContext.unbindService(mConnection);
+                } catch (Exception re) {
+                    Log.e(TAG,"",re);
+                }
+            }
+        }
     }
 
+    public void finalize() {
+        close();
+    }
     /**
      * Initiate connection to a profile of the remote bluetooth device.
      *
@@ -260,7 +321,7 @@
      * Set priority of the profile
      *
      * <p> The device should already be paired.
-     *  Priority can be one of {@link #PRIORITY_ON} or
+     *  Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
      * {@link #PRIORITY_OFF},
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index c822754..75ef3dd 100755
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -73,7 +73,7 @@
  */
 public final class BluetoothAdapter {
     private static final String TAG = "BluetoothAdapter";
-    private static final boolean DBG = false;
+    private static final boolean DBG = true;
 
     /**
      * Sentinel error value for this class. Guaranteed to not equal any other
@@ -343,7 +343,7 @@
     public static final int STATE_DISCONNECTING = 3;
 
     /** @hide */
-    public static final String BLUETOOTH_SERVICE = "bluetooth";
+    public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
 
     private static final int ADDRESS_LENGTH = 17;
 
@@ -353,7 +353,8 @@
      */
     private static BluetoothAdapter sAdapter;
 
-    private final IBluetooth mService;
+    private final IBluetoothManager mManagerService;
+    private IBluetooth mService;
 
     private Handler mServiceRecordHandler;
 
@@ -367,10 +368,10 @@
      */
     public static synchronized BluetoothAdapter getDefaultAdapter() {
         if (sAdapter == null) {
-            IBinder b = ServiceManager.getService("bluetooth");
+            IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
             if (b != null) {
-                IBluetooth service = IBluetooth.Stub.asInterface(b);
-                sAdapter = new BluetoothAdapter(service);
+                IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
+                sAdapter = new BluetoothAdapter(managerService);
             } else {
                 Log.e(TAG, "Bluetooth binder is null");
             }
@@ -381,11 +382,15 @@
     /**
      * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
      */
-    BluetoothAdapter(IBluetooth service) {
-        if (service == null) {
-            throw new IllegalArgumentException("service is null");
+    BluetoothAdapter(IBluetoothManager managerService) {
+
+        if (managerService == null) {
+            throw new IllegalArgumentException("bluetooth manager service is null");
         }
-        mService = service;
+        try {
+            mService = managerService.registerAdapter(mManagerCallback);
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        mManagerService = managerService;
         mServiceRecordHandler = null;
     }
 
@@ -402,6 +407,10 @@
      * @throws IllegalArgumentException if address is invalid
      */
     public BluetoothDevice getRemoteDevice(String address) {
+        if (mService == null) {
+            Log.e(TAG, "BT not enabled. Cannot create Remote Device");
+            return null;
+        }
         return new BluetoothDevice(address);
     }
 
@@ -433,8 +442,11 @@
      * @return true if the local adapter is turned on
      */
     public boolean isEnabled() {
+
         try {
-            return mService.isEnabled();
+            synchronized(mManagerCallback) {
+                if (mService != null) return mService.isEnabled();
+            }
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
@@ -451,9 +463,15 @@
      * @return current state of Bluetooth adapter
      */
     public int getState() {
-        if (mService == null) return STATE_OFF;
         try {
-            return mService.getState();
+            synchronized(mManagerCallback) {
+                if (mService != null)
+                {
+                    return mService.getState();
+                }
+                // TODO(BT) there might be a small gap during STATE_TURNING_ON that
+                //          mService is null, handle that case
+            }
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return STATE_OFF;
     }
@@ -486,8 +504,13 @@
      *         immediate error
      */
     public boolean enable() {
+
+        boolean enabled = false;
         try {
-            return mService.enable();
+            enabled = mManagerService.enable();
+            if (enabled) {
+                // TODO(BT)
+            }
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
@@ -518,7 +541,7 @@
      */
     public boolean disable() {
         try {
-            return mService.disable(true);
+            return mManagerService.disable(true);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
@@ -534,8 +557,9 @@
      * @hide
      */
     public boolean disable(boolean persist) {
+
         try {
-            return mService.disable(persist);
+            return mManagerService.disable(persist);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
@@ -549,7 +573,7 @@
      */
     public String getAddress() {
         try {
-            return mService.getAddress();
+            return mManagerService.getAddress();
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return null;
     }
@@ -563,7 +587,7 @@
      */
     public String getName() {
         try {
-            return mService.getName();
+            return mManagerService.getName();
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return null;
     }
@@ -579,7 +603,9 @@
     public ParcelUuid[] getUuids() {
         if (getState() != STATE_ON) return null;
         try {
-            return mService.getUuids();
+            synchronized(mManagerCallback) {
+                if (mService != null) return mService.getUuids();
+            }
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return null;
     }
@@ -602,7 +628,9 @@
     public boolean setName(String name) {
         if (getState() != STATE_ON) return false;
         try {
-            return mService.setName(name);
+            synchronized(mManagerCallback) {
+                if (mService != null) return mService.setName(name);
+            }
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
@@ -626,7 +654,9 @@
     public int getScanMode() {
         if (getState() != STATE_ON) return SCAN_MODE_NONE;
         try {
-            return mService.getScanMode();
+            synchronized(mManagerCallback) {
+                if (mService != null) return mService.getScanMode();
+            }
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return SCAN_MODE_NONE;
     }
@@ -662,7 +692,9 @@
     public boolean setScanMode(int mode, int duration) {
         if (getState() != STATE_ON) return false;
         try {
-            return mService.setScanMode(mode, duration);
+            synchronized(mManagerCallback) {
+                if (mService != null) return mService.setScanMode(mode, duration);
+            }
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
@@ -678,7 +710,9 @@
     public int getDiscoverableTimeout() {
         if (getState() != STATE_ON) return -1;
         try {
-            return mService.getDiscoverableTimeout();
+            synchronized(mManagerCallback) {
+                if (mService != null) return mService.getDiscoverableTimeout();
+            }
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return -1;
     }
@@ -687,7 +721,9 @@
     public void setDiscoverableTimeout(int timeout) {
         if (getState() != STATE_ON) return;
         try {
-            mService.setDiscoverableTimeout(timeout);
+            synchronized(mManagerCallback) {
+                if (mService != null) mService.setDiscoverableTimeout(timeout);
+            }
         } catch (RemoteException e) {Log.e(TAG, "", e);}
     }
 
@@ -724,7 +760,9 @@
     public boolean startDiscovery() {
         if (getState() != STATE_ON) return false;
         try {
-            return mService.startDiscovery();
+            synchronized(mManagerCallback) {
+                if (mService != null) return mService.startDiscovery();
+            }
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
@@ -749,7 +787,9 @@
     public boolean cancelDiscovery() {
         if (getState() != STATE_ON) return false;
         try {
-            return mService.cancelDiscovery();
+            synchronized(mManagerCallback) {
+                if (mService != null) return mService.cancelDiscovery();
+            }
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
@@ -776,7 +816,9 @@
     public boolean isDiscovering() {
         if (getState() != STATE_ON) return false;
         try {
-            return mService.isDiscovering();
+            synchronized(mManagerCallback) {
+                if (mService != null ) return mService.isDiscovering();
+            }
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
@@ -797,7 +839,10 @@
             return toDeviceSet(new BluetoothDevice[0]);
         }
         try {
-            return toDeviceSet(mService.getBondedDevices());
+            synchronized(mManagerCallback) {
+                if (mService != null) return toDeviceSet(mService.getBondedDevices());
+            }
+            return toDeviceSet(new BluetoothDevice[0]);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return null;
     }
@@ -818,7 +863,9 @@
     public int getConnectionState() {
         if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED;
         try {
-            return mService.getAdapterConnectionState();
+            synchronized(mManagerCallback) {
+                if (mService != null) return mService.getAdapterConnectionState();
+            }
         } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);}
         return BluetoothAdapter.STATE_DISCONNECTED;
     }
@@ -841,7 +888,9 @@
     public int getProfileConnectionState(int profile) {
         if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
         try {
-            return mService.getProfileConnectionState(profile);
+            synchronized(mManagerCallback) {
+                if (mService != null) return mService.getProfileConnectionState(profile);
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "getProfileConnectionState:", e);
         }
@@ -1160,6 +1209,23 @@
         }
     }
 
+    final private IBluetoothManagerCallback mManagerCallback =
+        new IBluetoothManagerCallback.Stub() {
+            public void onBluetoothServiceUp(IBluetooth bluetoothService) {
+                if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
+                synchronized (mManagerCallback) {
+                    mService = bluetoothService;
+                }
+            }
+
+            public void onBluetoothServiceDown() {
+                if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
+                synchronized (mManagerCallback) {
+                    mService = null;
+                }
+            }
+    };
+
     /**
      * Enable the Bluetooth Adapter, but don't auto-connect devices
      * and don't persist state. Only for use by system applications.
@@ -1245,6 +1311,17 @@
         return Collections.unmodifiableSet(deviceSet);
     }
 
+    protected void finalize() throws Throwable {
+        try {
+            mManagerService.unregisterAdapter(mManagerCallback);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            super.finalize();
+        }
+    }
+
+
     /**
      * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
      * <p>Alphabetic characters must be uppercase to be valid.
@@ -1275,4 +1352,14 @@
         }
         return true;
     }
+
+    /*package*/ IBluetoothManager getBluetoothManager() {
+            return mManagerService;
+    }
+
+    /*package*/ IBluetooth getBluetoothService() {
+        synchronized (mManagerCallback) {
+            return mService;
+        }
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 4d9dd82..82bd702 100755
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -65,6 +65,7 @@
  */
 public final class BluetoothDevice implements Parcelable {
     private static final String TAG = "BluetoothDevice";
+    private static final boolean DBG = true;
 
     /**
      * Sentinel error value for this class. Guaranteed to not equal any other
@@ -483,11 +484,8 @@
     /*package*/ static IBluetooth getService() {
         synchronized (BluetoothDevice.class) {
             if (sService == null) {
-                IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
-                if (b == null) {
-                    throw new RuntimeException("Bluetooth service not available");
-                }
-                sService = IBluetooth.Stub.asInterface(b);
+                BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+                sService = adapter.getBluetoothService();
             }
         }
         return sService;
@@ -561,6 +559,7 @@
      * @return Bluetooth hardware address as string
      */
     public String getAddress() {
+        if (DBG) Log.d(TAG, "mAddress: " + mAddress);
         return mAddress;
     }
 
@@ -575,6 +574,10 @@
      * @return the Bluetooth name, or null if there was a problem.
      */
     public String getName() {
+        if (sService == null) {
+            Log.e(TAG, "BT not enabled. Cannot get Remote Device name");
+            return null;
+        }
         try {
             return sService.getRemoteName(this);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -589,6 +592,10 @@
      * @hide
      */
     public String getAlias() {
+        if (sService == null) {
+            Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias");
+            return null;
+        }
         try {
             return sService.getRemoteAlias(this);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -606,6 +613,10 @@
      * @hide
      */
     public boolean setAlias(String alias) {
+        if (sService == null) {
+            Log.e(TAG, "BT not enabled. Cannot set Remote Device name");
+            return false;
+        }
         try {
             return sService.setRemoteAlias(this, alias);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -642,6 +653,10 @@
      * @hide
      */
     public boolean createBond() {
+        if (sService == null) {
+            Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
+            return false;
+        }
         try {
             return sService.createBond(this);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -706,6 +721,10 @@
      * @hide
      */
     public boolean cancelBondProcess() {
+        if (sService == null) {
+            Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond");
+            return false;
+        }
         try {
             return sService.cancelBondProcess(this);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -723,6 +742,10 @@
      * @hide
      */
     public boolean removeBond() {
+        if (sService == null) {
+            Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond");
+            return false;
+        }
         try {
             return sService.removeBond(this);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -740,6 +763,10 @@
      * @return the bond state
      */
     public int getBondState() {
+        if (sService == null) {
+            Log.e(TAG, "BT not enabled. Cannot get bond state");
+            return BOND_NONE;
+        }
         try {
             return sService.getBondState(this);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -753,6 +780,10 @@
      * @return Bluetooth class object, or null on error
      */
     public BluetoothClass getBluetoothClass() {
+        if (sService == null) {
+            Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class");
+            return null;
+        }
         try {
             int classInt = sService.getRemoteClass(this);
             if (classInt == BluetoothClass.ERROR) return null;
@@ -807,6 +838,10 @@
      *         or null on error
      */
      public ParcelUuid[] getUuids() {
+         if (sService == null) {
+            Log.e(TAG, "BT not enabled. Cannot get remote device Uuids");
+             return null;
+         }
         try {
             return sService.getRemoteUuids(this);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -847,6 +882,10 @@
 
     /** @hide */
     public boolean setPin(byte[] pin) {
+        if (sService == null) {
+            Log.e(TAG, "BT not enabled. Cannot set Remote Device pin");
+            return false;
+        }
         try {
             return sService.setPin(this, true, pin.length, pin);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -865,6 +904,10 @@
 
     /** @hide */
     public boolean setPairingConfirmation(boolean confirm) {
+        if (sService == null) {
+            Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
+            return false;
+        }
         try {
             return sService.setPairingConfirmation(this, confirm);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -883,6 +926,10 @@
 
     /** @hide */
     public boolean cancelPairingUserInput() {
+        if (sService == null) {
+            Log.e(TAG, "BT not enabled. Cannot create pairing user input");
+            return false;
+        }
         try {
             return sService.cancelBondProcess(this);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 2df33a63..541b69f 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -45,7 +45,7 @@
  */
 public final class BluetoothHeadset implements BluetoothProfile {
     private static final String TAG = "BluetoothHeadset";
-    private static final boolean DBG = false;
+    private static final boolean DBG = true;
 
     /**
      * Intent used to broadcast the change in connection state of the Headset
@@ -221,6 +221,37 @@
     private IBluetoothHeadset mService;
     private BluetoothAdapter mAdapter;
 
+    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+            new IBluetoothStateChangeCallback.Stub() {
+                public void onBluetoothStateChange(boolean up) {
+                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+                    if (!up) {
+                        if (DBG) Log.d(TAG,"Unbinding service...");
+                        synchronized (mConnection) {
+                            try {
+                                mService = null;
+                                mContext.unbindService(mConnection);
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    } else {
+                        synchronized (mConnection) {
+                            try {
+                                if (mService == null) {
+                                    if (DBG) Log.d(TAG,"Binding service...");
+                                    if (!mContext.bindService(new Intent(IBluetoothHeadset.class.getName()), mConnection, 0)) {
+                                        Log.e(TAG, "Could not bind to Bluetooth Headset Service");
+                                    }
+                                }
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    }
+                }
+        };
+
     /**
      * Create a BluetoothHeadset proxy object.
      */
@@ -228,6 +259,16 @@
         mContext = context;
         mServiceListener = l;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
+
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
         if (!context.bindService(new Intent(IBluetoothHeadset.class.getName()), mConnection, 0)) {
             Log.e(TAG, "Could not bind to Bluetooth Headset Service");
         }
@@ -241,9 +282,25 @@
      */
     /*package*/ void close() {
         if (DBG) log("close()");
-        if (mConnection != null) {
-            mContext.unbindService(mConnection);
-            mConnection = null;
+
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (Exception e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
+        synchronized (mConnection) {
+            if (mService != null) {
+                try {
+                    mService = null;
+                    mContext.unbindService(mConnection);
+                } catch (Exception re) {
+                    Log.e(TAG,"",re);
+                }
+            }
         }
         mServiceListener = null;
     }
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index 5dad291..4a0bc7e 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -57,7 +57,7 @@
  */
 public final class BluetoothHealth implements BluetoothProfile {
     private static final String TAG = "BluetoothHealth";
-    private static final boolean DBG = false;
+    private static final boolean DBG = true;
 
     /**
      * Health Profile Source Role - the health device.
@@ -97,6 +97,37 @@
     /** @hide */
     public static final int HEALTH_OPERATION_NOT_ALLOWED = 6005;
 
+    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+            new IBluetoothStateChangeCallback.Stub() {
+                public void onBluetoothStateChange(boolean up) {
+                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+                    if (!up) {
+                        if (DBG) Log.d(TAG,"Unbinding service...");
+                        synchronized (mConnection) {
+                            try {
+                                mService = null;
+                                mContext.unbindService(mConnection);
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    } else {
+                        synchronized (mConnection) {
+                            try {
+                                if (mService == null) {
+                                    if (DBG) Log.d(TAG,"Binding service...");
+                                    if (!mContext.bindService(new Intent(IBluetoothHealth.class.getName()), mConnection, 0)) {
+                                        Log.e(TAG, "Could not bind to Bluetooth Health Service");
+                                    }
+                                }
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    }
+                }
+        };
+
 
     /**
      * Register an application configuration that acts as a Health SINK.
@@ -442,6 +473,15 @@
         mContext = context;
         mServiceListener = l;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
         if (!context.bindService(new Intent(IBluetoothHealth.class.getName()), mConnection, 0)) {
             Log.e(TAG, "Could not bind to Bluetooth Health Service");
         }
@@ -449,9 +489,24 @@
 
     /*package*/ void close() {
         if (DBG) log("close()");
-        if (mConnection != null) {
-            mContext.unbindService(mConnection);
-            mConnection = null;
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (Exception e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
+        synchronized (mConnection) {
+            if (mService != null) {
+                try {
+                    mService = null;
+                    mContext.unbindService(mConnection);
+                } catch (Exception re) {
+                    Log.e(TAG,"",re);
+                }
+            }
         }
         mServiceListener = null;
     }
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index 478a9d3..bff966d 100755
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -44,7 +44,7 @@
  */
 public final class BluetoothInputDevice implements BluetoothProfile {
     private static final String TAG = "BluetoothInputDevice";
-    private static final boolean DBG = false;
+    private static final boolean DBG = true;
 
     /**
      * Intent used to broadcast the change in connection state of the Input
@@ -186,6 +186,37 @@
     private BluetoothAdapter mAdapter;
     private IBluetoothInputDevice mService;
 
+    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+            new IBluetoothStateChangeCallback.Stub() {
+                public void onBluetoothStateChange(boolean up) {
+                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+                    if (!up) {
+                        if (DBG) Log.d(TAG,"Unbinding service...");
+                        synchronized (mConnection) {
+                            try {
+                                mService = null;
+                                mContext.unbindService(mConnection);
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    } else {
+                        synchronized (mConnection) {
+                            try {
+                                if (mService == null) {
+                                    if (DBG) Log.d(TAG,"Binding service...");
+                                    if (!mContext.bindService(new Intent(IBluetoothInputDevice.class.getName()), mConnection, 0)) {
+                                        Log.e(TAG, "Could not bind to Bluetooth HID Service");
+                                    }
+                                }
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    }
+                }
+        };
+
     /**
      * Create a BluetoothInputDevice proxy object for interacting with the local
      * Bluetooth Service which handles the InputDevice profile
@@ -195,6 +226,16 @@
         mContext = context;
         mServiceListener = l;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
+
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
         if (!context.bindService(new Intent(IBluetoothInputDevice.class.getName()),
                                  mConnection, 0)) {
             Log.e(TAG, "Could not bind to Bluetooth HID Service");
@@ -203,9 +244,24 @@
 
     /*package*/ void close() {
         if (DBG) log("close()");
-        if (mConnection != null) {
-            mContext.unbindService(mConnection);
-            mConnection = null;
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (Exception e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
+        synchronized (mConnection) {
+            if (mService != null) {
+                try {
+                    mService = null;
+                    mContext.unbindService(mConnection);
+                } catch (Exception re) {
+                    Log.e(TAG,"",re);
+                }
+           }
         }
         mServiceListener = null;
     }
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 13526e8..13d9078 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -18,7 +18,10 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -27,7 +30,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-
 /**
  * This class provides the APIs to control the Bluetooth Pan
  * Profile.
@@ -41,7 +43,7 @@
  */
 public final class BluetoothPan implements BluetoothProfile {
     private static final String TAG = "BluetoothPan";
-    private static final boolean DBG = false;
+    private static final boolean DBG = true;
 
     /**
      * Intent used to broadcast the change in connection state of the Pan
@@ -76,15 +78,18 @@
      */
     public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
 
+    public static final int PAN_ROLE_NONE = 0;
     /**
      * The local device is acting as a Network Access Point.
      */
     public static final int LOCAL_NAP_ROLE = 1;
+    public static final int REMOTE_NAP_ROLE = 1;
 
     /**
      * The local device is acting as a PAN User.
      */
     public static final int LOCAL_PANU_ROLE = 2;
+    public static final int REMOTE_PANU_ROLE = 2;
 
     /**
      * Return codes for the connect and disconnect Bluez / Dbus calls.
@@ -112,34 +117,34 @@
      */
     public static final int PAN_OPERATION_SUCCESS = 1004;
 
+    private Context mContext;
     private ServiceListener mServiceListener;
     private BluetoothAdapter mAdapter;
-    private IBluetooth mService;
+    private IBluetoothPan mPanService;
 
     /**
      * Create a BluetoothPan proxy object for interacting with the local
      * Bluetooth Service which handles the Pan profile
      *
      */
-    /*package*/ BluetoothPan(Context mContext, ServiceListener l) {
-        IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
+    /*package*/ BluetoothPan(Context context, ServiceListener l) {
+        mContext = context;
         mServiceListener = l;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
-        if (b != null) {
-            mService = IBluetooth.Stub.asInterface(b);
-            if (mServiceListener != null) {
-                mServiceListener.onServiceConnected(BluetoothProfile.PAN, this);
-            }
-        } else {
-            Log.w(TAG, "Bluetooth Service not available!");
-
-            // Instead of throwing an exception which prevents people from going
-            // into Wireless settings in the emulator. Let it crash later when it is actually used.
-            mService = null;
+        Log.d(TAG, "BluetoothPan() call bindService");
+        if (!context.bindService(new Intent(IBluetoothPan.class.getName()),
+                                 mConnection, 0)) {
+            Log.e(TAG, "Could not bind to Bluetooth HID Service");
         }
+        Log.d(TAG, "BluetoothPan(), bindService called");
     }
 
     /*package*/ void close() {
+        if (DBG) log("close()");
+        if (mConnection != null) {
+            mContext.unbindService(mConnection);
+            mConnection = null;
+        }
         mServiceListener = null;
     }
 
@@ -163,18 +168,16 @@
      */
     public boolean connect(BluetoothDevice device) {
         if (DBG) log("connect(" + device + ")");
-        if (mService != null && isEnabled() &&
+        if (mPanService != null && isEnabled() &&
             isValidDevice(device)) {
-            //TODO(BT
-            /*
             try {
-                return mService.connectPanDevice(device);
+                return mPanService.connect(device);
             } catch (RemoteException e) {
                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
                 return false;
-            }*/
+            }
         }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        if (mPanService == null) Log.w(TAG, "Proxy not attached to service");
         return false;
     }
 
@@ -206,18 +209,16 @@
      */
     public boolean disconnect(BluetoothDevice device) {
         if (DBG) log("disconnect(" + device + ")");
-        if (mService != null && isEnabled() &&
+        if (mPanService != null && isEnabled() &&
             isValidDevice(device)) {
-            //TODO(BT
-            /*
             try {
-                return mService.disconnectPanDevice(device);
+                return mPanService.disconnect(device);
             } catch (RemoteException e) {
                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
                 return false;
-            }*/
+            }
         }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        if (mPanService == null) Log.w(TAG, "Proxy not attached to service");
         return false;
     }
 
@@ -226,17 +227,15 @@
      */
     public List<BluetoothDevice> getConnectedDevices() {
         if (DBG) log("getConnectedDevices()");
-        if (mService != null && isEnabled()) {
-            //TODO(BT
-            /*
+        if (mPanService != null && isEnabled()) {
             try {
-                return mService.getConnectedPanDevices();
+                return mPanService.getConnectedDevices();
             } catch (RemoteException e) {
                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
                 return new ArrayList<BluetoothDevice>();
-            }*/
+            }
         }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        if (mPanService == null) Log.w(TAG, "Proxy not attached to service");
         return new ArrayList<BluetoothDevice>();
     }
 
@@ -245,17 +244,15 @@
      */
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
         if (DBG) log("getDevicesMatchingStates()");
-        if (mService != null && isEnabled()) {
-            //TODO(BT
-            /*
+        if (mPanService != null && isEnabled()) {
             try {
-                return mService.getPanDevicesMatchingConnectionStates(states);
+                return mPanService.getDevicesMatchingConnectionStates(states);
             } catch (RemoteException e) {
                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
                 return new ArrayList<BluetoothDevice>();
-            }*/
+            }
         }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        if (mPanService == null) Log.w(TAG, "Proxy not attached to service");
         return new ArrayList<BluetoothDevice>();
     }
 
@@ -264,45 +261,57 @@
      */
     public int getConnectionState(BluetoothDevice device) {
         if (DBG) log("getState(" + device + ")");
-        if (mService != null && isEnabled()
+        if (mPanService != null && isEnabled()
             && isValidDevice(device)) {
-            //TODO(BT
-            /*
             try {
-                return mService.getPanDeviceConnectionState(device);
+                return mPanService.getConnectionState(device);
             } catch (RemoteException e) {
                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
                 return BluetoothProfile.STATE_DISCONNECTED;
-            }*/
+            }
         }
-        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        if (mPanService == null) Log.w(TAG, "Proxy not attached to service");
         return BluetoothProfile.STATE_DISCONNECTED;
     }
 
     public void setBluetoothTethering(boolean value) {
         if (DBG) log("setBluetoothTethering(" + value + ")");
-        //TODO(BT
-        /*
         try {
-            mService.setBluetoothTethering(value);
+            mPanService.setBluetoothTethering(value);
         } catch (RemoteException e) {
             Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-        }*/
+        }
     }
 
     public boolean isTetheringOn() {
         if (DBG) log("isTetheringOn()");
-        //TODO(BT
-        /*
         try {
-            return mService.isTetheringOn();
+            return mPanService.isTetheringOn();
         } catch (RemoteException e) {
             Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-            return false;
-        }*/
+        }
         return false;
     }
 
+    private ServiceConnection mConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            if (DBG) Log.d(TAG, "BluetoothPAN Proxy object connected");
+            mPanService = IBluetoothPan.Stub.asInterface(service);
+
+            if (mServiceListener != null) {
+                mServiceListener.onServiceConnected(BluetoothProfile.PAN,
+                                                    BluetoothPan.this);
+            }
+        }
+        public void onServiceDisconnected(ComponentName className) {
+            if (DBG) Log.d(TAG, "BluetoothPAN Proxy object disconnected");
+            mPanService = null;
+            if (mServiceListener != null) {
+                mServiceListener.onServiceDisconnected(BluetoothProfile.PAN);
+            }
+        }
+    };
+
     private boolean isEnabled() {
        if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
        return false;
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 9b0e1cb..d37f2d5 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -102,7 +102,6 @@
     private int mPort;  /* RFCOMM channel or L2CAP psm */
     private int mFd;
     private String mServiceName;
-    private static IBluetooth sBluetoothProxy;
     private static int PROXY_CONNECTION_TIMEOUT = 5000;
 
     private static int SOCK_SIGNAL_SIZE = 16;
@@ -158,17 +157,6 @@
         }
         mInputStream = new BluetoothInputStream(this);
         mOutputStream = new BluetoothOutputStream(this);
-
-        if (sBluetoothProxy == null) {
-            synchronized (BluetoothSocket.class) {
-                if (sBluetoothProxy == null) {
-                    IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
-                    if (b == null)
-                        throw new RuntimeException("Bluetooth service not available");
-                    sBluetoothProxy = IBluetooth.Stub.asInterface(b);
-                }
-            }
-        }
     }
     private BluetoothSocket(BluetoothSocket s) {
         mUuid = s.mUuid;
@@ -297,8 +285,9 @@
         try {
             // TODO(BT) derive flag from auth and encrypt
             if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
-
-            mPfd = sBluetoothProxy.connectSocket(mDevice, mType,
+            IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
+            if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
+            mPfd = bluetoothProxy.connectSocket(mDevice, mType,
                     mUuid, mPort, getSecurityFlags());
             synchronized(this)
             {
@@ -333,8 +322,13 @@
     /*package*/ int bindListen() {
         int ret;
         if (mSocketState == SocketState.CLOSED) return EBADFD;
+        IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
+        if (bluetoothProxy == null) {
+            Log.e(TAG, "bindListen fail, reason: bluetooth is off");
+            return -1;
+        }
         try {
-            mPfd = sBluetoothProxy.createSocketChannel(mType, mServiceName,
+            mPfd = bluetoothProxy.createSocketChannel(mType, mServiceName,
                     mUuid, mPort, getSecurityFlags());
         } catch (RemoteException e) {
             Log.e(TAG, Log.getStackTraceString(new Throwable()));
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index 83d1bda..593b699 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -16,6 +16,9 @@
 
 package android.bluetooth;
 
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.os.INetworkManagementService;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.DhcpInfoInternal;
@@ -28,6 +31,11 @@
 import android.os.Handler;
 import android.os.Message;
 import android.util.Log;
+import java.net.InterfaceAddress;
+import android.net.LinkAddress;
+import android.net.RouteInfo;
+import java.net.Inet4Address;
+import android.os.SystemProperties;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -54,7 +62,6 @@
     private NetworkInfo mNetworkInfo;
 
     private BluetoothPan mBluetoothPan;
-    private BluetoothDevice mDevice;
     private static String mIface;
 
     /* For sending events to connectivity service handler */
@@ -92,8 +99,10 @@
      * Begin monitoring connectivity
      */
     public void startMonitoring(Context context, Handler target) {
+        Log.d(TAG, "startMonitoring: target: " + target);
         mContext = context;
         mCsHandler = target;
+        Log.d(TAG, "startMonitoring: mCsHandler: " + mCsHandler);
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
         if (adapter != null) {
             adapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.PAN);
@@ -259,38 +268,87 @@
         return "net.tcp.buffersize.wifi";
     }
 
+    private static short countPrefixLength(byte [] mask) {
+        short count = 0;
+        for (byte b : mask) {
+            for (int i = 0; i < 8; ++i) {
+                if ((b & (1 << i)) != 0) {
+                    ++count;
+                }
+            }
+        }
+        return count;
+    }
 
-    public synchronized void startReverseTether(String iface, BluetoothDevice device) {
+
+    private boolean readLinkProperty(String iface) {
+        String DhcpPrefix = "dhcp." + iface + ".";
+        String ip = SystemProperties.get(DhcpPrefix + "ipaddress");
+        String dns1 = SystemProperties.get(DhcpPrefix + "dns1");
+        String dns2 = SystemProperties.get(DhcpPrefix + "dns2");
+        String gateway = SystemProperties.get(DhcpPrefix + "gateway");
+        String mask = SystemProperties.get(DhcpPrefix + "mask");
+        if(ip.isEmpty() || gateway.isEmpty()) {
+            Log.e(TAG, "readLinkProperty, ip: " +  ip + ", gateway: " + gateway + ", can not be empty");
+            return false;
+        }
+        int PrefixLen = countPrefixLength(NetworkUtils.numericToInetAddress(mask).getAddress());
+        mLinkProperties.addLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress(ip), PrefixLen));
+        RouteInfo ri = new RouteInfo(NetworkUtils.numericToInetAddress(gateway));
+        mLinkProperties.addRoute(ri);
+        if(!dns1.isEmpty())
+            mLinkProperties.addDns(NetworkUtils.numericToInetAddress(dns1));
+        if(!dns2.isEmpty())
+            mLinkProperties.addDns(NetworkUtils.numericToInetAddress(dns2));
+        mLinkProperties.setInterfaceName(iface);
+        return true;
+    }
+    public synchronized void startReverseTether(String iface) {
         mIface = iface;
-        mDevice = device;
+        Log.d(TAG, "startReverseTether mCsHandler: " + mCsHandler);
         Thread dhcpThread = new Thread(new Runnable() {
             public void run() {
                 //TODO(): Add callbacks for failure and success case.
                 //Currently this thread runs independently.
-                DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
-                if (!NetworkUtils.runDhcp(mIface, dhcpInfoInternal)) {
-                    Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
-                    return;
+                Log.d(TAG, "startReverseTether mCsHandler: " + mCsHandler);
+                String DhcpResultName = "dhcp." + mIface + ".result";;
+                String result = "";
+                Log.d(TAG, "waiting for change of sys prop dhcp result: " + DhcpResultName);
+                for(int i = 0; i < 30*5; i++) {
+                    try { Thread.sleep(200); } catch (InterruptedException ie) { }
+                    result = SystemProperties.get(DhcpResultName);
+                    Log.d(TAG, "read " + DhcpResultName + ": " + result);
+                    if(result.equals("failed")) {
+                        Log.e(TAG, "startReverseTether, failed to start dhcp service");
+                        return;
+                    }
+                    if(result.equals("ok")) {
+                        Log.d(TAG, "startReverseTether, dhcp resut: " + result);
+                        if(readLinkProperty(mIface)) {
+
+                            mNetworkInfo.setIsAvailable(true);
+                            mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
+
+                            Log.d(TAG, "startReverseTether mCsHandler: " + mCsHandler);
+                            if(mCsHandler != null) {
+                                Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
+                                msg.sendToTarget();
+
+                                msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
+                                msg.sendToTarget();
+                            }
+                        }
+                        return;
+                    }
                 }
-                mLinkProperties = dhcpInfoInternal.makeLinkProperties();
-                mLinkProperties.setInterfaceName(mIface);
-
-                mNetworkInfo.setIsAvailable(true);
-                mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
-
-                Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
-                msg.sendToTarget();
-
-                msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
-                msg.sendToTarget();
+                Log.d(TAG, "startReverseTether, dhcp failed, resut: " + result);
             }
         });
         dhcpThread.start();
     }
 
-    public synchronized void stopReverseTether(String iface) {
-        NetworkUtils.stopDhcp(iface);
-
+    public synchronized void stopReverseTether() {
+        //NetworkUtils.stopDhcp(iface);
         mLinkProperties.clear();
         mNetworkInfo.setIsAvailable(false);
         mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
new file mode 100644
index 0000000..f82da82
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetooth;
+import android.bluetooth.IBluetoothManagerCallback;
+import android.bluetooth.IBluetoothStateChangeCallback;
+
+/**
+ * System private API for talking with the Bluetooth service.
+ *
+ * {@hide}
+ */
+interface IBluetoothManager
+{
+    IBluetooth registerAdapter(in IBluetoothManagerCallback callback);
+    void unregisterAdapter(in IBluetoothManagerCallback callback);
+    void registerStateChangeCallback(in IBluetoothStateChangeCallback callback);
+    void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
+    boolean isEnabled();
+    boolean enable();
+    boolean disable(boolean persist);
+
+    String getAddress();
+    String getName();
+}
diff --git a/core/java/android/bluetooth/IBluetoothManagerCallback.aidl b/core/java/android/bluetooth/IBluetoothManagerCallback.aidl
new file mode 100644
index 0000000..3e795ea
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothManagerCallback.aidl
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetooth;
+
+/**
+ * API for Communication between BluetoothAdapter and BluetoothManager
+ *
+ * {@hide}
+ */
+interface IBluetoothManagerCallback {
+    void onBluetoothServiceUp(in IBluetooth bluetoothService);
+    void onBluetoothServiceDown();
+}
\ No newline at end of file
diff --git a/core/java/android/bluetooth/IBluetoothPan.aidl b/core/java/android/bluetooth/IBluetoothPan.aidl
new file mode 100644
index 0000000..b91bd7d
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothPan.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ */
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * API for Bluetooth Pan service
+ *
+ * {@hide}
+ */
+interface IBluetoothPan {
+    // Public API
+    boolean isTetheringOn();
+    void setBluetoothTethering(boolean value);
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+}