Bluetooth: API change.

Split BluetoothDevice into BluetoothDevice and BluetoothAdapter.

BluetoothAdapter: Represents the local BT adapter. Operations on the local
                  adapter (start a scan, etc).
BluetoothDevice: Represents a remote BT device. Operations on remote devices
                 (pair, connect, etc).

IBluetoothDevice.aidl -> Bluetooth.aidl
BluetoothDeviceService.java -> BluetoothDeviceService.java

TODO:
Javadoc
diff --git a/Android.mk b/Android.mk
index a9caa20..2bc83b3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -88,8 +88,8 @@
 	core/java/android/backup/IBackupManager.aidl \
 	core/java/android/backup/IRestoreObserver.aidl \
 	core/java/android/backup/IRestoreSession.aidl \
+	core/java/android/bluetooth/IBluetooth.aidl \
 	core/java/android/bluetooth/IBluetoothA2dp.aidl \
-	core/java/android/bluetooth/IBluetoothDevice.aidl \
 	core/java/android/bluetooth/IBluetoothHeadset.aidl \
 	core/java/android/bluetooth/IBluetoothPbap.aidl \
 	core/java/android/content/IContentService.aidl \
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index a74fbe4..7c0d1d3 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -22,8 +22,8 @@
 
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.IBluetoothDevice;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.IBluetooth;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -158,8 +158,6 @@
     private static ConnectivityManager sConnectivityManager;
     private static WifiManager sWifiManager;
     private static LocationManager sLocationManager;
-    private static boolean sIsBluetoothDeviceCached = false;
-    private static BluetoothDevice sBluetoothDevice;
     private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs =
             new HashMap<File, SharedPreferencesImpl>();
 
@@ -184,6 +182,8 @@
     private StatusBarManager mStatusBarManager = null;
     private TelephonyManager mTelephonyManager = null;
     private ClipboardManager mClipboardManager = null;
+    private boolean mIsBluetoothAdapterCached = false;
+    private BluetoothAdapter mBluetoothAdapter;
     private boolean mRestricted;
 
     private final Object mSync = new Object();
@@ -830,7 +830,7 @@
         } else if (SENSOR_SERVICE.equals(name)) {
             return getSensorManager();
         } else if (BLUETOOTH_SERVICE.equals(name)) {
-            return getBluetoothDevice();
+            return getBluetoothAdapter();
         } else if (VIBRATOR_SERVICE.equals(name)) {
             return getVibrator();
         } else if (STATUS_BAR_SERVICE.equals(name)) {
@@ -980,21 +980,16 @@
         return mSearchManager;
     }
 
-    private BluetoothDevice getBluetoothDevice() {
-        if (sIsBluetoothDeviceCached) {
-            return sBluetoothDevice;
-        }
-        synchronized (sSync) {
+    private synchronized BluetoothAdapter getBluetoothAdapter() {
+        if (!mIsBluetoothAdapterCached) {
+            mIsBluetoothAdapterCached = true;
             IBinder b = ServiceManager.getService(BLUETOOTH_SERVICE);
-            if (b == null) {
-                sBluetoothDevice = null;
-            } else {
-                IBluetoothDevice service = IBluetoothDevice.Stub.asInterface(b);
-                sBluetoothDevice = new BluetoothDevice(service);
+            if (b != null) {
+                IBluetooth service = IBluetooth.Stub.asInterface(b);
+                mBluetoothAdapter = new BluetoothAdapter(service);
             }
-            sIsBluetoothDeviceCached = true;
         }
-        return sBluetoothDevice;
+        return mBluetoothAdapter;
     }
 
     private SensorManager getSensorManager() {
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 2ea45d5..6e48b66 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -25,7 +25,10 @@
 import android.os.IBinder;
 import android.util.Log;
 
-import java.util.List;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.HashSet;
 
 /**
  * Public API for controlling the Bluetooth A2DP Profile Service.
@@ -47,7 +50,7 @@
  *
  * @hide
  */
-public class BluetoothA2dp {
+public final class BluetoothA2dp {
     private static final String TAG = "BluetoothA2dp";
     private static final boolean DBG = false;
 
@@ -79,6 +82,7 @@
     /** Default priority for a2dp devices that should not allow incoming
      * connections */
     public static final int PRIORITY_OFF = 0;
+
     private final IBluetoothA2dp mService;
     private final Context mContext;
 
@@ -89,6 +93,7 @@
      */
     public BluetoothA2dp(Context c) {
         mContext = c;
+
         IBinder b = ServiceManager.getService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE);
         if (b == null) {
             throw new RuntimeException("Bluetooth A2DP service not available!");
@@ -99,14 +104,14 @@
     /** Initiate a connection to an A2DP sink.
      *  Listen for SINK_STATE_CHANGED_ACTION to find out when the
      *  connection is completed.
-     *  @param address Remote BT address.
+     *  @param device Remote BT device.
      *  @return Result code, negative indicates an immediate error.
      *  @hide
      */
-    public int connectSink(String address) {
-        if (DBG) log("connectSink(" + address + ")");
+    public int connectSink(BluetoothDevice device) {
+        if (DBG) log("connectSink(" + device + ")");
         try {
-            return mService.connectSink(address);
+            return mService.connectSink(device);
         } catch (RemoteException e) {
             Log.w(TAG, "", e);
             return BluetoothError.ERROR_IPC;
@@ -116,14 +121,14 @@
     /** Initiate disconnect from an A2DP sink.
      *  Listen for SINK_STATE_CHANGED_ACTION to find out when
      *  disconnect is completed.
-     *  @param address Remote BT address.
+     *  @param device Remote BT device.
      *  @return Result code, negative indicates an immediate error.
      *  @hide
      */
-    public int disconnectSink(String address) {
-        if (DBG) log("disconnectSink(" + address + ")");
+    public int disconnectSink(BluetoothDevice device) {
+        if (DBG) log("disconnectSink(" + device + ")");
         try {
-            return mService.disconnectSink(address);
+            return mService.disconnectSink(device);
         } catch (RemoteException e) {
             Log.w(TAG, "", e);
             return BluetoothError.ERROR_IPC;
@@ -131,24 +136,25 @@
     }
 
     /** Check if a specified A2DP sink is connected.
-     *  @param address Remote BT address.
+     *  @param device Remote BT device.
      *  @return True if connected (or playing), false otherwise and on error.
      *  @hide
      */
-    public boolean isSinkConnected(String address) {
-        if (DBG) log("isSinkConnected(" + address + ")");
-        int state = getSinkState(address);
+    public boolean isSinkConnected(BluetoothDevice device) {
+        if (DBG) log("isSinkConnected(" + device + ")");
+        int state = getSinkState(device);
         return state == STATE_CONNECTED || state == STATE_PLAYING;
     }
 
     /** Check if any A2DP sink is connected.
-     * @return a List of connected A2DP sinks, or null on error.
+     * @return a unmodifiable set of connected A2DP sinks, or null on error.
      * @hide
      */
-    public List<String> listConnectedSinks() {
-        if (DBG) log("listConnectedSinks()");
+    public Set<BluetoothDevice> getConnectedSinks() {
+        if (DBG) log("getConnectedSinks()");
         try {
-            return mService.listConnectedSinks();
+            return Collections.unmodifiableSet(
+                    new HashSet<BluetoothDevice>(Arrays.asList(mService.getConnectedSinks())));
         } catch (RemoteException e) {
             Log.w(TAG, "", e);
             return null;
@@ -156,14 +162,14 @@
     }
 
     /** Get the state of an A2DP sink
-     *  @param address Remote BT address.
+     *  @param device Remote BT device.
      *  @return State code, or negative on error
      *  @hide
      */
-    public int getSinkState(String address) {
-        if (DBG) log("getSinkState(" + address + ")");
+    public int getSinkState(BluetoothDevice device) {
+        if (DBG) log("getSinkState(" + device + ")");
         try {
-            return mService.getSinkState(address);
+            return mService.getSinkState(device);
         } catch (RemoteException e) {
             Log.w(TAG, "", e);
             return BluetoothError.ERROR_IPC;
@@ -177,15 +183,15 @@
      * Sinks with priority greater than zero will accept incoming connections
      * (if no sink is currently connected).
      * Priority for unpaired sink must be PRIORITY_NONE.
-     * @param address Paired sink
+     * @param device Paired sink
      * @param priority Integer priority, for example PRIORITY_AUTO or
      *                 PRIORITY_NONE
      * @return Result code, negative indicates an error
      */
-    public int setSinkPriority(String address, int priority) {
-        if (DBG) log("setSinkPriority(" + address + ", " + priority + ")");
+    public int setSinkPriority(BluetoothDevice device, int priority) {
+        if (DBG) log("setSinkPriority(" + device + ", " + priority + ")");
         try {
-            return mService.setSinkPriority(address, priority);
+            return mService.setSinkPriority(device, priority);
         } catch (RemoteException e) {
             Log.w(TAG, "", e);
             return BluetoothError.ERROR_IPC;
@@ -194,13 +200,13 @@
 
     /**
      * Get priority of a2dp sink.
-     * @param address Sink
+     * @param device Sink
      * @return non-negative priority, or negative error code on error.
      */
-    public int getSinkPriority(String address) {
-        if (DBG) log("getSinkPriority(" + address + ")");
+    public int getSinkPriority(BluetoothDevice device) {
+        if (DBG) log("getSinkPriority(" + device + ")");
         try {
-            return mService.getSinkPriority(address);
+            return mService.getSinkPriority(device);
         } catch (RemoteException e) {
             Log.w(TAG, "", e);
             return BluetoothError.ERROR_IPC;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
new file mode 100644
index 0000000..d207540
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * Represents the local Bluetooth adapter.
+ *
+ * @hide
+ */
+public final class BluetoothAdapter {
+    private static final String TAG = "BluetoothAdapter";
+
+    public static final int BLUETOOTH_STATE_OFF = 0;
+    public static final int BLUETOOTH_STATE_TURNING_ON = 1;
+    public static final int BLUETOOTH_STATE_ON = 2;
+    public static final int BLUETOOTH_STATE_TURNING_OFF = 3;
+
+    /** Inquiry scan and page scan are both off.
+     *  Device is neither discoverable nor connectable */
+    public static final int SCAN_MODE_NONE = 0;
+    /** Page scan is on, inquiry scan is off.
+     *  Device is connectable, but not discoverable */
+    public static final int SCAN_MODE_CONNECTABLE = 1;
+    /** Page scan and inquiry scan are on.
+     *  Device is connectable and discoverable */
+    public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3;
+
+    public static final int RESULT_FAILURE = -1;
+    public static final int RESULT_SUCCESS = 0;
+
+    /* The user will be prompted to enter a pin */
+    public static final int PAIRING_VARIANT_PIN = 0;
+    /* The user will be prompted to enter a passkey */
+    public static final int PAIRING_VARIANT_PASSKEY = 1;
+    /* The user will be prompted to confirm the passkey displayed on the screen */
+    public static final int PAIRING_VARIANT_CONFIRMATION = 2;
+
+    private final IBluetooth mService;
+
+    /**
+     * Do not use this constructor. Use Context.getSystemService() instead.
+     * @hide
+     */
+    public BluetoothAdapter(IBluetooth service) {
+        if (service == null) {
+            throw new IllegalArgumentException("service is null");
+        }
+        mService = service;
+    }
+
+    /**
+     * Get the remote BluetoothDevice associated with the given MAC address.
+     * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB".
+     * @param address valid Bluetooth MAC address
+     */
+    public BluetoothDevice getRemoteDevice(String address) {
+        return new BluetoothDevice(address);
+    }
+
+    /**
+     * Is Bluetooth currently turned on.
+     *
+     * @return true if Bluetooth enabled, false otherwise.
+     */
+    public boolean isEnabled() {
+        try {
+            return mService.isEnabled();
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
+    }
+
+    /**
+     * Get the current state of Bluetooth.
+     *
+     * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR.
+     */
+    public int getBluetoothState() {
+        try {
+            return mService.getBluetoothState();
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return BluetoothError.ERROR;
+    }
+
+    /**
+     * Enable the Bluetooth device.
+     * Turn on the underlying hardware.
+     * This is an asynchronous call,
+     * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if
+     * and when the device is sucessfully enabled.
+     * @return false if we cannot enable the Bluetooth device. True does not
+     * imply the device was enabled, it only implies that so far there were no
+     * problems.
+     */
+    public boolean enable() {
+        try {
+            return mService.enable();
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
+    }
+
+    /**
+     * Disable the Bluetooth device.
+     * This turns off the underlying hardware.
+     *
+     * @return true if successful, false otherwise.
+     */
+    public boolean disable() {
+        try {
+            return mService.disable(true);
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
+    }
+
+    public String getAddress() {
+        try {
+            return mService.getAddress();
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return null;
+    }
+
+    /**
+     * Get the friendly Bluetooth name of this device.
+     *
+     * This name is visible to remote Bluetooth devices. Currently it is only
+     * possible to retrieve the Bluetooth name when Bluetooth is enabled.
+     *
+     * @return the Bluetooth name, or null if there was a problem.
+     */
+    public String getName() {
+        try {
+            return mService.getName();
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return null;
+    }
+
+    /**
+     * Set the friendly Bluetooth name of this device.
+     *
+     * This name is visible to remote Bluetooth devices. The Bluetooth Service
+     * is responsible for persisting this name.
+     *
+     * @param name the name to set
+     * @return     true, if the name was successfully set. False otherwise.
+     */
+    public boolean setName(String name) {
+        try {
+            return mService.setName(name);
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
+    }
+
+    /**
+     * Get the current scan mode.
+     * Used to determine if the local device is connectable and/or discoverable
+     * @return Scan mode, one of SCAN_MODE_* or an error code
+     */
+    public int getScanMode() {
+        try {
+            return mService.getScanMode();
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return BluetoothError.ERROR_IPC;
+    }
+
+    /**
+     * Set the current scan mode.
+     * Used to make the local device connectable and/or discoverable
+     * @param scanMode One of SCAN_MODE_*
+     */
+    public void setScanMode(int scanMode) {
+        try {
+            mService.setScanMode(scanMode);
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+    }
+
+    public int getDiscoverableTimeout() {
+        try {
+            return mService.getDiscoverableTimeout();
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return -1;
+    }
+
+    public void setDiscoverableTimeout(int timeout) {
+        try {
+            mService.setDiscoverableTimeout(timeout);
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+    }
+
+    public boolean startDiscovery() {
+        try {
+            return mService.startDiscovery();
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
+    }
+
+    public void cancelDiscovery() {
+        try {
+            mService.cancelDiscovery();
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+    }
+
+    public boolean isDiscovering() {
+        try {
+            return mService.isDiscovering();
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
+    }
+
+    /**
+     * List remote devices that are bonded (paired) to the local adapter.
+     *
+     * Bonding (pairing) is the process by which the user enters a pin code for
+     * the device, which generates a shared link key, allowing for
+     * authentication and encryption of future connections. In Android we
+     * require bonding before RFCOMM or SCO connections can be made to a remote
+     * device.
+     *
+     * This function lists which remote devices we have a link key for. It does
+     * not cause any RF transmission, and does not check if the remote device
+     * still has it's link key with us. If the other side no longer has its
+     * link key then the RFCOMM or SCO connection attempt will result in an
+     * error.
+     *
+     * This function does not check if the remote device is in range.
+     *
+     * Remote devices that have an in-progress bonding attempt are not
+     * returned.
+     *
+     * @return unmodifiable set of bonded devices, or null on error
+     */
+    public Set<BluetoothDevice> getBondedDevices() {
+        try {
+            return toDeviceSet(mService.listBonds());
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return null;
+    }
+
+    /**
+     * Construct a listening, secure RFCOMM server socket.
+     * The remote device connecting to this socket will be authenticated and
+     * communication on this socket will be encrypted.
+     * Call #accept to retrieve connections to this socket.
+     * @return An RFCOMM BluetoothServerSocket
+     * @throws IOException On error, for example Bluetooth not available, or
+     *                     insufficient permissions.
+     */
+    public BluetoothServerSocket listenUsingRfcommOn(int port) throws IOException {
+        BluetoothServerSocket socket = new BluetoothServerSocket(
+                BluetoothSocket.TYPE_RFCOMM, true, true, port);
+        try {
+            socket.mSocket.bindListenNative();
+        } catch (IOException e) {
+            try {
+                socket.close();
+            } catch (IOException e2) { }
+            throw e;
+        }
+        return socket;
+    }
+
+    /**
+     * Construct an unencrypted, unauthenticated, RFCOMM server socket.
+     * Call #accept to retrieve connections to this socket.
+     * @return An RFCOMM BluetoothServerSocket
+     * @throws IOException On error, for example Bluetooth not available, or
+     *                     insufficient permissions.
+     */
+    public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
+        BluetoothServerSocket socket = new BluetoothServerSocket(
+                BluetoothSocket.TYPE_RFCOMM, false, false, port);
+        try {
+            socket.mSocket.bindListenNative();
+        } catch (IOException e) {
+            try {
+                socket.close();
+            } catch (IOException e2) { }
+            throw e;
+        }
+        return socket;
+    }
+
+    /**
+     * Construct a SCO server socket.
+     * Call #accept to retrieve connections to this socket.
+     * @return A SCO BluetoothServerSocket
+     * @throws IOException On error, for example Bluetooth not available, or
+     *                     insufficient permissions.
+     */
+    public static BluetoothServerSocket listenUsingScoOn() throws IOException {
+        BluetoothServerSocket socket = new BluetoothServerSocket(
+                BluetoothSocket.TYPE_SCO, false, false, -1);
+        try {
+            socket.mSocket.bindListenNative();
+        } catch (IOException e) {
+            try {
+                socket.close();
+            } catch (IOException e2) { }
+            throw e;
+        }
+        return socket;
+    }
+
+    private Set<BluetoothDevice> toDeviceSet(String[] addresses) {
+        Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(addresses.length);
+        for (int i = 0; i < addresses.length; i++) {
+            devices.add(getRemoteDevice(addresses[i]));
+        }
+        return Collections.unmodifiableSet(devices);
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothAudioGateway.java b/core/java/android/bluetooth/BluetoothAudioGateway.java
index f3afd2a..abd7723 100644
--- a/core/java/android/bluetooth/BluetoothAudioGateway.java
+++ b/core/java/android/bluetooth/BluetoothAudioGateway.java
@@ -9,24 +9,22 @@
 /**
  * Listen's for incoming RFCOMM connection for the headset / handsfree service.
  *
- * This class is planned for deletion, in favor of a generic Rfcomm class.
+ * TODO: Use the new generic BluetoothSocket class instead of this legacy code
  *
  * @hide
  */
-public class BluetoothAudioGateway {
+public final class BluetoothAudioGateway {
     private static final String TAG = "BT Audio Gateway";
     private static final boolean DBG = false;
 
     private int mNativeData;
     static { classInitNative(); }
 
-    private BluetoothDevice mBluetooth;
-
     /* in */
     private int mHandsfreeAgRfcommChannel = -1;
     private int mHeadsetAgRfcommChannel   = -1;
 
-    /* out */
+    /* out - written by native code */
     private String mConnectingHeadsetAddress;
     private int mConnectingHeadsetRfcommChannel; /* -1 when not connected */
     private int mConnectingHeadsetSocketFd;
@@ -35,17 +33,18 @@
     private int mConnectingHandsfreeSocketFd;
     private int mTimeoutRemainingMs; /* in/out */
 
+    private final BluetoothAdapter mAdapter;
+
     public static final int DEFAULT_HF_AG_CHANNEL = 10;
     public static final int DEFAULT_HS_AG_CHANNEL = 11;
 
-    public BluetoothAudioGateway(BluetoothDevice bluetooth) {
-        this(bluetooth, DEFAULT_HF_AG_CHANNEL, DEFAULT_HS_AG_CHANNEL);
+    public BluetoothAudioGateway(BluetoothAdapter adapter) {
+        this(adapter, DEFAULT_HF_AG_CHANNEL, DEFAULT_HS_AG_CHANNEL);
     }
 
-    public BluetoothAudioGateway(BluetoothDevice bluetooth,
-                                 int handsfreeAgRfcommChannel,
-                                 int headsetAgRfcommChannel) {
-        mBluetooth = bluetooth;
+    public BluetoothAudioGateway(BluetoothAdapter adapter, int handsfreeAgRfcommChannel,
+                int headsetAgRfcommChannel) {
+        mAdapter = adapter;
         mHandsfreeAgRfcommChannel = handsfreeAgRfcommChannel;
         mHeadsetAgRfcommChannel = headsetAgRfcommChannel;
         initializeNativeDataNative();
@@ -58,18 +57,17 @@
     private Handler mCallback;
 
     public class IncomingConnectionInfo {
-        IncomingConnectionInfo(BluetoothDevice bluetooth, String address, int socketFd,
-                               int rfcommChan) {
-            mBluetooth = bluetooth;
-            mAddress = address;
+        public BluetoothAdapter mAdapter;
+        public BluetoothDevice mRemoteDevice;
+        public int mSocketFd;
+        public int mRfcommChan;
+        IncomingConnectionInfo(BluetoothAdapter adapter, BluetoothDevice remoteDevice,
+                int socketFd, int rfcommChan) {
+            mAdapter = adapter;
+            mRemoteDevice = remoteDevice;
             mSocketFd = socketFd;
             mRfcommChan = rfcommChan;
         }
-
-        public BluetoothDevice mBluetooth;
-        public String mAddress;
-        public int mSocketFd;
-        public int mRfcommChan;
     }
 
     public static final int MSG_INCOMING_HEADSET_CONNECTION   = 100;
@@ -111,12 +109,11 @@
                                           mConnectingHeadsetRfcommChannel);
                                     Message msg = Message.obtain(mCallback);
                                     msg.what = MSG_INCOMING_HEADSET_CONNECTION;
-                                    msg.obj = 
-                                        new IncomingConnectionInfo(
-                                            mBluetooth, 
-                                            mConnectingHeadsetAddress,
-                                            mConnectingHeadsetSocketFd,
-                                            mConnectingHeadsetRfcommChannel);
+                                    msg.obj = new IncomingConnectionInfo(
+                                        mAdapter,
+                                        mAdapter.getRemoteDevice(mConnectingHeadsetAddress),
+                                        mConnectingHeadsetSocketFd,
+                                        mConnectingHeadsetRfcommChannel);
                                     msg.sendToTarget();
                                 }
                                 if (mConnectingHandsfreeRfcommChannel >= 0) {
@@ -126,12 +123,11 @@
                                     Message msg = Message.obtain();
                                     msg.setTarget(mCallback);
                                     msg.what = MSG_INCOMING_HANDSFREE_CONNECTION;
-                                    msg.obj = 
-                                        new IncomingConnectionInfo(
-                                            mBluetooth,
-                                            mConnectingHandsfreeAddress,
-                                            mConnectingHandsfreeSocketFd,
-                                            mConnectingHandsfreeRfcommChannel);
+                                    msg.obj = new IncomingConnectionInfo(
+                                        mAdapter,
+                                        mAdapter.getRemoteDevice(mConnectingHandsfreeAddress),
+                                        mConnectingHandsfreeSocketFd,
+                                        mConnectingHandsfreeRfcommChannel);
                                     msg.sendToTarget();
                                 }
                             }
diff --git a/core/java/android/bluetooth/BluetoothDevice.aidl b/core/java/android/bluetooth/BluetoothDevice.aidl
new file mode 100644
index 0000000..daae74d
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothDevice.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothDevice;
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index a64c6d72..27b2849 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2009 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,39 +16,25 @@
 
 package android.bluetooth;
 
+import android.content.Context;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
 
+import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 
 /**
- * The Android Bluetooth API is not finalized, and *will* change. Use at your
- * own risk.
+ * Represents a remote Bluetooth device.
  *
- * Manages the local Bluetooth device. Scan for devices, create bondings,
- * power up and down the adapter.
- *
+ * TODO: unhide
  * @hide
  */
-public class BluetoothDevice {
-
-    public static final int BLUETOOTH_STATE_OFF = 0;
-    public static final int BLUETOOTH_STATE_TURNING_ON = 1;
-    public static final int BLUETOOTH_STATE_ON = 2;
-    public static final int BLUETOOTH_STATE_TURNING_OFF = 3;
-
-    /** Inquiry scan and page scan are both off.
-     *  Device is neither discoverable nor connectable */
-    public static final int SCAN_MODE_NONE = 0;
-    /** Page scan is on, inquiry scan is off.
-     *  Device is connectable, but not discoverable */
-    public static final int SCAN_MODE_CONNECTABLE = 1;
-    /** Page scan and inquiry scan are on.
-     *  Device is connectable and discoverable */
-    public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3;
-
-    public static final int RESULT_FAILURE = -1;
-    public static final int RESULT_SUCCESS = 0;
+public final class BluetoothDevice implements Parcelable {
+    private static final String TAG = "BluetoothDevice";
 
     /** We do not have a link key for the remote device, and are therefore not
      * bonded */
@@ -81,84 +67,81 @@
     /* The user will be prompted to confirm the passkey displayed on the screen */
     public static final int PAIRING_VARIANT_CONFIRMATION = 2;
 
+    private static final int ADDRESS_LENGTH = 17;
 
-    private static final String TAG = "BluetoothDevice";
+    private static IBluetooth sService;  /* Guarenteed constant after first object constructed */
 
-    private final IBluetoothDevice mService;
+    private final String mAddress;
+
     /**
-     * @hide - hide this because it takes a parameter of type
-     * IBluetoothDevice, which is a System private class.
-     * Also note that Context.getSystemService is a factory that
-     * returns a BlueToothDevice. That is the right way to get
-     * a BluetoothDevice.
+     * Create a new BluetoothDevice
+     * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
+     * and is validated in this constructor.
+     * @param address valid Bluetooth MAC address
+     * @throws RuntimeException Bluetooth is not available on this platform
+     * @throws IllegalArgumentException address is invalid
+     * @hide
      */
-    public BluetoothDevice(IBluetoothDevice service) {
-        mService = service;
+    /*package*/ BluetoothDevice(String address) {
+        synchronized (BluetoothDevice.class) {
+            if (sService == null) {
+                IBinder b = ServiceManager.getService(Context.BLUETOOTH_SERVICE);
+                if (b == null) {
+                    throw new RuntimeException("Bluetooth service not available");
+                }
+                sService = IBluetooth.Stub.asInterface(b);
+            }
+        }
+
+        if (!checkBluetoothAddress(address)) {
+            throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
+        }
+
+        mAddress = address;
     }
 
-    /**
-     * Is Bluetooth currently turned on.
-     *
-     * @return true if Bluetooth enabled, false otherwise.
-     */
-    public boolean isEnabled() {
-        try {
-            return mService.isEnabled();
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof BluetoothDevice) {
+            return mAddress.equals(((BluetoothDevice)o).getAddress());
+        }
         return false;
     }
 
-    /**
-     * Get the current state of Bluetooth.
-     *
-     * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR.
-     */
-    public int getBluetoothState() {
-        try {
-            return mService.getBluetoothState();
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return BluetoothError.ERROR;
+    @Override
+    public int hashCode() {
+        return mAddress.hashCode();
     }
 
-    /**
-     * Enable the Bluetooth device.
-     * Turn on the underlying hardware.
-     * This is an asynchronous call,
-     * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if
-     * and when the device is sucessfully enabled.
-     * @return false if we cannot enable the Bluetooth device. True does not
-     * imply the device was enabled, it only implies that so far there were no
-     * problems.
-     */
-    public boolean enable() {
-        try {
-            return mService.enable();
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return false;
+    @Override
+    public String toString() {
+        return mAddress;
     }
 
-    /**
-     * Disable the Bluetooth device.
-     * This turns off the underlying hardware.
-     *
-     * @return true if successful, false otherwise.
-     */
-    public boolean disable() {
-        try {
-            return mService.disable(true);
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return false;
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<BluetoothDevice> CREATOR =
+            new Parcelable.Creator<BluetoothDevice>() {
+        public BluetoothDevice createFromParcel(Parcel in) {
+            return new BluetoothDevice(in.readString());
+        }
+        public BluetoothDevice[] newArray(int size) {
+            return new BluetoothDevice[size];
+        }
+    };
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mAddress);
     }
 
     public String getAddress() {
-        try {
-            return mService.getAddress();
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return null;
+        return mAddress;
     }
 
     /**
-     * Get the friendly Bluetooth name of this device.
+     * Get the friendly Bluetooth name of this remote device.
      *
      * This name is visible to remote Bluetooth devices. Currently it is only
      * possible to retrieve the Bluetooth name when Bluetooth is enabled.
@@ -167,98 +150,12 @@
      */
     public String getName() {
         try {
-            return mService.getName();
+            return sService.getRemoteName(mAddress);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return null;
     }
 
     /**
-     * Set the friendly Bluetooth name of this device.
-     *
-     * This name is visible to remote Bluetooth devices. The Bluetooth Service
-     * is responsible for persisting this name.
-     *
-     * @param name the name to set
-     * @return     true, if the name was successfully set. False otherwise.
-     */
-    public boolean setName(String name) {
-        try {
-            return mService.setName(name);
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return false;
-    }
-
-    /**
-     * Get the current scan mode.
-     * Used to determine if the local device is connectable and/or discoverable
-     * @return Scan mode, one of SCAN_MODE_* or an error code
-     */
-    public int getScanMode() {
-        try {
-            return mService.getScanMode();
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return BluetoothError.ERROR_IPC;
-    }
-
-    /**
-     * Set the current scan mode.
-     * Used to make the local device connectable and/or discoverable
-     * @param scanMode One of SCAN_MODE_*
-     */
-    public void setScanMode(int scanMode) {
-        try {
-            mService.setScanMode(scanMode);
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-    }
-
-    public int getDiscoverableTimeout() {
-        try {
-            return mService.getDiscoverableTimeout();
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return -1;
-    }
-    public void setDiscoverableTimeout(int timeout) {
-        try {
-            mService.setDiscoverableTimeout(timeout);
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-    }
-
-    public boolean startDiscovery() {
-        try {
-            return mService.startDiscovery();
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return false;
-    }
-
-    public void cancelDiscovery() {
-        try {
-            mService.cancelDiscovery();
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-    }
-
-    public boolean isDiscovering() {
-        try {
-            return mService.isDiscovering();
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return false;
-    }
-
-    /**
-     * Removes the remote device and the pairing information associated
-     * with it.
-     *
-     * @param address the Bluetooth hardware address you want to disconnect.
-     * @return true if the device was disconnected, false otherwise and on
-     *         error.
-     */
-    public boolean removeBond(String address) {
-        try {
-            return mService.removeBond(address);
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return false;
-    }
-
-    /**
      * Create a bonding with a remote bluetooth device.
      *
      * This is an asynchronous call. The result of this bonding attempt can be
@@ -268,9 +165,9 @@
      * @return false If there was an immediate problem creating the bonding,
      *         true otherwise.
      */
-    public boolean createBond(String address) {
+    public boolean createBond() {
         try {
-            return mService.createBond(address);
+            return sService.createBond(mAddress);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
@@ -278,41 +175,25 @@
     /**
      * Cancel an in-progress bonding request started with createBond.
      */
-    public boolean cancelBondProcess(String address) {
+    public boolean cancelBondProcess() {
         try {
-            return mService.cancelBondProcess(address);
+            return sService.cancelBondProcess(mAddress);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
 
     /**
-     * List remote devices that are bonded (paired) to the local device.
+     * Removes the remote device and the pairing information associated
+     * with it.
      *
-     * Bonding (pairing) is the process by which the user enters a pin code for
-     * the device, which generates a shared link key, allowing for
-     * authentication and encryption of future connections. In Android we
-     * require bonding before RFCOMM or SCO connections can be made to a remote
-     * device.
-     *
-     * This function lists which remote devices we have a link key for. It does
-     * not cause any RF transmission, and does not check if the remote device
-     * still has it's link key with us. If the other side no longer has its
-     * link key then the RFCOMM or SCO connection attempt will result in an
-     * error.
-     *
-     * This function does not check if the remote device is in range.
-     *
-     * Remote devices that have an in-progress bonding attempt are not
-     * returned.
-     *
-     * @return bluetooth hardware addresses of remote devices that are
-     *         bonded. Array size is 0 if no devices are bonded. Null on error.
+     * @return true if the device was disconnected, false otherwise and on
+     *         error.
      */
-    public String[] listBonds() {
+    public boolean removeBond() {
         try {
-            return mService.listBonds();
+            return sService.removeBond(mAddress);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return null;
+        return false;
     }
 
     /**
@@ -325,70 +206,103 @@
      * @param address Bluetooth hardware address of the remote device to check.
      * @return Result code
      */
-    public int getBondState(String address) {
+    public int getBondState() {
         try {
-            return mService.getBondState(address);
+            return sService.getBondState(mAddress);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return BluetoothError.ERROR_IPC;
     }
 
-    public String getRemoteName(String address) {
+    public int getBluetoothClass() {
         try {
-            return mService.getRemoteName(address);
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return null;
-    }
-
-    public int getRemoteClass(String address) {
-        try {
-            return mService.getRemoteClass(address);
+            return sService.getRemoteClass(mAddress);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return BluetoothError.ERROR_IPC;
     }
 
-     public String[] getRemoteUuids(String address) {
+     public String[] getUuids() {
         try {
-            return mService.getRemoteUuids(address);
+            return sService.getRemoteUuids(mAddress);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return null;
     }
 
-    public int getRemoteServiceChannel(String address, String uuid) {
+    public int getServiceChannel(String uuid) {
          try {
-             return mService.getRemoteServiceChannel(address, uuid);
+             return sService.getRemoteServiceChannel(mAddress, uuid);
          } catch (RemoteException e) {Log.e(TAG, "", e);}
          return BluetoothError.ERROR_IPC;
     }
 
-    public boolean setPin(String address, byte[] pin) {
+    public boolean setPin(byte[] pin) {
         try {
-            return mService.setPin(address, pin);
+            return sService.setPin(mAddress, pin);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
 
-    public boolean setPasskey(String address, int passkey) {
+    public boolean setPasskey(int passkey) {
         try {
-            return mService.setPasskey(address, passkey);
+            return sService.setPasskey(mAddress, passkey);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
 
-    public boolean setPairingConfirmation(String address, boolean confirm) {
+    public boolean setPairingConfirmation(boolean confirm) {
         try {
-            return mService.setPairingConfirmation(address, confirm);
+            return sService.setPairingConfirmation(mAddress, confirm);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
 
-    public boolean cancelPairingUserInput(String address) {
+    public boolean cancelPairingUserInput() {
         try {
-            return mService.cancelPairingUserInput(address);
+            return sService.cancelPairingUserInput(mAddress);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
 
     /**
+     * Construct a secure RFCOMM socket ready to start an outgoing connection.
+     * Call #connect on the returned #BluetoothSocket to begin the connection.
+     * The remote device will be authenticated and communication on this socket
+     * will be encrypted.
+     * @param port    remote port
+     * @return an RFCOMM BluetoothSocket
+     * @throws IOException on error, for example Bluetooth not available, or
+     *                     insufficient permissions.
+     */
+    public BluetoothSocket createRfcommSocket(int port) throws IOException {
+        return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, port);
+    }
+
+    /**
+     * Construct an insecure RFCOMM socket ready to start an outgoing
+     * connection.
+     * Call #connect on the returned #BluetoothSocket to begin the connection.
+     * The remote device will not be authenticated and communication on this
+     * socket will not be encrypted.
+     * @param port    remote port
+     * @return An RFCOMM BluetoothSocket
+     * @throws IOException On error, for example Bluetooth not available, or
+     *                     insufficient permissions.
+     */
+    public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
+        return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port);
+    }
+
+    /**
+     * Construct a SCO socket ready to start an outgoing connection.
+     * Call #connect on the returned #BluetoothSocket to begin the connection.
+     * @return a SCO BluetoothSocket
+     * @throws IOException on error, for example Bluetooth not available, or
+     *                     insufficient permissions.
+     */
+    public BluetoothSocket createScoSocket() throws IOException {
+        return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1);
+    }
+
+    /**
      * Check that a pin is valid and convert to byte array.
      *
      * Bluetooth pin's are 1 to 16 bytes of UTF8 characters.
@@ -413,7 +327,6 @@
         return pinBytes;
     }
 
-    private static final int ADDRESS_LENGTH = 17;
     /** Sanity check a bluetooth address, such as "00:43:A8:23:10:F0" */
     public static boolean checkBluetoothAddress(String address) {
         if (address == null || address.length() != ADDRESS_LENGTH) {
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index fe1e09a..0e3d2bb 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -49,7 +49,7 @@
  *
  * @hide
  */
-public class BluetoothHeadset {
+public final class BluetoothHeadset {
 
     private static final String TAG = "BluetoothHeadset";
     private static final boolean DBG = false;
@@ -163,16 +163,16 @@
     }
 
     /**
-     * Get the Bluetooth address of the current headset.
-     * @return The Bluetooth address, or null if not in connected or connecting
+     * Get the BluetoothDevice for the current headset.
+     * @return current headset, or null if not in connected or connecting
      *         state, or if this proxy object is not connected to the Headset
      *         service.
      */
-    public String getHeadsetAddress() {
-        if (DBG) log("getHeadsetAddress()");
+    public BluetoothDevice getCurrentHeadset() {
+        if (DBG) log("getCurrentHeadset()");
         if (mService != null) {
             try {
-                return mService.getHeadsetAddress();
+                return mService.getCurrentHeadset();
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
         } else {
             Log.w(TAG, "Proxy not attached to service");
@@ -185,19 +185,19 @@
      * Request to initiate a connection to a headset.
      * This call does not block. Fails if a headset is already connecting
      * or connected.
-     * Initiates auto-connection if address is null. Tries to connect to all
+     * Initiates auto-connection if device is null. Tries to connect to all
      * devices with priority greater than PRIORITY_AUTO in descending order.
-     * @param address The Bluetooth Address to connect to, or null to
-     *                auto-connect to the last connected headset.
-     * @return        False if there was a problem initiating the connection
-     *                procedure, and no further HEADSET_STATE_CHANGED intents
-     *                will be expected.
+     * @param device device to connect to, or null to auto-connect last connected
+     *               headset
+     * @return       false if there was a problem initiating the connection
+     *               procedure, and no further HEADSET_STATE_CHANGED intents
+     *               will be expected.
      */
-    public boolean connectHeadset(String address) {
-        if (DBG) log("connectHeadset(" + address + ")");
+    public boolean connectHeadset(BluetoothDevice device) {
+        if (DBG) log("connectHeadset(" + device + ")");
         if (mService != null) {
             try {
-                if (mService.connectHeadset(address)) {
+                if (mService.connectHeadset(device)) {
                     return true;
                 }
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
@@ -213,11 +213,11 @@
      * connecting). Returns false if not connected, or if this proxy object
      * if not currently connected to the headset service.
      */
-    public boolean isConnected(String address) {
-        if (DBG) log("isConnected(" + address + ")");
+    public boolean isConnected(BluetoothDevice device) {
+        if (DBG) log("isConnected(" + device + ")");
         if (mService != null) {
             try {
-                return mService.isConnected(address);
+                return mService.isConnected(device);
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
         } else {
             Log.w(TAG, "Proxy not attached to service");
@@ -295,16 +295,16 @@
      * auto-connected.
      * Incoming connections are ignored regardless of priority if there is
      * already a headset connected.
-     * @param address Paired headset
+     * @param device paired headset
      * @param priority Integer priority, for example PRIORITY_AUTO or
      *                 PRIORITY_NONE
-     * @return True if successful, false if there was some error.
+     * @return true if successful, false if there was some error
      */
-    public boolean setPriority(String address, int priority) {
-        if (DBG) log("setPriority(" + address + ", " + priority + ")");
+    public boolean setPriority(BluetoothDevice device, int priority) {
+        if (DBG) log("setPriority(" + device + ", " + priority + ")");
         if (mService != null) {
             try {
-                return mService.setPriority(address, priority);
+                return mService.setPriority(device, priority);
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
         } else {
             Log.w(TAG, "Proxy not attached to service");
@@ -315,14 +315,14 @@
 
     /**
      * Get priority of headset.
-     * @param address Headset
-     * @return non-negative priority, or negative error code on error.
+     * @param device headset
+     * @return non-negative priority, or negative error code on error
      */
-    public int getPriority(String address) {
-        if (DBG) log("getPriority(" + address + ")");
+    public int getPriority(BluetoothDevice device) {
+        if (DBG) log("getPriority(" + device + ")");
         if (mService != null) {
             try {
-                return mService.getPriority(address);
+                return mService.getPriority(device);
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
         } else {
             Log.w(TAG, "Proxy not attached to service");
diff --git a/core/java/android/bluetooth/BluetoothIntent.java b/core/java/android/bluetooth/BluetoothIntent.java
index d6c79b4..2a0de61 100644
--- a/core/java/android/bluetooth/BluetoothIntent.java
+++ b/core/java/android/bluetooth/BluetoothIntent.java
@@ -31,8 +31,8 @@
 public interface BluetoothIntent {
     public static final String SCAN_MODE =
         "android.bluetooth.intent.SCAN_MODE";
-    public static final String ADDRESS =
-        "android.bluetooth.intent.ADDRESS";
+    public static final String DEVICE =
+        "android.bluetooth.intent.DEVICE";
     public static final String NAME =
         "android.bluetooth.intent.NAME";
     public static final String ALIAS =
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index 5782644..645e241 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -73,11 +73,11 @@
 
     /** There was an error trying to obtain the state */
     public static final int STATE_ERROR        = -1;
-    /** No Pce currently connected */
+    /** No client currently connected */
     public static final int STATE_DISCONNECTED = 0;
     /** Connection attempt in progress */
     public static final int STATE_CONNECTING   = 1;
-    /** A Pce is currently connected */
+    /** Client is currently connected */
     public static final int STATE_CONNECTED    = 2;
 
     public static final int RESULT_FAILURE = 0;
@@ -159,16 +159,16 @@
     }
 
     /**
-     * Get the Bluetooth address of the current Pce.
-     * @return The Bluetooth address, or null if not in connected or connecting
-     *         state, or if this proxy object is not connected to the Pbap
-     *         service.
+     * Get the currently connected remote Bluetooth device (PCE).
+     * @return The remote Bluetooth device, or null if not in connected or
+     *         connecting state, or if this proxy object is not connected to
+     *         the Pbap service.
      */
-    public String getPceAddress() {
-        if (DBG) log("getPceAddress()");
+    public BluetoothDevice getClient() {
+        if (DBG) log("getClient()");
         if (mService != null) {
             try {
-                return mService.getPceAddress();
+                return mService.getClient();
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
         } else {
             Log.w(TAG, "Proxy not attached to service");
@@ -178,15 +178,15 @@
     }
 
     /**
-     * Returns true if the specified Pcs is connected (does not include
-     * connecting). Returns false if not connected, or if this proxy object
-     * if not currently connected to the Pbap service.
+     * Returns true if the specified Bluetooth device is connected (does not
+     * include connecting). Returns false if not connected, or if this proxy
+     * object is not currently connected to the Pbap service.
      */
-    public boolean isConnected(String address) {
-        if (DBG) log("isConnected(" + address + ")");
+    public boolean isConnected(BluetoothDevice device) {
+        if (DBG) log("isConnected(" + device + ")");
         if (mService != null) {
             try {
-                return mService.isConnected(address);
+                return mService.isConnected(device);
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
         } else {
             Log.w(TAG, "Proxy not attached to service");
@@ -196,15 +196,15 @@
     }
 
     /**
-     * Disconnects the current Pce. Currently this call blocks, it may soon
-     * be made asynchornous. Returns false if this proxy object is
+     * Disconnects the current Pbap client (PCE). Currently this call blocks,
+     * it may soon be made asynchornous. Returns false if this proxy object is
      * not currently connected to the Pbap service.
      */
-    public boolean disconnectPce() {
-        if (DBG) log("disconnectPce()");
+    public boolean disconnect() {
+        if (DBG) log("disconnect()");
         if (mService != null) {
             try {
-                mService.disconnectPce();
+                mService.disconnect();
                 return true;
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
         } else {
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index f3baeab..8be300b 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -33,72 +33,7 @@
  * @hide
  */
 public final class BluetoothServerSocket implements Closeable {
-    private final BluetoothSocket mSocket;
-
-    /**
-     * Construct a listening, secure RFCOMM server socket.
-     * The remote device connecting to this socket will be authenticated and
-     * communication on this socket will be encrypted.
-     * Call #accept to retrieve connections to this socket.
-     * @return An RFCOMM BluetoothServerSocket
-     * @throws IOException On error, for example Bluetooth not available, or
-     *                     insufficient permissions.
-     */
-    public static BluetoothServerSocket listenUsingRfcommOn(int port) throws IOException {
-        BluetoothServerSocket socket = new BluetoothServerSocket(
-                BluetoothSocket.TYPE_RFCOMM, true, true, port);
-        try {
-            socket.mSocket.bindListenNative();
-        } catch (IOException e) {
-            try {
-                socket.close();
-            } catch (IOException e2) { }
-            throw e;
-        }
-        return socket;
-    }
-
-    /**
-     * Construct an unencrypted, unauthenticated, RFCOMM server socket.
-     * Call #accept to retrieve connections to this socket.
-     * @return An RFCOMM BluetoothServerSocket
-     * @throws IOException On error, for example Bluetooth not available, or
-     *                     insufficient permissions.
-     */
-    public static BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
-        BluetoothServerSocket socket = new BluetoothServerSocket(
-                BluetoothSocket.TYPE_RFCOMM, false, false, port);
-        try {
-            socket.mSocket.bindListenNative();
-        } catch (IOException e) {
-            try {
-                socket.close();
-            } catch (IOException e2) { }
-            throw e;
-        }
-        return socket;
-    }
-
-    /**
-     * Construct a SCO server socket.
-     * Call #accept to retrieve connections to this socket.
-     * @return A SCO BluetoothServerSocket
-     * @throws IOException On error, for example Bluetooth not available, or
-     *                     insufficient permissions.
-     */
-    public static BluetoothServerSocket listenUsingScoOn() throws IOException {
-        BluetoothServerSocket socket = new BluetoothServerSocket(
-                BluetoothSocket.TYPE_SCO, false, false, -1);
-        try {
-            socket.mSocket.bindListenNative();
-        } catch (IOException e) {
-            try {
-                socket.close();
-            } catch (IOException e2) { }
-            throw e;
-        }
-        return socket;
-    }
+    /*package*/ final BluetoothSocket mSocket;
 
     /**
      * Construct a socket for incoming connections.
@@ -109,7 +44,7 @@
      * @throws IOException On error, for example Bluetooth not available, or
      *                     insufficient priveleges
      */
-    private BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port)
+    /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port)
             throws IOException {
         mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port);
     }
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index de1f326..dda2cef 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -42,6 +42,7 @@
 
     private final int mType;  /* one of TYPE_RFCOMM etc */
     private final int mPort;  /* RFCOMM channel or L2CAP psm */
+    private final BluetoothDevice mDevice;    /* remote device */
     private final String mAddress;    /* remote address */
     private final boolean mAuth;
     private final boolean mEncrypt;
@@ -51,68 +52,27 @@
     private int mSocketData;    /* used by native code only */
 
     /**
-     * Construct a secure RFCOMM socket ready to start an outgoing connection.
-     * Call #connect on the returned #BluetoothSocket to begin the connection.
-     * The remote device will be authenticated and communication on this socket
-     * will be encrypted.
-     * @param address remote Bluetooth address that this socket can connect to
-     * @param port    remote port
-     * @return an RFCOMM BluetoothSocket
-     * @throws IOException on error, for example Bluetooth not available, or
-     *                     insufficient permissions.
-     */
-    public static BluetoothSocket createRfcommSocket(String address, int port)
-            throws IOException {
-        return new BluetoothSocket(TYPE_RFCOMM, -1, true, true, address, port);
-    }
-
-    /**
-     * Construct an insecure RFCOMM socket ready to start an outgoing
-     * connection.
-     * Call #connect on the returned #BluetoothSocket to begin the connection.
-     * The remote device will not be authenticated and communication on this
-     * socket will not be encrypted.
-     * @param address remote Bluetooth address that this socket can connect to
-     * @param port    remote port
-     * @return An RFCOMM BluetoothSocket
-     * @throws IOException On error, for example Bluetooth not available, or
-     *                     insufficient permissions.
-     */
-    public static BluetoothSocket createInsecureRfcommSocket(String address, int port)
-            throws IOException {
-        return new BluetoothSocket(TYPE_RFCOMM, -1, false, false, address, port);
-    }
-
-    /**
-     * Construct a SCO socket ready to start an outgoing connection.
-     * Call #connect on the returned #BluetoothSocket to begin the connection.
-     * @param address remote Bluetooth address that this socket can connect to
-     * @return a SCO BluetoothSocket
-     * @throws IOException on error, for example Bluetooth not available, or
-     *                     insufficient permissions.
-     */
-    public static BluetoothSocket createScoSocket(String address, int port)
-            throws IOException {
-        return new BluetoothSocket(TYPE_SCO, -1, true, true, address, port);
-    }
-
-    /**
-     * Construct a Bluetooth.
+     * Construct a BluetoothSocket.
      * @param type    type of socket
      * @param fd      fd to use for connected socket, or -1 for a new socket
      * @param auth    require the remote device to be authenticated
      * @param encrypt require the connection to be encrypted
-     * @param address remote Bluetooth address that this socket can connect to
+     * @param device  remote device that this socket can connect to
      * @param port    remote port
      * @throws IOException On error, for example Bluetooth not available, or
      *                     insufficient priveleges
      */
-    /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address,
-            int port) throws IOException {
+    /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
+            BluetoothDevice device, int port) throws IOException {
         mType = type;
         mAuth = auth;
         mEncrypt = encrypt;
-        mAddress = address;
+        mDevice = device;
+        if (device == null) {
+            mAddress = null;
+        } else {
+            mAddress = device.getAddress();
+        }
         mPort = port;
         if (fd == -1) {
             initSocketNative();
@@ -123,6 +83,22 @@
         mOutputStream = new BluetoothOutputStream(this);
     }
 
+    /**
+     * Construct a BluetoothSocket from address.
+     * @param type    type of socket
+     * @param fd      fd to use for connected socket, or -1 for a new socket
+     * @param auth    require the remote device to be authenticated
+     * @param encrypt require the connection to be encrypted
+     * @param address remote device that this socket can connect to
+     * @param port    remote port
+     * @throws IOException On error, for example Bluetooth not available, or
+     *                     insufficient priveleges
+     */
+    private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address,
+            int port) throws IOException {
+        this(type, fd, auth, encrypt, new BluetoothDevice(address), port);
+    }
+
     @Override
     protected void finalize() throws Throwable {
         try {
@@ -154,12 +130,12 @@
     }
 
     /**
-     * Return the address we are connecting, or connected, to.
-     * @return Bluetooth address, or null if this socket has not yet attempted
+     * Return the remote device we are connecting, or connected, to.
+     * @return remote device, or null if this socket has not yet attempted
      *         or established a connection.
      */
-    public String getAddress() {
-        return mAddress;
+    public BluetoothDevice getRemoteDevice() {
+        return mDevice;
     }
 
     /**
diff --git a/core/java/android/bluetooth/HeadsetBase.java b/core/java/android/bluetooth/HeadsetBase.java
index f987ffd..29cf41d 100644
--- a/core/java/android/bluetooth/HeadsetBase.java
+++ b/core/java/android/bluetooth/HeadsetBase.java
@@ -31,7 +31,7 @@
  *
  * @hide
  */
-public class HeadsetBase {
+public final class HeadsetBase {
     private static final String TAG = "Bluetooth HeadsetBase";
     private static final boolean DBG = false;
 
@@ -42,8 +42,9 @@
 
     private static int sAtInputCount = 0;  /* TODO: Consider not using a static variable */
 
-    private final BluetoothDevice mBluetooth;
-    private final String mAddress;
+    private final BluetoothAdapter mAdapter;
+    private final BluetoothDevice mRemoteDevice;
+    private final String mAddress;  // for native code
     private final int mRfcommChannel;
     private int mNativeData;
     private Thread mEventThread;
@@ -73,12 +74,13 @@
 
     private native void cleanupNativeDataNative();
 
-    public HeadsetBase(PowerManager pm, BluetoothDevice bluetooth, String address,
-                       int rfcommChannel) {
+    public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, BluetoothDevice device,
+            int rfcommChannel) {
         mDirection = DIRECTION_OUTGOING;
         mConnectTimestamp = System.currentTimeMillis();
-        mBluetooth = bluetooth;
-        mAddress = address;
+        mAdapter = adapter;
+        mRemoteDevice = device;
+        mAddress = device.getAddress();
         mRfcommChannel = rfcommChannel;
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "HeadsetBase");
         mWakeLock.setReferenceCounted(false);
@@ -88,12 +90,13 @@
     }
 
     /* Create from an already exisiting rfcomm connection */
-    public HeadsetBase(PowerManager pm, BluetoothDevice bluetooth, String address, int socketFd,
-            int rfcommChannel, Handler handler) {
+    public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, BluetoothDevice device,
+            int socketFd, int rfcommChannel, Handler handler) {
         mDirection = DIRECTION_INCOMING;
         mConnectTimestamp = System.currentTimeMillis();
-        mBluetooth = bluetooth;
-        mAddress = address;
+        mAdapter = adapter;
+        mRemoteDevice = device;
+        mAddress = device.getAddress();
         mRfcommChannel = rfcommChannel;
         mEventThreadHandler = handler;
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "HeadsetBase");
@@ -252,12 +255,8 @@
         return mEventThread != null;
     }
 
-    public String getAddress() {
-        return mAddress;
-    }
-
-    public String getName() {
-        return mBluetooth.getRemoteName(mAddress);
+    public BluetoothDevice getRemoteDevice() {
+        return mRemoteDevice;
     }
 
     public int getDirection() {
diff --git a/core/java/android/bluetooth/IBluetoothDevice.aidl b/core/java/android/bluetooth/IBluetooth.aidl
similarity index 98%
rename from core/java/android/bluetooth/IBluetoothDevice.aidl
rename to core/java/android/bluetooth/IBluetooth.aidl
index a78752b..9e05a87 100644
--- a/core/java/android/bluetooth/IBluetoothDevice.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -21,7 +21,7 @@
  *
  * {@hide}
  */
-interface IBluetoothDevice
+interface IBluetooth
 {
     boolean isEnabled();
     int getBluetoothState();
diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl
index 55ff27f..e6c6be2 100644
--- a/core/java/android/bluetooth/IBluetoothA2dp.aidl
+++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl
@@ -16,16 +16,18 @@
 
 package android.bluetooth;
 
+import android.bluetooth.BluetoothDevice;
+
 /**
  * System private API for Bluetooth A2DP service
  *
  * {@hide}
  */
 interface IBluetoothA2dp {
-    int connectSink(in String address);
-    int disconnectSink(in String address);
-    List<String> listConnectedSinks();
-    int getSinkState(in String address);
-    int setSinkPriority(in String address, int priority);
-    int getSinkPriority(in String address);
+    int connectSink(in BluetoothDevice device);
+    int disconnectSink(in BluetoothDevice device);
+    BluetoothDevice[] getConnectedSinks();  // change to Set<> once AIDL supports
+    int getSinkState(in BluetoothDevice device);
+    int setSinkPriority(in BluetoothDevice device, int priority);
+    int getSinkPriority(in BluetoothDevice device);
 }
diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl
index 5f42fd6..6cccd50 100644
--- a/core/java/android/bluetooth/IBluetoothHeadset.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl
@@ -16,6 +16,8 @@
 
 package android.bluetooth;
 
+import android.bluetooth.BluetoothDevice;
+
 /**
  * System private API for Bluetooth Headset service
  *
@@ -23,13 +25,13 @@
  */
 interface IBluetoothHeadset {
     int getState();
-    String getHeadsetAddress();
-    boolean connectHeadset(in String address);
+    BluetoothDevice getCurrentHeadset();
+    boolean connectHeadset(in BluetoothDevice device);
     void disconnectHeadset();
-    boolean isConnected(in String address);
+    boolean isConnected(in BluetoothDevice device);
     boolean startVoiceRecognition();
     boolean stopVoiceRecognition();
-    boolean setPriority(in String address, int priority);
-    int getPriority(in String address);
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
     int getBatteryUsageHint();
 }
diff --git a/core/java/android/bluetooth/IBluetoothPbap.aidl b/core/java/android/bluetooth/IBluetoothPbap.aidl
index 06cdb7b..7cc77d1 100644
--- a/core/java/android/bluetooth/IBluetoothPbap.aidl
+++ b/core/java/android/bluetooth/IBluetoothPbap.aidl
@@ -16,6 +16,8 @@
 
 package android.bluetooth;
 
+import android.bluetooth.BluetoothDevice;
+
 /**
  * System private API for Bluetooth pbap service
  *
@@ -23,8 +25,8 @@
  */
 interface IBluetoothPbap {
     int getState();
-    String getPceAddress();
-    boolean connectPce(in String address);
-    void disconnectPce();
-    boolean isConnected(in String address);
+    BluetoothDevice getClient();
+    boolean connect(in BluetoothDevice device);
+    void disconnect();
+    boolean isConnected(in BluetoothDevice device);
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index dbe6fb0..8ab67c5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1144,10 +1144,10 @@
     public static final String SENSOR_SERVICE = "sensor";
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
-     * android.bluetooth.BluetoothDevice} for interacting with Bluetooth.
+     * android.bluetooth.BluetoothAdapter} for using Bluetooth.
      *
      * @see #getSystemService
-     * @see android.bluetooth.BluetoothDevice
+     * @see android.bluetooth.BluetoothAdapter
      * @hide
      */
     public static final String BLUETOOTH_SERVICE = "bluetooth";
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 96ce9d6..d9fcb53 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -23,6 +23,7 @@
 package android.server;
 
 import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothError;
 import android.bluetooth.BluetoothIntent;
@@ -40,9 +41,9 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
 import java.util.UUID;
 
 public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
@@ -67,26 +68,27 @@
 
     private static int mSinkCount;
 
-
     private final Context mContext;
     private final IntentFilter mIntentFilter;
-    private HashMap<String, Integer> mAudioDevices;
+    private HashMap<BluetoothDevice, Integer> mAudioDevices;
     private final AudioManager mAudioManager;
-    private final BluetoothDeviceService mBluetoothService;
+    private final BluetoothService mBluetoothService;
+    private final BluetoothAdapter mAdapter;
 
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
+            BluetoothDevice device =
+                    intent.getParcelableExtra(BluetoothIntent.DEVICE);
             if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
                 int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
                                                BluetoothError.ERROR);
                 switch (state) {
-                case BluetoothDevice.BLUETOOTH_STATE_ON:
+                case BluetoothAdapter.BLUETOOTH_STATE_ON:
                     onBluetoothEnable();
                     break;
-                case BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF:
+                case BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF:
                     onBluetoothDisable();
                     break;
                 }
@@ -95,28 +97,28 @@
                                                    BluetoothError.ERROR);
                 switch(bondState) {
                 case BluetoothDevice.BOND_BONDED:
-                    setSinkPriority(address, BluetoothA2dp.PRIORITY_AUTO);
+                    setSinkPriority(device, BluetoothA2dp.PRIORITY_AUTO);
                     break;
                 case BluetoothDevice.BOND_BONDING:
                 case BluetoothDevice.BOND_NOT_BONDED:
-                    setSinkPriority(address, BluetoothA2dp.PRIORITY_OFF);
+                    setSinkPriority(device, BluetoothA2dp.PRIORITY_OFF);
                     break;
                 }
             } else if (action.equals(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION)) {
-                if (getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF &&
-                        isSinkDevice(address)) {
+                if (getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF &&
+                        isSinkDevice(device)) {
                     // This device is a preferred sink. Make an A2DP connection
                     // after a delay. We delay to avoid connection collisions,
                     // and to give other profiles such as HFP a chance to
                     // connect first.
-                    Message msg = Message.obtain(mHandler, MESSAGE_CONNECT_TO, address);
+                    Message msg = Message.obtain(mHandler, MESSAGE_CONNECT_TO, device);
                     mHandler.sendMessageDelayed(msg, 6000);
                 }
             }
         }
     };
 
-    public BluetoothA2dpService(Context context, BluetoothDeviceService bluetoothService) {
+    public BluetoothA2dpService(Context context, BluetoothService bluetoothService) {
         mContext = context;
 
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
@@ -130,12 +132,14 @@
             throw new RuntimeException("Could not init BluetoothA2dpService");
         }
 
+        mAdapter = (BluetoothAdapter) context.getSystemService(Context.BLUETOOTH_SERVICE);
+
         mIntentFilter = new IntentFilter(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
         mIntentFilter.addAction(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
         mIntentFilter.addAction(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
         mContext.registerReceiver(mReceiver, mIntentFilter);
 
-        mAudioDevices = new HashMap<String, Integer>();
+        mAudioDevices = new HashMap<BluetoothDevice, Integer>();
 
         if (mBluetoothService.isEnabled())
             onBluetoothEnable();
@@ -155,18 +159,18 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
             case MESSAGE_CONNECT_TO:
-                String address = (String)msg.obj;
+                BluetoothDevice device = (BluetoothDevice) msg.obj;
                 // check bluetooth is still on, device is still preferred, and
                 // nothing is currently connected
                 if (mBluetoothService.isEnabled() &&
-                        getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF &&
+                        getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF &&
                         lookupSinksMatchingStates(new int[] {
                             BluetoothA2dp.STATE_CONNECTING,
                             BluetoothA2dp.STATE_CONNECTED,
                             BluetoothA2dp.STATE_PLAYING,
                             BluetoothA2dp.STATE_DISCONNECTING}).size() == 0) {
-                    log("Auto-connecting A2DP to sink " + address);
-                    connectSink(address);
+                    log("Auto-connecting A2DP to sink " + device);
+                    connectSink(device);
                 }
                 break;
             }
@@ -185,8 +189,8 @@
         return -1;
     }
 
-    private boolean isSinkDevice(String address) {
-        String uuids[] = mBluetoothService.getRemoteUuids(address);
+    private boolean isSinkDevice(BluetoothDevice device) {
+        String uuids[] = mBluetoothService.getRemoteUuids(device.getAddress());
         UUID uuid;
         if (uuids != null) {
             for (String deviceUuid: uuids) {
@@ -199,11 +203,11 @@
         return false;
     }
 
-    private synchronized boolean addAudioSink (String address) {
-        String path = mBluetoothService.getObjectPathFromAddress(address);
+    private synchronized boolean addAudioSink (BluetoothDevice device) {
+        String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
         String propValues[] = (String []) getSinkPropertiesNative(path);
         if (propValues == null) {
-            Log.e(TAG, "Error while getting AudioSink properties for device: " + address);
+            Log.e(TAG, "Error while getting AudioSink properties for device: " + device);
             return false;
         }
         Integer state = null;
@@ -214,8 +218,8 @@
                 break;
             }
         }
-        mAudioDevices.put(address, state);
-        handleSinkStateChange(address, BluetoothA2dp.STATE_DISCONNECTED, state);
+        mAudioDevices.put(device, state);
+        handleSinkStateChange(device, BluetoothA2dp.STATE_DISCONNECTED, state);
         return true;
     }
 
@@ -226,6 +230,7 @@
             String [] paths = devices.split(",");
             for (String path: paths) {
                 String address = mBluetoothService.getAddressFromObjectPath(path);
+                BluetoothDevice device = mAdapter.getRemoteDevice(address);
                 String []uuids = mBluetoothService.getRemoteUuids(address);
                 if (uuids != null)
                     for (String uuid: uuids) {
@@ -233,7 +238,7 @@
                         if (BluetoothUuid.isAudioSink(remoteUuid) ||
                             BluetoothUuid.isAudioSource(remoteUuid) ||
                             BluetoothUuid.isAdvAudioDist(remoteUuid)) {
-                            addAudioSink(address);
+                            addAudioSink(device);
                             break;
                         }
                     }
@@ -244,36 +249,34 @@
 
     private synchronized void onBluetoothDisable() {
         if (!mAudioDevices.isEmpty()) {
-            String [] addresses = new String[mAudioDevices.size()];
-            addresses = mAudioDevices.keySet().toArray(addresses);
-            for (String address : addresses) {
-                int state = getSinkState(address);
+            BluetoothDevice[] devices = new BluetoothDevice[mAudioDevices.size()];
+            devices = mAudioDevices.keySet().toArray(devices);
+            for (BluetoothDevice device : devices) {
+                int state = getSinkState(device);
                 switch (state) {
                     case BluetoothA2dp.STATE_CONNECTING:
                     case BluetoothA2dp.STATE_CONNECTED:
                     case BluetoothA2dp.STATE_PLAYING:
-                        disconnectSinkNative(mBluetoothService.getObjectPathFromAddress(address));
-                        handleSinkStateChange(address,state, BluetoothA2dp.STATE_DISCONNECTED);
+                        disconnectSinkNative(mBluetoothService.getObjectPathFromAddress(
+                                device.getAddress()));
+                        handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTED);
                         break;
                     case BluetoothA2dp.STATE_DISCONNECTING:
-                        handleSinkStateChange(address, BluetoothA2dp.STATE_DISCONNECTING,
-                                                BluetoothA2dp.STATE_DISCONNECTED);
+                        handleSinkStateChange(device, BluetoothA2dp.STATE_DISCONNECTING,
+                                              BluetoothA2dp.STATE_DISCONNECTED);
                         break;
                 }
             }
             mAudioDevices.clear();
         }
 
-        mAudioManager.setParameters(BLUETOOTH_ENABLED+"=false");
+        mAudioManager.setParameters(BLUETOOTH_ENABLED + "=false");
     }
 
-    public synchronized int connectSink(String address) {
+    public synchronized int connectSink(BluetoothDevice device) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
-        if (DBG) log("connectSink(" + address + ")");
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
-            return BluetoothError.ERROR;
-        }
+        if (DBG) log("connectSink(" + device + ")");
 
         // ignore if there are any active sinks
         if (lookupSinksMatchingStates(new int[] {
@@ -284,10 +287,10 @@
             return BluetoothError.ERROR;
         }
 
-        if (mAudioDevices.get(address) == null && !addAudioSink(address))
+        if (mAudioDevices.get(device) == null && !addAudioSink(device))
             return BluetoothError.ERROR;
 
-        int state = mAudioDevices.get(address);
+        int state = mAudioDevices.get(device);
 
         switch (state) {
         case BluetoothA2dp.STATE_CONNECTED:
@@ -298,7 +301,7 @@
             return BluetoothError.SUCCESS;
         }
 
-        String path = mBluetoothService.getObjectPathFromAddress(address);
+        String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
         if (path == null)
             return BluetoothError.ERROR;
 
@@ -309,19 +312,17 @@
         return BluetoothError.SUCCESS;
     }
 
-    public synchronized int disconnectSink(String address) {
+    public synchronized int disconnectSink(BluetoothDevice device) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
-        if (DBG) log("disconnectSink(" + address + ")");
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
-            return BluetoothError.ERROR;
-        }
-        String path = mBluetoothService.getObjectPathFromAddress(address);
+        if (DBG) log("disconnectSink(" + device + ")");
+
+        String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
         if (path == null) {
             return BluetoothError.ERROR;
         }
 
-        switch (getSinkState(address)) {
+        switch (getSinkState(device)) {
         case BluetoothA2dp.STATE_DISCONNECTED:
             return BluetoothError.ERROR;
         case BluetoothA2dp.STATE_DISCONNECTING:
@@ -336,41 +337,36 @@
         }
     }
 
-    public synchronized List<String> listConnectedSinks() {
+    public synchronized BluetoothDevice[] getConnectedSinks() {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        return lookupSinksMatchingStates(new int[] {BluetoothA2dp.STATE_CONNECTED,
-                                                    BluetoothA2dp.STATE_PLAYING});
+        Set<BluetoothDevice> sinks = lookupSinksMatchingStates(
+                new int[] {BluetoothA2dp.STATE_CONNECTED, BluetoothA2dp.STATE_PLAYING});
+        return sinks.toArray(new BluetoothDevice[sinks.size()]);
     }
 
-    public synchronized int getSinkState(String address) {
+    public synchronized int getSinkState(BluetoothDevice device) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
-            return BluetoothError.ERROR;
-        }
-        Integer state = mAudioDevices.get(address);
+        Integer state = mAudioDevices.get(device);
         if (state == null)
             return BluetoothA2dp.STATE_DISCONNECTED;
         return state;
     }
 
-    public synchronized int getSinkPriority(String address) {
+    public synchronized int getSinkPriority(BluetoothDevice device) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
-            return BluetoothError.ERROR;
-        }
         return Settings.Secure.getInt(mContext.getContentResolver(),
-                Settings.Secure.getBluetoothA2dpSinkPriorityKey(address),
+                Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()),
                 BluetoothA2dp.PRIORITY_OFF);
     }
 
-    public synchronized int setSinkPriority(String address, int priority) {
+    public synchronized int setSinkPriority(BluetoothDevice device, int priority) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+        if (!BluetoothDevice.checkBluetoothAddress(device.getAddress())) {
             return BluetoothError.ERROR;
         }
         return Settings.Secure.putInt(mContext.getContentResolver(),
-                Settings.Secure.getBluetoothA2dpSinkPriorityKey(address), priority) ?
+                Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()), priority) ?
                 BluetoothError.SUCCESS : BluetoothError.ERROR;
     }
 
@@ -386,20 +382,22 @@
             return;
         }
 
+        BluetoothDevice device = mAdapter.getRemoteDevice(address);
+
         if (name.equals(PROPERTY_STATE)) {
             int state = convertBluezSinkStringtoState(propValues[1]);
-            if (mAudioDevices.get(address) == null) {
+            if (mAudioDevices.get(device) == null) {
                 // This is for an incoming connection for a device not known to us.
                 // We have authorized it and bluez state has changed.
-                addAudioSink(address);
+                addAudioSink(device);
             } else {
-                int prevState = mAudioDevices.get(address);
-                handleSinkStateChange(address, prevState, state);
+                int prevState = mAudioDevices.get(device);
+                handleSinkStateChange(device, prevState, state);
             }
         }
     }
 
-    private void handleSinkStateChange(String address, int prevState, int state) {
+    private void handleSinkStateChange(BluetoothDevice device, int prevState, int state) {
         if (state != prevState) {
             if (state == BluetoothA2dp.STATE_DISCONNECTED ||
                     state == BluetoothA2dp.STATE_DISCONNECTING) {
@@ -413,28 +411,28 @@
             } else if (state == BluetoothA2dp.STATE_CONNECTED) {
                 mSinkCount ++;
             }
-            mAudioDevices.put(address, state);
+            mAudioDevices.put(device, state);
 
             Intent intent = new Intent(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
-            intent.putExtra(BluetoothIntent.ADDRESS, address);
+            intent.putExtra(BluetoothIntent.DEVICE, device);
             intent.putExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, prevState);
             intent.putExtra(BluetoothA2dp.SINK_STATE, state);
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
 
-            if (DBG) log("A2DP state : address: " + address + " State:" + prevState + "->" + state);
+            if (DBG) log("A2DP state : device: " + device + " State:" + prevState + "->" + state);
         }
     }
 
-    private synchronized List<String> lookupSinksMatchingStates(int[] states) {
-        List<String> sinks = new ArrayList<String>();
+    private synchronized Set<BluetoothDevice> lookupSinksMatchingStates(int[] states) {
+        Set<BluetoothDevice> sinks = new HashSet<BluetoothDevice>();
         if (mAudioDevices.isEmpty()) {
             return sinks;
         }
-        for (String path: mAudioDevices.keySet()) {
-            int sinkState = getSinkState(path);
+        for (BluetoothDevice device: mAudioDevices.keySet()) {
+            int sinkState = getSinkState(device);
             for (int state : states) {
                 if (state == sinkState) {
-                    sinks.add(path);
+                    sinks.add(device);
                     break;
                 }
             }
@@ -446,9 +444,9 @@
     protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mAudioDevices.isEmpty()) return;
         pw.println("Cached audio devices:");
-        for (String address : mAudioDevices.keySet()) {
-            int state = mAudioDevices.get(address);
-            pw.println(address + " " + BluetoothA2dp.stateToString(state));
+        for (BluetoothDevice device : mAudioDevices.keySet()) {
+            int state = mAudioDevices.get(device);
+            pw.println(device + " " + BluetoothA2dp.stateToString(state));
         }
     }
 
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 1704733..6610d0e 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -18,6 +18,7 @@
 
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothError;
 import android.bluetooth.BluetoothIntent;
@@ -46,8 +47,10 @@
     private Thread mThread;
     private boolean mStarted;
     private boolean mInterrupted;
+
     private final HashMap<String, Integer> mPasskeyAgentRequestData;
-    private final BluetoothDeviceService mBluetoothService;
+    private final BluetoothService mBluetoothService;
+    private final BluetoothAdapter mAdapter;
     private final Context mContext;
 
     private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1;
@@ -84,10 +87,12 @@
     static { classInitNative(); }
     private static native void classInitNative();
 
-    /* pacakge */ BluetoothEventLoop(Context context, BluetoothDeviceService bluetoothService) {
+    /* pacakge */ BluetoothEventLoop(Context context, BluetoothAdapter adapter,
+            BluetoothService bluetoothService) {
         mBluetoothService = bluetoothService;
         mContext = context;
         mPasskeyAgentRequestData = new HashMap();
+        mAdapter = adapter;
         initializeNativeDataNative();
     }
 
@@ -137,7 +142,7 @@
         }
         if (classValue != null) {
             Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION);
-            intent.putExtra(BluetoothIntent.ADDRESS, address);
+            intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
             intent.putExtra(BluetoothIntent.CLASS, Integer.valueOf(classValue));
             intent.putExtra(BluetoothIntent.RSSI, rssiValue);
             intent.putExtra(BluetoothIntent.NAME, name);
@@ -158,7 +163,7 @@
 
     private void onDeviceDisappeared(String address) {
         Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION);
-        intent.putExtra(BluetoothIntent.ADDRESS, address);
+        intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
         mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
 
@@ -251,7 +256,7 @@
             if (pairable == null || discoverable == null)
                 return;
 
-            int mode = BluetoothDeviceService.bluezStringToScanMode(
+            int mode = BluetoothService.bluezStringToScanMode(
                     pairable.equals("true"),
                     discoverable.equals("true"));
             if (mode >= 0) {
@@ -299,15 +304,16 @@
             Log.e(TAG, "onDevicePropertyChanged: Address of the remote device in null");
             return;
         }
+        BluetoothDevice device = mAdapter.getRemoteDevice(address);
         if (name.equals("Name")) {
             Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
-            intent.putExtra(BluetoothIntent.ADDRESS, address);
+            intent.putExtra(BluetoothIntent.DEVICE, device);
             intent.putExtra(BluetoothIntent.NAME, propValues[1]);
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
             mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
         } else if (name.equals("Class")) {
             Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION);
-            intent.putExtra(BluetoothIntent.ADDRESS, address);
+            intent.putExtra(BluetoothIntent.DEVICE, device);
             intent.putExtra(BluetoothIntent.CLASS, propValues[1]);
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
             mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
@@ -318,7 +324,7 @@
             } else {
                 intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION);
             }
-            intent.putExtra(BluetoothIntent.ADDRESS, address);
+            intent.putExtra(BluetoothIntent.DEVICE, device);
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
             mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
         } else if (name.equals("UUIDs")) {
@@ -351,7 +357,7 @@
         address = address.toUpperCase();
         mPasskeyAgentRequestData.put(address, new Integer(nativeData));
 
-        if (mBluetoothService.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF) {
+        if (mBluetoothService.getBluetoothState() == BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF) {
             // shutdown path
             mBluetoothService.cancelPairingUserInput(address);
             return null;
@@ -364,7 +370,7 @@
         if (address == null) return;
 
         Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
-        intent.putExtra(BluetoothIntent.ADDRESS, address);
+        intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
         intent.putExtra(BluetoothIntent.PASSKEY, passkey);
         intent.putExtra(BluetoothIntent.PAIRING_VARIANT,
                 BluetoothDevice.PAIRING_VARIANT_CONFIRMATION);
@@ -377,7 +383,7 @@
         if (address == null) return;
 
         Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
-        intent.putExtra(BluetoothIntent.ADDRESS, address);
+        intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
         intent.putExtra(BluetoothIntent.PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PASSKEY);
         mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
         return;
@@ -409,7 +415,7 @@
            }
         }
         Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
-        intent.putExtra(BluetoothIntent.ADDRESS, address);
+        intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
         intent.putExtra(BluetoothIntent.PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN);
         mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
         return;
@@ -428,7 +434,8 @@
                 (BluetoothUuid.isAudioSink(uuid) || BluetoothUuid.isAvrcpController(uuid)
                         || BluetoothUuid.isAdvAudioDist(uuid))) {
             BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
-            authorized = a2dp.getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF;
+            BluetoothDevice device = mAdapter.getRemoteDevice(address);
+            authorized = a2dp.getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF;
             if (authorized) {
                 Log.i(TAG, "Allowing incoming A2DP / AVRCP connection from " + address);
             } else {
diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothService.java
similarity index 92%
rename from core/java/android/server/BluetoothDeviceService.java
rename to core/java/android/server/BluetoothService.java
index d2b4447..acee3af 100644
--- a/core/java/android/server/BluetoothDeviceService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -16,7 +16,7 @@
 
 /**
  * TODO: Move this to
- * java/services/com/android/server/BluetoothDeviceService.java
+ * java/services/com/android/server/BluetoothService.java
  * and make the contructor package private again.
  *
  * @hide
@@ -25,11 +25,12 @@
 package android.server;
 
 import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothError;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothIntent;
-import android.bluetooth.IBluetoothDevice;
+import android.bluetooth.IBluetooth;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -55,8 +56,8 @@
 import java.util.Iterator;
 import java.util.Map;
 
-public class BluetoothDeviceService extends IBluetoothDevice.Stub {
-    private static final String TAG = "BluetoothDeviceService";
+public class BluetoothService extends IBluetooth.Stub {
+    private static final String TAG = "BluetoothService";
     private static final boolean DBG = true;
 
     private int mNativeData;
@@ -65,11 +66,11 @@
     private boolean mIsAirplaneSensitive;
     private int mBluetoothState;
     private boolean mRestart = false;  // need to call enable() after disable()
-
-    private final BondState mBondState = new BondState();  // local cache of bondings
     private boolean mIsDiscovering;
-    private final IBatteryStats mBatteryStats;
 
+    private BluetoothAdapter mAdapter;  // constant after init()
+    private final BondState mBondState = new BondState();  // local cache of bondings
+    private final IBatteryStats mBatteryStats;
     private final Context mContext;
 
     private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
@@ -78,14 +79,14 @@
     private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
     private static final int MESSAGE_FINISH_DISABLE = 2;
 
-    private Map<String, String> mProperties;
-    private HashMap <String, Map<String, String>> mRemoteDeviceProperties;
+    private final Map<String, String> mAdapterProperties;
+    private final HashMap <String, Map<String, String>> mDeviceProperties;
 
     static {
         classInitNative();
     }
 
-    public BluetoothDeviceService(Context context) {
+    public BluetoothService(Context context) {
         mContext = context;
 
         // Need to do this in place of:
@@ -93,11 +94,7 @@
         // Since we can not import BatteryStatsService from here. This class really needs to be
         // moved to java/services/com/android/server/
         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
-    }
 
-    /** Must be called after construction, and before any other method.
-     */
-    public synchronized void init() {
         initializeNativeDataNative();
 
         if (isEnabledNative() == 1) {
@@ -105,12 +102,16 @@
             disableNative();
         }
 
-        setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_OFF);
+        mBluetoothState = BluetoothAdapter.BLUETOOTH_STATE_OFF;
         mIsDiscovering = false;
-        mEventLoop = new BluetoothEventLoop(mContext, this);
+        mAdapterProperties = new HashMap<String, String>();
+        mDeviceProperties = new HashMap<String, Map<String,String>>();
         registerForAirplaneMode();
-        mProperties = new HashMap<String, String>();
-        mRemoteDeviceProperties = new HashMap<String, Map<String,String>>();
+    }
+
+    public synchronized void initAfterRegistration() {
+        mAdapter = (BluetoothAdapter) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
+        mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this);
     }
 
     @Override
@@ -127,7 +128,7 @@
 
     public boolean isEnabled() {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        return mBluetoothState == BluetoothDevice.BLUETOOTH_STATE_ON;
+        return mBluetoothState == BluetoothAdapter.BLUETOOTH_STATE_ON;
     }
 
     public int getBluetoothState() {
@@ -152,9 +153,9 @@
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
 
         switch (mBluetoothState) {
-        case BluetoothDevice.BLUETOOTH_STATE_OFF:
+        case BluetoothAdapter.BLUETOOTH_STATE_OFF:
             return true;
-        case BluetoothDevice.BLUETOOTH_STATE_ON:
+        case BluetoothAdapter.BLUETOOTH_STATE_ON:
             break;
         default:
             return false;
@@ -162,11 +163,11 @@
         if (mEnableThread != null && mEnableThread.isAlive()) {
             return false;
         }
-        setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF);
+        setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF);
 
         // Allow 3 seconds for profiles to gracefully disconnect
         // TODO: Introduce a callback mechanism so that each profile can notify
-        // BluetoothDeviceService when it is done shutting down
+        // BluetoothService when it is done shutting down
         mHandler.sendMessageDelayed(
                 mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
         return true;
@@ -174,7 +175,7 @@
 
 
     private synchronized void finishDisable(boolean saveSetting) {
-        if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF) {
+        if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF) {
             return;
         }
         mEventLoop.stop();
@@ -189,17 +190,17 @@
 
         // update mode
         Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION);
-        intent.putExtra(BluetoothIntent.SCAN_MODE, BluetoothDevice.SCAN_MODE_NONE);
+        intent.putExtra(BluetoothIntent.SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
         mContext.sendBroadcast(intent, BLUETOOTH_PERM);
 
         mIsDiscovering = false;
-        mProperties.clear();
+        mAdapterProperties.clear();
 
         if (saveSetting) {
             persistBluetoothOnSetting(false);
         }
 
-        setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_OFF);
+        setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_OFF);
 
         // Log bluetooth off to battery stats.
         long ident = Binder.clearCallingIdentity();
@@ -236,13 +237,13 @@
         if (mIsAirplaneSensitive && isAirplaneModeOn()) {
             return false;
         }
-        if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_OFF) {
+        if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_OFF) {
             return false;
         }
         if (mEnableThread != null && mEnableThread.isAlive()) {
             return false;
         }
-        setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_TURNING_ON);
+        setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON);
         mEnableThread = new EnableThread(saveSetting);
         mEnableThread.start();
         return true;
@@ -250,7 +251,7 @@
 
     /** Forcibly restart Bluetooth if it is on */
     /* package */ synchronized void restart() {
-        if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_ON) {
+        if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_ON) {
             return;
         }
         mRestart = true;
@@ -356,8 +357,8 @@
             mEnableThread = null;
 
             setBluetoothState(res ?
-                              BluetoothDevice.BLUETOOTH_STATE_ON :
-                              BluetoothDevice.BLUETOOTH_STATE_OFF);
+                              BluetoothAdapter.BLUETOOTH_STATE_ON :
+                              BluetoothAdapter.BLUETOOTH_STATE_OFF);
 
             if (res) {
                 // Update mode
@@ -410,7 +411,7 @@
                         ));
 
         public synchronized void loadBondState() {
-            if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_TURNING_ON) {
+            if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON) {
                 return;
             }
             String []bonds = null;
@@ -442,7 +443,7 @@
             if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
                          reason + ")");
             Intent intent = new Intent(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
-            intent.putExtra(BluetoothIntent.ADDRESS, address);
+            intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
             intent.putExtra(BluetoothIntent.BOND_STATE, state);
             intent.putExtra(BluetoothIntent.BOND_PREVIOUS_STATE, oldState);
             if (state == BluetoothDevice.BOND_NOT_BONDED) {
@@ -539,7 +540,7 @@
 
     /*package*/synchronized void getAllProperties() {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        mProperties.clear();
+        mAdapterProperties.clear();
 
         String properties[] = (String [])getAdapterPropertiesNative();
         // The String Array consists of key-value pairs.
@@ -568,17 +569,17 @@
             } else {
                 newValue = properties[++i];
             }
-            mProperties.put(name, newValue);
+            mAdapterProperties.put(name, newValue);
         }
 
         // Add adapter object path property.
         String adapterPath = getAdapterPathNative();
         if (adapterPath != null)
-            mProperties.put("ObjectPath", adapterPath + "/dev_");
+            mAdapterProperties.put("ObjectPath", adapterPath + "/dev_");
     }
 
     /* package */ synchronized void setProperty(String name, String value) {
-        mProperties.put(name, value);
+        mAdapterProperties.put(name, value);
     }
 
     public synchronized boolean setName(String name) {
@@ -646,10 +647,10 @@
     }
 
     /*package*/ synchronized String getProperty (String name) {
-        if (!mProperties.isEmpty())
-            return mProperties.get(name);
+        if (!mAdapterProperties.isEmpty())
+            return mAdapterProperties.get(name);
         getAllProperties();
-        return mProperties.get(name);
+        return mAdapterProperties.get(name);
     }
 
     public synchronized String getAddress() {
@@ -678,7 +679,7 @@
         if (!BluetoothDevice.checkBluetoothAddress(address)) {
             return null;
         }
-        Map <String, String> properties = mRemoteDeviceProperties.get(address);
+        Map <String, String> properties = mDeviceProperties.get(address);
         if (properties != null) return properties.get("Name");
         return null;
     }
@@ -805,7 +806,7 @@
     }
 
     /*package*/ boolean isRemoteDeviceInCache(String address) {
-        return (mRemoteDeviceProperties.get(address) != null);
+        return (mDeviceProperties.get(address) != null);
     }
 
     /*package*/ String[] getRemoteDeviceProperties(String address) {
@@ -814,7 +815,7 @@
     }
 
     /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) {
-        Map<String, String> properties = mRemoteDeviceProperties.get(address);
+        Map<String, String> properties = mDeviceProperties.get(address);
         if (properties != null) {
             return properties.get(property);
         } else {
@@ -835,7 +836,7 @@
         /*
          * We get a DeviceFound signal every time RSSI changes or name changes.
          * Don't create a new Map object every time */
-        Map<String, String> propertyValues = mRemoteDeviceProperties.get(address);
+        Map<String, String> propertyValues = mDeviceProperties.get(address);
         if (propertyValues != null) {
             propertyValues.clear();
         } else {
@@ -864,19 +865,19 @@
             }
             propertyValues.put(name, newValue);
         }
-        mRemoteDeviceProperties.put(address, propertyValues);
+        mDeviceProperties.put(address, propertyValues);
     }
 
     /* package */ void removeRemoteDeviceProperties(String address) {
-        mRemoteDeviceProperties.remove(address);
+        mDeviceProperties.remove(address);
     }
 
     /* package */ synchronized void setRemoteDeviceProperty(String address, String name,
                                                               String value) {
-        Map <String, String> propVal = mRemoteDeviceProperties.get(address);
+        Map <String, String> propVal = mDeviceProperties.get(address);
         if (propVal != null) {
             propVal.put(name, value);
-            mRemoteDeviceProperties.put(address, propVal);
+            mDeviceProperties.put(address, propVal);
         } else {
             Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address);
         }
@@ -1059,16 +1060,16 @@
         pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive + "\n");
 
         switch(mBluetoothState) {
-        case BluetoothDevice.BLUETOOTH_STATE_OFF:
+        case BluetoothAdapter.BLUETOOTH_STATE_OFF:
             pw.println("\nBluetooth OFF\n");
             return;
-        case BluetoothDevice.BLUETOOTH_STATE_TURNING_ON:
+        case BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON:
             pw.println("\nBluetooth TURNING ON\n");
             return;
-        case BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF:
+        case BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF:
             pw.println("\nBluetooth TURNING OFF\n");
             return;
-        case BluetoothDevice.BLUETOOTH_STATE_ON:
+        case BluetoothAdapter.BLUETOOTH_STATE_ON:
             pw.println("\nBluetooth ON\n");
         }
 
@@ -1079,7 +1080,7 @@
         BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
 
         pw.println("\n--Known devices--");
-        for (String address : mRemoteDeviceProperties.keySet()) {
+        for (String address : mDeviceProperties.keySet()) {
             pw.printf("%s %10s (%d) %s\n", address,
                        toBondStateString(mBondState.getBondState(address)),
                        mBondState.getAttempt(address),
@@ -1113,7 +1114,7 @@
             pw.println("getState() = STATE_ERROR");
             break;
         }
-        pw.println("getHeadsetAddress() = " + headset.getHeadsetAddress());
+        pw.println("getCurrentHeadset() = " + headset.getCurrentHeadset());
         pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
 
         headset.close();
@@ -1121,20 +1122,20 @@
 
     /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
         if (pairable && discoverable)
-            return BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
+            return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
         else if (pairable && !discoverable)
-            return BluetoothDevice.SCAN_MODE_CONNECTABLE;
+            return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
         else
-            return BluetoothDevice.SCAN_MODE_NONE;
+            return BluetoothAdapter.SCAN_MODE_NONE;
     }
 
     /* package */ static String scanModeToBluezString(int mode) {
         switch (mode) {
-        case BluetoothDevice.SCAN_MODE_NONE:
+        case BluetoothAdapter.SCAN_MODE_NONE:
             return "off";
-        case BluetoothDevice.SCAN_MODE_CONNECTABLE:
+        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
             return "connectable";
-        case BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
+        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
             return "discoverable";
         }
         return null;
diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java
index 77d6e20..4c9451e 100644
--- a/core/java/com/android/internal/app/ShutdownThread.java
+++ b/core/java/com/android/internal/app/ShutdownThread.java
@@ -21,8 +21,8 @@
 import android.app.IActivityManager;
 import android.app.ProgressDialog;
 import android.app.AlertDialog;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.IBluetoothDevice;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.IBluetooth;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -179,13 +179,13 @@
         
         final ITelephony phone =
                 ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
-        final IBluetoothDevice bluetooth =
-                IBluetoothDevice.Stub.asInterface(ServiceManager.checkService(
+        final IBluetooth bluetooth =
+                IBluetooth.Stub.asInterface(ServiceManager.checkService(
                         Context.BLUETOOTH_SERVICE));
         
         try {
             bluetoothOff = bluetooth == null ||
-                           bluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF;
+                           bluetooth.getBluetoothState() == BluetoothAdapter.BLUETOOTH_STATE_OFF;
             if (!bluetoothOff) {
                 Log.w(TAG, "Disabling Bluetooth...");
                 bluetooth.disable(false);  // disable but don't persist new state
@@ -213,7 +213,7 @@
             if (!bluetoothOff) {
                 try {
                     bluetoothOff =
-                            bluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF;
+                            bluetooth.getBluetoothState() == BluetoothAdapter.BLUETOOTH_STATE_OFF;
                 } catch (RemoteException ex) {
                     Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
                     bluetoothOff = true;
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 36d2684..015268b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -114,7 +114,7 @@
 	android_bluetooth_BluetoothAudioGateway.cpp \
 	android_bluetooth_BluetoothSocket.cpp \
 	android_bluetooth_ScoSocket.cpp \
-	android_server_BluetoothDeviceService.cpp \
+	android_server_BluetoothService.cpp \
 	android_server_BluetoothEventLoop.cpp \
 	android_server_BluetoothA2dpService.cpp \
 	android_message_digest_sha1.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 63dc9e8..2e73372 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -146,7 +146,7 @@
 extern int register_android_bluetooth_BluetoothAudioGateway(JNIEnv* env);
 extern int register_android_bluetooth_BluetoothSocket(JNIEnv *env);
 extern int register_android_bluetooth_ScoSocket(JNIEnv *env);
-extern int register_android_server_BluetoothDeviceService(JNIEnv* env);
+extern int register_android_server_BluetoothService(JNIEnv* env);
 extern int register_android_server_BluetoothEventLoop(JNIEnv *env);
 extern int register_android_server_BluetoothA2dpService(JNIEnv* env);
 extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
@@ -1241,7 +1241,7 @@
     REG_JNI(register_android_bluetooth_BluetoothAudioGateway),
     REG_JNI(register_android_bluetooth_BluetoothSocket),
     REG_JNI(register_android_bluetooth_ScoSocket),
-    REG_JNI(register_android_server_BluetoothDeviceService),
+    REG_JNI(register_android_server_BluetoothService),
     REG_JNI(register_android_server_BluetoothEventLoop),
     REG_JNI(register_android_server_BluetoothA2dpService),
     REG_JNI(register_android_message_digest_sha1),
diff --git a/core/jni/android_server_BluetoothDeviceService.cpp b/core/jni/android_server_BluetoothService.cpp
similarity index 98%
rename from core/jni/android_server_BluetoothDeviceService.cpp
rename to core/jni/android_server_BluetoothService.cpp
index 444e628..326052b 100644
--- a/core/jni/android_server_BluetoothDeviceService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -16,7 +16,7 @@
 
 #define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
 #define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device"
-#define LOG_TAG "BluetoothDeviceService.cpp"
+#define LOG_TAG "BluetoothService.cpp"
 
 #include "android_bluetooth_common.h"
 #include "android_runtime/AndroidRuntime.h"
@@ -49,7 +49,7 @@
 
 #ifdef HAVE_BLUETOOTH
 // We initialize these variables when we load class
-// android.server.BluetoothDeviceService
+// android.server.BluetoothService
 static jfieldID field_mNativeData;
 static jfieldID field_mEventLoop;
 
@@ -732,9 +732,9 @@
             (void *)cancelPairingUserInputNative},
 };
 
-int register_android_server_BluetoothDeviceService(JNIEnv *env) {
+int register_android_server_BluetoothService(JNIEnv *env) {
     return AndroidRuntime::registerNativeMethods(env,
-                "android/server/BluetoothDeviceService", sMethods, NELEM(sMethods));
+                "android/server/BluetoothService", sMethods, NELEM(sMethods));
 }
 
 } /* namespace android */
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 5a59712..05b68d4 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -17,16 +17,16 @@
 package android.media;
 
 import android.app.ActivityManagerNative;
+import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.bluetooth.BluetoothIntent;
-import android.content.BroadcastReceiver;
-import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothIntent;
+import android.bluetooth.BluetoothHeadset;
 
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
@@ -236,8 +236,6 @@
     // Forced device usage for communications
     private int mForcedUseForComm;
 
-    private BluetoothDevice mBluetoothDevice = null;
-
     ///////////////////////////////////////////////////////////////////////////
     // Construction
     ///////////////////////////////////////////////////////////////////////////
@@ -1371,8 +1369,8 @@
             if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
                 int state = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
                                                BluetoothA2dp.STATE_DISCONNECTED);
-                String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
-
+                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothIntent.DEVICE);
+                String address = btDevice.getAddress();
                 boolean isConnected = (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
                                        ((String)mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)).equals(address));
 
@@ -1387,30 +1385,27 @@
                     AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                                                          AudioSystem.DEVICE_STATE_AVAILABLE,
                                                          address);
-                    mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), address);
+                    mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
+                            address);
                 }
             } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
                 int state = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
                                                BluetoothHeadset.STATE_ERROR);
-                String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
+                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothIntent.DEVICE);
+                String address = btDevice.getAddress();
                 int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
-                if (mBluetoothDevice == null) {
-                    mBluetoothDevice = (BluetoothDevice)mContext.getSystemService(Context.BLUETOOTH_SERVICE);
-                }
-                if (mBluetoothDevice != null) {
-                    int btClass = mBluetoothDevice.getRemoteClass(address);
-                    if (BluetoothClass.Device.Major.getDeviceMajor(btClass) == BluetoothClass.Device.Major.AUDIO_VIDEO) {
-                        switch (BluetoothClass.Device.getDevice(btClass)) {
-                        case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
-                        case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
-                            device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
-                            break;
-                        case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
-                            device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
-                            break;
-                        default:
-                            break;
-                        }
+                int btClass = btDevice.getBluetoothClass();
+                if (BluetoothClass.Device.Major.getDeviceMajor(btClass) == BluetoothClass.Device.Major.AUDIO_VIDEO) {
+                    switch (BluetoothClass.Device.getDevice(btClass)) {
+                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
+                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
+                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+                        break;
+                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
+                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+                        break;
+                    default:
+                        break;
                     }
                 }
 
@@ -1426,7 +1421,7 @@
                     AudioSystem.setDeviceConnectionState(device,
                                                          AudioSystem.DEVICE_STATE_AVAILABLE,
                                                          address);
-                    mConnectedDevices.put( new Integer(device), address);
+                    mConnectedDevices.put(new Integer(device), address);
                 }
             } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
                 int state = intent.getIntExtra("state", 0);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index a5bd254..56a279a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -30,7 +30,7 @@
 import android.backup.BackupDataInput;
 import android.backup.BackupDataOutput;
 import android.backup.BackupHelperAgent;
-import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothAdapter;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -393,7 +393,7 @@
     }
 
     private void enableBluetooth(boolean enable) {
-        BluetoothDevice bt = (BluetoothDevice) getSystemService(Context.BLUETOOTH_SERVICE);
+        BluetoothAdapter bt = (BluetoothAdapter) getSystemService(Context.BLUETOOTH_SERVICE);
         if (bt != null) {
             if (!enable) {
                 bt.disable();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ce476eb..98f35f4 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -36,7 +36,7 @@
 import android.provider.Contacts.People;
 import android.provider.Settings;
 import android.server.BluetoothA2dpService;
-import android.server.BluetoothDeviceService;
+import android.server.BluetoothService;
 import android.server.search.SearchManagerService;
 import android.util.EventLog;
 import android.util.Log;
@@ -89,7 +89,7 @@
         IPackageManager pm = null;
         Context context = null;
         WindowManagerService wm = null;
-        BluetoothDeviceService bluetooth = null;
+        BluetoothService bluetooth = null;
         BluetoothA2dpService bluetoothA2dp = null;
         HeadsetObserver headset = null;
         DockObserver dock = null;
@@ -176,9 +176,9 @@
                 ServiceManager.addService(Context.BLUETOOTH_SERVICE, null);
             } else {
                 Log.i(TAG, "Starting Bluetooth Service.");
-                bluetooth = new BluetoothDeviceService(context);
-                bluetooth.init();
+                bluetooth = new BluetoothService(context);
                 ServiceManager.addService(Context.BLUETOOTH_SERVICE, bluetooth);
+                bluetooth.initAfterRegistration();
                 bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
                 ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
                                           bluetoothA2dp);
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index e71d329..33d899a 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -18,7 +18,7 @@
 
 import android.app.AlertDialog;
 import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothError;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothIntent;
@@ -473,10 +473,10 @@
         mBluetoothData = IconData.makeIcon("bluetooth",
                 null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0);
         mBluetoothIcon = service.addIcon(mBluetoothData, null);
-        BluetoothDevice bluetooth =
-                (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
-        if (bluetooth != null) {
-            mBluetoothEnabled = bluetooth.isEnabled();
+        BluetoothAdapter adapter =
+                (BluetoothAdapter) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
+        if (adapter != null) {
+            mBluetoothEnabled = adapter.isEnabled();
         } else {
             mBluetoothEnabled = false;
         }
@@ -1083,7 +1083,7 @@
         if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
             int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
                                            BluetoothError.ERROR);
-            mBluetoothEnabled = state == BluetoothDevice.BLUETOOTH_STATE_ON;
+            mBluetoothEnabled = state == BluetoothAdapter.BLUETOOTH_STATE_ON;
         } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
             mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
                     BluetoothHeadset.STATE_ERROR);
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 083cda3..fa24a98 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -39,6 +39,7 @@
 import android.util.Config;
 import android.app.Notification;
 import android.app.PendingIntent;
+import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothA2dp;
 import android.content.ContentResolver;
@@ -49,6 +50,7 @@
 
 import java.util.List;
 import java.util.ArrayList;
+import java.util.Set;
 import java.net.UnknownHostException;
 
 /**
@@ -645,10 +647,10 @@
 
     private void checkIsBluetoothPlaying() {
         boolean isBluetoothPlaying = false;
-        List<String> connected = mBluetoothA2dp.listConnectedSinks();
+        Set<BluetoothDevice> connected = mBluetoothA2dp.getConnectedSinks();
 
-        for (String address : connected) {
-            if (mBluetoothA2dp.getSinkState(address) == BluetoothA2dp.STATE_PLAYING) {
+        for (BluetoothDevice device : connected) {
+            if (mBluetoothA2dp.getSinkState(device) == BluetoothA2dp.STATE_PLAYING) {
                 isBluetoothPlaying = true;
                 break;
             }