Unhide Bluetooth Low Energy public APIs

Updated API headers. Add BluetoothManager to be retrieved by
context.getSystemService(Context.BLUETOOTH_SERVICE).
LE scan functions are placed in BluetoothAdapter
The GATT API are device driven instead of a profile-driver.
bug 8450158

Change-Id: I424a4cedaac3ef8120a05996500008dd210d2553
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 734d435..459e49c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -19,7 +19,7 @@
 import com.android.internal.policy.PolicyManager;
 import com.android.internal.util.Preconditions;
 
-import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -319,7 +319,7 @@
 
         registerService(BLUETOOTH_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
-                    return BluetoothAdapter.getDefaultAdapter();
+                    return new BluetoothManager(ctx);
                 }});
 
         registerService(CLIPBOARD_SERVICE, new ServiceFetcher() {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index b00bf09..2e9c9e3 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -22,7 +22,6 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
@@ -359,6 +358,8 @@
     private IBluetooth mService;
 
     private Handler mServiceRecordHandler;
+    private BluetoothAdapterCallback mCallback;
+    private int mClientIf;
 
     /**
      * Get a handle to the default local Bluetooth adapter.
@@ -1137,7 +1138,8 @@
      * Get the profile proxy object associated with the profile.
      *
      * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
-     * or {@link BluetoothProfile#A2DP}. Clients must implement
+     * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, or
+     * {@link BluetoothProfile#GATT_SERVER}. Clients must implement
      * {@link BluetoothProfile.ServiceListener} to get notified of
      * the connection status and to get the proxy object.
      *
@@ -1166,12 +1168,6 @@
         } else if (profile == BluetoothProfile.HEALTH) {
             BluetoothHealth health = new BluetoothHealth(context, listener);
             return true;
-        } else if (profile == BluetoothProfile.GATT) {
-            BluetoothGatt gatt = new BluetoothGatt(context, listener);
-            return true;
-        } else if (profile == BluetoothProfile.GATT_SERVER) {
-            BluetoothGattServer gattServer = new BluetoothGattServer(context, listener);
-            return true;
         } else {
             return false;
         }
@@ -1411,4 +1407,230 @@
             mProxyServiceStateCallbacks.remove(cb);
         }
     }
+
+    /**
+     * Register an callback to receive async results, such as LE scan result.
+     *
+     * <p>This is an asynchronous call. The callback
+     * {@link BluetoothAdapterCallback#onCallbackRegistration}
+     * is used to notify success or failure if the function returns true.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param callback BluetootAdapter callback handler that will receive asynchronous callbacks.
+     * @return If true, the callback will be called to notify success or failure,
+     *         false on immediate error
+     */
+    public boolean registerCallback(BluetoothAdapterCallback callback) {
+        try {
+            IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
+            mCallback = callback;
+            UUID uuid = UUID.randomUUID();
+            if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid);
+
+            iGatt.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback);
+            return true;
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+            return false;
+        }
+    }
+
+    /**
+     * Unregister the registered callback.
+     */
+    public boolean unRegisterCallback(BluetoothAdapterCallback callback) {
+        if (callback != mCallback) return false;
+        try {
+            IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
+
+            iGatt.unregisterClient(mClientIf);
+            return true;
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+            return false;
+        }
+    }
+
+    /**
+     * Starts a scan for Bluetooth LE devices.
+     *
+     * <p>Results of the scan are reported using the
+     * {@link BluetoothAdapterCallback#onLeScan} callback.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @return true, if the scan was started successfully
+     */
+    public boolean startLeScan() {
+        if (DBG) Log.d(TAG, "startLeScan()");
+        if (mClientIf == 0) return false;
+
+        try {
+            IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
+            iGatt.startScan(mClientIf, false);
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Starts a scan for Bluetooth LE devices, looking for devices that
+     * advertise given services.
+     *
+     * <p>Devices which advertise all specified services are reported using the
+     * {@link BluetoothAdapterCallback#onLeScan} callback.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param serviceUuids Array of services to look for
+     * @return true, if the scan was started successfully
+     */
+    public boolean startLeScan(UUID[] serviceUuids) {
+        if (DBG) Log.d(TAG, "startLeScan() - with UUIDs");
+        if (mClientIf == 0) return false;
+
+        try {
+            IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
+            ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length];
+            for(int i = 0; i != uuids.length; ++i) {
+                uuids[i] = new ParcelUuid(serviceUuids[i]);
+            }
+            iGatt.startScanWithUuids(mClientIf, false, uuids);
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Stops an ongoing Bluetooth LE device scan.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     */
+    public void stopLeScan() {
+        if (DBG) Log.d(TAG, "stopScan()");
+        if (mClientIf == 0) return;
+
+        try {
+            IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
+            iGatt.stopScan(mClientIf, false);
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+        }
+    }
+
+    /**
+     * Bluetooth GATT interface callbacks
+     */
+    private final IBluetoothGattCallback mBluetoothGattCallback =
+        new IBluetoothGattCallback.Stub() {
+            /**
+             * Application interface registered - app is ready to go
+             */
+            public void onClientRegistered(int status, int clientIf) {
+                if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status
+                    + " clientIf=" + clientIf);
+                mClientIf = clientIf;
+                mCallback.onCallbackRegistration(status == BluetoothGatt.GATT_SUCCESS ?
+                                  BluetoothAdapterCallback.CALLBACK_REGISTERED :
+                                  BluetoothAdapterCallback.CALLBACK_REGISTRATION_FAILURE);
+            }
+
+            public void onClientConnectionState(int status, int clientIf,
+                                                boolean connected, String address) {
+                // no op
+            }
+
+            /**
+             * Callback reporting an LE scan result.
+             * @hide
+             */
+            public void onScanResult(String address, int rssi, byte[] advData) {
+                if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
+
+                try {
+                    mCallback.onLeScan(getRemoteDevice(address), rssi, advData);
+                } catch (Exception ex) {
+                    Log.w(TAG, "Unhandled exception: " + ex);
+                }
+            }
+
+            public void onGetService(String address, int srvcType,
+                                     int srvcInstId, ParcelUuid srvcUuid) {
+                // no op
+            }
+
+            public void onGetIncludedService(String address, int srvcType,
+                                             int srvcInstId, ParcelUuid srvcUuid,
+                                             int inclSrvcType, int inclSrvcInstId,
+                                             ParcelUuid inclSrvcUuid) {
+                // no op
+            }
+
+            public void onGetCharacteristic(String address, int srvcType,
+                             int srvcInstId, ParcelUuid srvcUuid,
+                             int charInstId, ParcelUuid charUuid,
+                             int charProps) {
+                // no op
+            }
+
+            public void onGetDescriptor(String address, int srvcType,
+                             int srvcInstId, ParcelUuid srvcUuid,
+                             int charInstId, ParcelUuid charUuid,
+                             ParcelUuid descUuid) {
+                // no op
+            }
+
+            public void onSearchComplete(String address, int status) {
+                // no op
+            }
+
+            public void onCharacteristicRead(String address, int status, int srvcType,
+                             int srvcInstId, ParcelUuid srvcUuid,
+                             int charInstId, ParcelUuid charUuid, byte[] value) {
+                // no op
+            }
+
+            public void onCharacteristicWrite(String address, int status, int srvcType,
+                             int srvcInstId, ParcelUuid srvcUuid,
+                             int charInstId, ParcelUuid charUuid) {
+                // no op
+            }
+
+            public void onNotify(String address, int srvcType,
+                             int srvcInstId, ParcelUuid srvcUuid,
+                             int charInstId, ParcelUuid charUuid,
+                             byte[] value) {
+                // no op
+            }
+
+            public void onDescriptorRead(String address, int status, int srvcType,
+                             int srvcInstId, ParcelUuid srvcUuid,
+                             int charInstId, ParcelUuid charUuid,
+                             ParcelUuid descrUuid, byte[] value) {
+                // no op
+            }
+
+            public void onDescriptorWrite(String address, int status, int srvcType,
+                             int srvcInstId, ParcelUuid srvcUuid,
+                             int charInstId, ParcelUuid charUuid,
+                             ParcelUuid descrUuid) {
+                // no op
+            }
+
+            public void onExecuteWrite(String address, int status) {
+                // no op
+            }
+
+            public void onReadRemoteRssi(String address, int rssi, int status) {
+                // no op
+            }
+        };
+
 }
diff --git a/core/java/android/bluetooth/BluetoothAdapterCallback.java b/core/java/android/bluetooth/BluetoothAdapterCallback.java
new file mode 100644
index 0000000..a726bc9
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAdapterCallback.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2013 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.bluetooth.BluetoothDevice;
+
+/**
+ * This abstract class is used to implement {@link BluetoothAdapter} callbacks.
+ */
+public abstract class BluetoothAdapterCallback {
+
+    /**
+     * Indicates the callback has been registered successfully
+     */
+    public static final int CALLBACK_REGISTERED = 0;
+
+    /**
+     * Indicates the callback registration has failed
+     */
+    public static final int CALLBACK_REGISTRATION_FAILURE = 1;
+
+    /**
+     * Callback to inform change in registration state of the  application.
+     *
+     * @param status Returns {@link #CALLBACK_REGISTERED} if the application
+     *               was successfully registered.
+     */
+    public void onCallbackRegistration(int status) {
+    }
+
+    /**
+     * Callback reporting an LE device found during a device scan initiated
+     * by the {@link BluetoothAdapter#startLeScan} function.
+     *
+     * @param device Identifies the remote device
+     * @param rssi The RSSI value for the remote device as reported by the
+     *             Bluetooth hardware. 0 if no RSSI value is available.
+     * @param scanRecord The content of the advertisement record offered by
+     *                   the remote device.
+     */
+    public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 4cc22b4..83e95ca 100755
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -1126,4 +1127,30 @@
         return pinBytes;
     }
 
+    /**
+     * Connect to GATT Server hosted by this device. Caller acts as GATT client.
+     * The callback is used to deliver results to Caller, such as connection status as well
+     * as any further GATT client operations.
+     * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
+     * GATT client operations.
+     * @param callback GATT callback handler that will receive asynchronous callbacks.
+     * @param autoConnect Whether to directly connect to the remote device (false)
+     *                    or to automatically connect as soon as the remote
+     *                    device becomes available (true).
+     * @throws IllegalArgumentException if callback is null
+     */
+    public BluetoothGatt connectGattServer(Context context, boolean autoConnect,
+                                           BluetoothGattCallback callback) {
+        // TODO(Bluetooth) check whether platform support BLE
+        //     Do the check here or in GattServer?
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        IBluetoothManager managerService = adapter.getBluetoothManager();
+        try {
+            IBluetoothGatt iGatt = managerService.getBluetoothGatt();
+            BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this);
+            gatt.connect(autoConnect, callback);
+            return gatt;
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return null;
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 1e12025..f9ce6ea 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -16,8 +16,6 @@
 
 package android.bluetooth;
 
-
-import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothProfile.ServiceListener;
@@ -39,42 +37,48 @@
 import java.util.UUID;
 
 /**
- * Public API for the Bluetooth Gatt Profile.
+ * Public API for the Bluetooth GATT Profile.
  *
- * <p>This class provides Bluetooth Gatt functionality to enable communication
+ * <p>This class provides Bluetooth GATT functionality to enable communication
  * with Bluetooth Smart or Smart Ready devices.
  *
- * <p>BluetoothGatt is a proxy object for controlling the Bluetooth Service
- * via IPC.  Use {@link BluetoothAdapter#getProfileProxy} to get the
- * BluetoothGatt proxy object.
- *
  * <p>To connect to a remote peripheral device, create a {@link BluetoothGattCallback}
- * and call {@link #registerApp} to register your application. Gatt capable
- * devices can be discovered using the {@link #startScan} function or the
- * regular Bluetooth device discovery process.
- * @hide
+ * and call {@link BluetoothDevice#connectGattServer} to get a instance of this class.
+ * GATT capable devices can be discovered using the Bluetooth device discovery or BLE
+ * scan process.
  */
 public final class BluetoothGatt implements BluetoothProfile {
     private static final String TAG = "BluetoothGatt";
     private static final boolean DBG = true;
+    private static final boolean VDBG = true;
 
-    private Context mContext;
-    private ServiceListener mServiceListener;
-    private BluetoothAdapter mAdapter;
+    private final Context mContext;
     private IBluetoothGatt mService;
     private BluetoothGattCallback mCallback;
     private int mClientIf;
     private boolean mAuthRetry = false;
+    private BluetoothDevice mDevice;
+    private boolean mAutoConnect;
+    private int mConnState;
+    private final Object mStateLock = new Object();
+
+    private static final int CONN_STATE_IDLE = 0;
+    private static final int CONN_STATE_CONNECTING = 1;
+    private static final int CONN_STATE_CONNECTED = 2;
+    private static final int CONN_STATE_DISCONNECTING = 3;
 
     private List<BluetoothGattService> mServices;
 
-    /** A Gatt operation completed successfully */
+    /** A GATT operation failed */
+    public static final int GATT_FAILURE = 0;
+
+    /** A GATT operation completed successfully */
     public static final int GATT_SUCCESS = 0;
 
-    /** Gatt read operation is not permitted */
+    /** GATT read operation is not permitted */
     public static final int GATT_READ_NOT_PERMITTED = 0x2;
 
-    /** Gatt write operation is not permitted */
+    /** GATT write operation is not permitted */
     public static final int GATT_WRITE_NOT_PERMITTED = 0x3;
 
     /** Insufficient authentication for a given operation */
@@ -111,55 +115,6 @@
     /*package*/ static final int AUTHENTICATION_MITM = 2;
 
     /**
-     * Bluetooth state change handlers
-     */
-    private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
-        new IBluetoothStateChangeCallback.Stub() {
-            public void onBluetoothStateChange(boolean up) {
-                if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
-                if (!up) {
-                    if (DBG) Log.d(TAG,"Unbinding service...");
-                    synchronized (mConnection) {
-                        mService = null;
-                        mContext.unbindService(mConnection);
-                    }
-                } else {
-                    synchronized (mConnection) {
-                        if (mService == null) {
-                            if (DBG) Log.d(TAG,"Binding service...");
-                            if (!mContext.bindService(new Intent(IBluetoothGatt.class.getName()),
-                                                      mConnection, 0)) {
-                                Log.e(TAG, "Could not bind to Bluetooth GATT Service");
-                            }
-                        }
-                    }
-                }
-            }
-        };
-
-    /**
-     * Service binder handling
-     */
-    private ServiceConnection mConnection = new ServiceConnection() {
-            public void onServiceConnected(ComponentName className, IBinder service) {
-                if (DBG) Log.d(TAG, "Proxy object connected");
-                mService = IBluetoothGatt.Stub.asInterface(service);
-                ServiceListener serviceListener = mServiceListener;
-                if (serviceListener != null) {
-                    serviceListener.onServiceConnected(BluetoothProfile.GATT, BluetoothGatt.this);
-                }
-            }
-            public void onServiceDisconnected(ComponentName className) {
-                if (DBG) Log.d(TAG, "Proxy object disconnected");
-                mService = null;
-                ServiceListener serviceListener = mServiceListener;
-                if (serviceListener != null) {
-                    serviceListener.onServiceDisconnected(BluetoothProfile.GATT);
-                }
-            }
-        };
-
-    /**
      * Bluetooth GATT interface callbacks
      */
     private final IBluetoothGattCallback mBluetoothGattCallback =
@@ -171,11 +126,27 @@
             public void onClientRegistered(int status, int clientIf) {
                 if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status
                     + " clientIf=" + clientIf);
+                if (VDBG) {
+                    synchronized(mStateLock) {
+                        if (mConnState != CONN_STATE_CONNECTING) {
+                            Log.e(TAG, "Bad connection state: " + mConnState);
+                        }
+                    }
+                }
                 mClientIf = clientIf;
+                if (status != GATT_SUCCESS) {
+                    mCallback.onConnectionStateChange(mDevice, GATT_FAILURE,
+                                                      BluetoothProfile.STATE_DISCONNECTED);
+                    synchronized(mStateLock) {
+                        mConnState = CONN_STATE_IDLE;
+                    }
+                    return;
+                }
                 try {
-                    mCallback.onAppRegistered(status);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    mService.clientConnect(mClientIf, mDevice.getAddress(),
+                                           !mAutoConnect); // autoConnect is inverse of "isDirect"
+                } catch (RemoteException e) {
+                    Log.e(TAG,"",e);
                 }
             }
 
@@ -187,13 +158,24 @@
                                                 boolean connected, String address) {
                 if (DBG) Log.d(TAG, "onClientConnectionState() - status=" + status
                                  + " clientIf=" + clientIf + " device=" + address);
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                int profileState = connected ? BluetoothProfile.STATE_CONNECTED :
+                                               BluetoothProfile.STATE_DISCONNECTED;
                 try {
-                    mCallback.onConnectionStateChange(mAdapter.getRemoteDevice(address), status,
-                                                      connected ? BluetoothProfile.STATE_CONNECTED
-                                                      : BluetoothProfile.STATE_DISCONNECTED);
+                    mCallback.onConnectionStateChange(mDevice, status, profileState);
                 } catch (Exception ex) {
                     Log.w(TAG, "Unhandled exception: " + ex);
                 }
+
+                synchronized(mStateLock) {
+                    if (connected) {
+                        mConnState = CONN_STATE_CONNECTED;
+                    } else {
+                        mConnState = CONN_STATE_IDLE;
+                    }
+                }
             }
 
             /**
@@ -201,13 +183,7 @@
              * @hide
              */
             public void onScanResult(String address, int rssi, byte[] advData) {
-                if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
-
-                try {
-                    mCallback.onScanResult(mAdapter.getRemoteDevice(address), rssi, advData);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
-                }
+                // no op
             }
 
             /**
@@ -219,8 +195,10 @@
             public void onGetService(String address, int srvcType,
                                      int srvcInstId, ParcelUuid srvcUuid) {
                 if (DBG) Log.d(TAG, "onGetService() - Device=" + address + " UUID=" + srvcUuid);
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                mServices.add(new BluetoothGattService(device, srvcUuid.getUuid(),
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                mServices.add(new BluetoothGattService(mDevice, srvcUuid.getUuid(),
                                                        srvcInstId, srvcType));
             }
 
@@ -236,10 +214,12 @@
                 if (DBG) Log.d(TAG, "onGetIncludedService() - Device=" + address
                     + " UUID=" + srvcUuid + " Included=" + inclSrvcUuid);
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device,
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                BluetoothGattService service = getService(mDevice,
                         srvcUuid.getUuid(), srvcInstId, srvcType);
-                BluetoothGattService includedService = getService(device,
+                BluetoothGattService includedService = getService(mDevice,
                         inclSrvcUuid.getUuid(), inclSrvcInstId, inclSrvcType);
 
                 if (service != null && includedService != null) {
@@ -260,8 +240,10 @@
                 if (DBG) Log.d(TAG, "onGetCharacteristic() - Device=" + address + " UUID=" +
                                charUuid);
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device, srvcUuid.getUuid(),
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service != null) {
                     service.addCharacteristic(new BluetoothGattCharacteristic(
@@ -281,8 +263,10 @@
                              ParcelUuid descUuid) {
                 if (DBG) Log.d(TAG, "onGetDescriptor() - Device=" + address + " UUID=" + descUuid);
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device, srvcUuid.getUuid(),
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
 
@@ -303,9 +287,11 @@
              */
             public void onSearchComplete(String address, int status) {
                 if (DBG) Log.d(TAG, "onSearchComplete() = Device=" + address + " Status=" + status);
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
                 try {
-                    mCallback.onServicesDiscovered(device, status);
+                    mCallback.onServicesDiscovered(mDevice, status);
                 } catch (Exception ex) {
                     Log.w(TAG, "Unhandled exception: " + ex);
                 }
@@ -322,6 +308,9 @@
                 if (DBG) Log.d(TAG, "onCharacteristicRead() - Device=" + address
                             + " UUID=" + charUuid + " Status=" + status);
 
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
                 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
                   || status == GATT_INSUFFICIENT_ENCRYPTION)
                   && mAuthRetry == false) {
@@ -338,8 +327,7 @@
 
                 mAuthRetry = false;
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device, srvcUuid.getUuid(),
+                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
 
@@ -367,8 +355,10 @@
                 if (DBG) Log.d(TAG, "onCharacteristicWrite() - Device=" + address
                             + " UUID=" + charUuid + " Status=" + status);
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device, srvcUuid.getUuid(),
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
 
@@ -411,8 +401,10 @@
                              byte[] value) {
                 if (DBG) Log.d(TAG, "onNotify() - Device=" + address + " UUID=" + charUuid);
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device, srvcUuid.getUuid(),
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
 
@@ -439,8 +431,10 @@
                              ParcelUuid descrUuid, byte[] value) {
                 if (DBG) Log.d(TAG, "onDescriptorRead() - Device=" + address + " UUID=" + charUuid);
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device, srvcUuid.getUuid(),
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
 
@@ -486,8 +480,10 @@
                              ParcelUuid descrUuid) {
                 if (DBG) Log.d(TAG, "onDescriptorWrite() - Device=" + address + " UUID=" + charUuid);
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device, srvcUuid.getUuid(),
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
 
@@ -529,9 +525,11 @@
             public void onExecuteWrite(String address, int status) {
                 if (DBG) Log.d(TAG, "onExecuteWrite() - Device=" + address
                     + " status=" + status);
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
                 try {
-                    mCallback.onReliableWriteCompleted(device, status);
+                    mCallback.onReliableWriteCompleted(mDevice, status);
                 } catch (Exception ex) {
                     Log.w(TAG, "Unhandled exception: " + ex);
                 }
@@ -544,43 +542,24 @@
             public void onReadRemoteRssi(String address, int rssi, int status) {
                 if (DBG) Log.d(TAG, "onReadRemoteRssi() - Device=" + address +
                             " rssi=" + rssi + " status=" + status);
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
                 try {
-                    mCallback.onReadRemoteRssi(device, rssi, status);
+                    mCallback.onReadRemoteRssi(mDevice, rssi, status);
                 } catch (Exception ex) {
                     Log.w(TAG, "Unhandled exception: " + ex);
                 }
             }
         };
 
-    /**
-     * Create a BluetoothGatt proxy object.
-     */
-    /*package*/ BluetoothGatt(Context context, ServiceListener l) {
+    /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device) {
         mContext = context;
-        mServiceListener = l;
-        mAdapter = BluetoothAdapter.getDefaultAdapter();
+        mService = iGatt;
+        mDevice = device;
         mServices = new ArrayList<BluetoothGattService>();
 
-        IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE);
-        if (b != null) {
-            IBluetoothManager mgr = IBluetoothManager.Stub.asInterface(b);
-            try {
-                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
-            } catch (RemoteException re) {
-                Log.e(TAG, "Unable to register BluetoothStateChangeCallback", re);
-            }
-        } else {
-            Log.e(TAG, "Unable to get BluetoothManager interface.");
-            throw new RuntimeException("BluetoothManager inactive");
-        }
-
-        //Bind to the service only if the Bluetooth is ON
-        if(mAdapter.isEnabled()){
-            if (!context.bindService(new Intent(IBluetoothGatt.class.getName()), mConnection, 0)) {
-                Log.e(TAG, "Could not bind to Bluetooth Gatt Service");
-            }
-        }
+        mConnState = CONN_STATE_IDLE;
     }
 
     /**
@@ -590,24 +569,6 @@
         if (DBG) Log.d(TAG, "close()");
 
         unregisterApp();
-        mServiceListener = null;
-
-        IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE);
-        if (b != null) {
-            IBluetoothManager mgr = IBluetoothManager.Stub.asInterface(b);
-            try {
-                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
-            } catch (RemoteException re) {
-                Log.e(TAG, "Unable to unregister BluetoothStateChangeCallback", re);
-            }
-        }
-
-        synchronized (mConnection) {
-            if (mService != null) {
-                mService = null;
-                mContext.unbindService(mConnection);
-            }
-        }
     }
 
     /**
@@ -629,18 +590,18 @@
 
 
     /**
-     * Register an application callback to start using Gatt.
+     * Register an application callback to start using GATT.
      *
-     * <p>This is an asynchronous call. The callback is used to notify
-     * success or failure if the function returns true.
+     * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
+     * is used to notify success or failure if the function returns true.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param callback Gatt callback handler that will receive asynchronous
-     *          callbacks.
-     * @return true, if application was successfully registered.
+     * @param callback GATT callback handler that will receive asynchronous callbacks.
+     * @return If true, the callback will be called to notify success or failure,
+     *         false on immediate error
      */
-    public boolean registerApp(BluetoothGattCallback callback) {
+    private boolean registerApp(BluetoothGattCallback callback) {
         if (DBG) Log.d(TAG, "registerApp()");
         if (mService == null) return false;
 
@@ -661,7 +622,7 @@
     /**
      * Unregister the current application and callbacks.
      */
-    public void unregisterApp() {
+    private void unregisterApp() {
         if (DBG) Log.d(TAG, "unregisterApp() - mClientIf=" + mClientIf);
         if (mService == null || mClientIf == 0) return;
 
@@ -675,77 +636,7 @@
     }
 
     /**
-     * Starts a scan for Bluetooth LE devices.
-     *
-     * <p>Results of the scan are reported using the
-     * {@link BluetoothGattCallback#onScanResult} callback.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @return true, if the scan was started successfully
-     */
-    public boolean startScan() {
-        if (DBG) Log.d(TAG, "startScan()");
-        if (mService == null || mClientIf == 0) return false;
-
-        try {
-            mService.startScan(mClientIf, false);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Starts a scan for Bluetooth LE devices, looking for devices that
-     * advertise given services.
-     *
-     * <p>Devices which advertise all specified services are reported using the
-     * {@link BluetoothGattCallback#onScanResult} callback.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param serviceUuids Array of services to look for
-     * @return true, if the scan was started successfully
-     */
-    public boolean startScan(UUID[] serviceUuids) {
-        if (DBG) Log.d(TAG, "startScan() - with UUIDs");
-        if (mService == null || mClientIf == 0) return false;
-
-        try {
-            ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length];
-            for(int i = 0; i != uuids.length; ++i) {
-                uuids[i] = new ParcelUuid(serviceUuids[i]);
-            }
-            mService.startScanWithUuids(mClientIf, false, uuids);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Stops an ongoing Bluetooth LE device scan.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     */
-    public void stopScan() {
-        if (DBG) Log.d(TAG, "stopScan()");
-        if (mService == null || mClientIf == 0) return;
-
-        try {
-            mService.stopScan(mClientIf, false);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-        }
-    }
-
-    /**
-     * Initiate a connection to a Bluetooth Gatt capable device.
+     * Initiate a connection to a Bluetooth GATT capable device.
      *
      * <p>The connection may not be established right away, but will be
      * completed when the remote device is available. A
@@ -757,7 +648,7 @@
      * when the remote device is in range/available. Generally, the first ever
      * connection to a device should be direct (autoConnect set to false) and
      * subsequent connections to known devices should be invoked with the
-     * autoConnect parameter set to false.
+     * autoConnect parameter set to true.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
@@ -767,18 +658,24 @@
      *                    device becomes available (true).
      * @return true, if the connection attempt was initiated successfully
      */
-    public boolean connect(BluetoothDevice device, boolean autoConnect) {
-        if (DBG) Log.d(TAG, "connect() - device: " + device.getAddress() + ", auto: " + autoConnect);
-        if (mService == null || mClientIf == 0) return false;
-
-        try {
-            mService.clientConnect(mClientIf, device.getAddress(),
-                                   autoConnect ? false : true); // autoConnect is inverse of "isDirect"
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
+    /*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback) {
+        if (DBG) Log.d(TAG, "connect() - device: " + mDevice.getAddress() + ", auto: " + autoConnect);
+        synchronized(mStateLock) {
+            if (mConnState != CONN_STATE_IDLE) {
+                throw new IllegalStateException("Not idle");
+            }
+            mConnState = CONN_STATE_CONNECTING;
+        }
+        if (!registerApp(callback)) {
+            synchronized(mStateLock) {
+                mConnState = CONN_STATE_IDLE;
+            }
+            Log.e(TAG, "Failed to register callback");
             return false;
         }
 
+        // the connection will continue after successful callback registration
+        mAutoConnect = autoConnect;
         return true;
     }
 
@@ -787,18 +684,17 @@
      * currently in progress.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param device Remote device
      */
-    public void cancelConnection(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "cancelOpen() - device: " + device.getAddress());
+    public void disconnect() {
+        if (DBG) Log.d(TAG, "cancelOpen() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return;
 
         try {
-            mService.clientDisconnect(mClientIf, device.getAddress());
+            mService.clientDisconnect(mClientIf, mDevice.getAddress());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
         }
+        // TBD deregister after conneciton is torn down
     }
 
     /**
@@ -812,17 +708,16 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param device Remote device to explore
      * @return true, if the remote service discovery has been started
      */
-    public boolean discoverServices(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "discoverServices() - device: " + device.getAddress());
+    public boolean discoverServices() {
+        if (DBG) Log.d(TAG, "discoverServices() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return false;
 
         mServices.clear();
 
         try {
-            mService.discoverServices(mClientIf, device.getAddress());
+            mService.discoverServices(mClientIf, mDevice.getAddress());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             return false;
@@ -839,16 +734,15 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param device Remote device
      * @return List of services on the remote device. Returns an empty list
      *         if service discovery has not yet been performed.
      */
-    public List<BluetoothGattService> getServices(BluetoothDevice device) {
+    public List<BluetoothGattService> getServices() {
         List<BluetoothGattService> result =
                 new ArrayList<BluetoothGattService>();
 
         for (BluetoothGattService service : mServices) {
-            if (service.getDevice().equals(device)) {
+            if (service.getDevice().equals(mDevice)) {
                 result.add(service);
             }
         }
@@ -868,14 +762,13 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param device Remote device
      * @param uuid UUID of the requested service
      * @return BluetoothGattService if supported, or null if the requested
      *         service is not offered by the remote device.
      */
-    public BluetoothGattService getService(BluetoothDevice device, UUID uuid) {
+    public BluetoothGattService getService(UUID uuid) {
         for (BluetoothGattService service : mServices) {
-            if (service.getDevice().equals(device) &&
+            if (service.getDevice().equals(mDevice) &&
                 service.getUuid().equals(uuid)) {
                 return service;
             }
@@ -923,8 +816,7 @@
     }
 
     /**
-     * Writes a given characteristic and it's values to the associated remote
-     * device.
+     * Writes a given characteristic and its values to the associated remote device.
      *
      * <p>Once the write operation has been completed, the
      * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked,
@@ -1061,15 +953,14 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param device Remote device
      * @return true, if the reliable write transaction has been initiated
      */
-    public boolean beginReliableWrite(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "beginReliableWrite() - device: " + device.getAddress());
+    public boolean beginReliableWrite() {
+        if (DBG) Log.d(TAG, "beginReliableWrite() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return false;
 
         try {
-            mService.beginReliableWrite(mClientIf, device.getAddress());
+            mService.beginReliableWrite(mClientIf, mDevice.getAddress());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             return false;
@@ -1089,15 +980,14 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param device Remote device
      * @return true, if the request to execute the transaction has been sent
      */
-    public boolean executeReliableWrite(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "executeReliableWrite() - device: " + device.getAddress());
+    public boolean executeReliableWrite() {
+        if (DBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return false;
 
         try {
-            mService.endReliableWrite(mClientIf, device.getAddress(), true);
+            mService.endReliableWrite(mClientIf, mDevice.getAddress(), true);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             return false;
@@ -1113,15 +1003,13 @@
      * operations for a given remote device.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param device Remote device
      */
-    public void abortReliableWrite(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "abortReliableWrite() - device: " + device.getAddress());
+    public void abortReliableWrite(BluetoothDevice mDevice) {
+        if (DBG) Log.d(TAG, "abortReliableWrite() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return;
 
         try {
-            mService.endReliableWrite(mClientIf, device.getAddress(), false);
+            mService.endReliableWrite(mClientIf, mDevice.getAddress(), false);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
         }
@@ -1172,12 +1060,12 @@
      * remote device.
      * @hide
      */
-    public boolean refresh(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "refresh() - device: " + device.getAddress());
+    public boolean refresh() {
+        if (DBG) Log.d(TAG, "refresh() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return false;
 
         try {
-            mService.refreshDevice(mClientIf, device.getAddress());
+            mService.refreshDevice(mClientIf, mDevice.getAddress());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             return false;
@@ -1194,15 +1082,14 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param device Remote device
      * @return true, if the RSSI value has been requested successfully
      */
-    public boolean readRemoteRssi(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "readRssi() - device: " + device.getAddress());
+    public boolean readRemoteRssi() {
+        if (DBG) Log.d(TAG, "readRssi() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return false;
 
         try {
-            mService.readRemoteRssi(mClientIf, device.getAddress());
+            mService.readRemoteRssi(mClientIf, mDevice.getAddress());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             return false;
@@ -1212,98 +1099,38 @@
     }
 
     /**
-     * Get the current connection state of the profile.
+     * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
+     * with {@link BluetoothProfile#GATT} as argument
      *
-     * <p>This is not specific to any application configuration but represents
-     * the connection state of the local Bluetooth adapter for this profile.
-     * This can be used by applications like status bar which would just like
-     * to know the state of the local adapter.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param device Remote bluetooth device.
-     * @return State of the profile connection. One of
-     *               {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
-     *               {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
+     * @throws UnsupportedOperationException
      */
     @Override
     public int getConnectionState(BluetoothDevice device) {
-        if (DBG) Log.d(TAG,"getConnectionState()");
-        if (mService == null) return STATE_DISCONNECTED;
-
-        List<BluetoothDevice> connectedDevices = getConnectedDevices();
-        for(BluetoothDevice connectedDevice : connectedDevices) {
-            if (device.equals(connectedDevice)) {
-                return STATE_CONNECTED;
-            }
-        }
-
-        return STATE_DISCONNECTED;
+        throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
     }
 
     /**
-     * Get connected devices for the Gatt profile.
+     * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
+     * with {@link BluetoothProfile#GATT} as argument
      *
-     * <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
-     *
-     * <p>This is not specific to any application configuration but represents
-     * the connection state of the local Bluetooth adapter for this profile.
-     * This can be used by applications like status bar which would just like
-     * to know the state of the local adapter.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @return List of devices. The list will be empty on error.
+     * @throws UnsupportedOperationException
      */
     @Override
     public List<BluetoothDevice> getConnectedDevices() {
-        if (DBG) Log.d(TAG,"getConnectedDevices");
-
-        List<BluetoothDevice> connectedDevices = new ArrayList<BluetoothDevice>();
-        if (mService == null) return connectedDevices;
-
-        try {
-            connectedDevices = mService.getDevicesMatchingConnectionStates(
-                new int[] { BluetoothProfile.STATE_CONNECTED });
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-        }
-
-        return connectedDevices;
+        throw new UnsupportedOperationException
+            ("Use BluetoothManager#getConnectedDevices instead.");
     }
 
     /**
-     * Get a list of devices that match any of the given connection
-     * states.
+     * Not supported - please use
+     * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])}
+     * with {@link BluetoothProfile#GATT} as first argument
      *
-     * <p> If none of the devices match any of the given states,
-     * an empty list will be returned.
-     *
-     * <p>This is not specific to any application configuration but represents
-     * the connection state of the local Bluetooth adapter for this profile.
-     * This can be used by applications like status bar which would just like
-     * to know the state of the local adapter.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param states Array of states. States can be one of
-     *              {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
-     *              {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
-     * @return List of devices. The list will be empty on error.
+     * @throws UnsupportedOperationException
      */
     @Override
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
-        if (DBG) Log.d(TAG,"getDevicesMatchingConnectionStates");
-
-        List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
-        if (mService == null) return devices;
-
-        try {
-            devices = mService.getDevicesMatchingConnectionStates(states);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-        }
-
-        return devices;
+        throw new UnsupportedOperationException
+            ("Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java
index afa4539..c9e5fea 100644
--- a/core/java/android/bluetooth/BluetoothGattCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattCallback.java
@@ -18,34 +18,10 @@
 
 import android.bluetooth.BluetoothDevice;
 
-import android.util.Log;
-
 /**
  * This abstract class is used to implement {@link BluetoothGatt} callbacks.
- * @hide
  */
 public abstract class BluetoothGattCallback {
-    /**
-     * Callback to inform change in registration state of the  application.
-     *
-     * @param status Returns {@link BluetoothGatt#GATT_SUCCESS} if the application
-     *               was successfully registered.
-     */
-    public void onAppRegistered(int status) {
-    }
-
-    /**
-     * Callback reporting an LE device found during a device scan initiated
-     * by the {@link BluetoothGatt#startScan} function.
-     *
-     * @param device Identifies the remote device
-     * @param rssi The RSSI value for the remote device as reported by the
-     *             Bluetooth hardware. 0 if no RSSI value is available.
-     * @param scanRecord The content of the advertisement record offered by
-     *                   the remote device.
-     */
-    public void onScanResult(BluetoothDevice device, int rssi, byte[] scanRecord) {
-    }
 
     /**
      * Callback indicating when a remote device has been connected or disconnected.
@@ -61,8 +37,8 @@
     }
 
     /**
-     * Callback invoked when the list of remote services, characteristics and
-     * descriptors for the remote device have been updated.
+     * Callback invoked when the list of remote services, characteristics and descriptors
+     * for the remote device have been updated, ie new services have been discovered.
      *
      * @param device Remote device
      * @param status {@link BluetoothGatt#GATT_SUCCESS} if the remote device
@@ -97,7 +73,7 @@
      * @param status The result of the write operation
      */
     public void onCharacteristicWrite(BluetoothGattCharacteristic characteristic,
-                               int status) {
+                                      int status) {
     }
 
     /**
@@ -113,23 +89,21 @@
      * Callback reporting the result of a descriptor read operation.
      *
      * @param descriptor Descriptor that was read from the associated
-     *                       remote device.
+     *                   remote device.
      * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation
      *               was completed successfully
      */
-    public void onDescriptorRead(BluetoothGattDescriptor descriptor,
-                                     int status) {
+    public void onDescriptorRead(BluetoothGattDescriptor descriptor, int status) {
     }
 
     /**
      * Callback indicating the result of a descriptor write operation.
      *
      * @param descriptor Descriptor that was writte to the associated
-     *                       remote device.
+     *                   remote device.
      * @param status The result of the write operation
      */
-    public void onDescriptorWrite(BluetoothGattDescriptor descriptor,
-                               int status) {
+    public void onDescriptorWrite(BluetoothGattDescriptor descriptor, int status) {
     }
 
     /**
@@ -150,7 +124,7 @@
      *
      * @param device Identifies the remote device
      * @param rssi The RSSI value for the remote device
-     * @param status 0 if the RSSI was read successfully
+     * @param status {@link BluetoothGatt#GATT_SUCCESS} if the RSSI was read successfully
      */
     public void onReadRemoteRssi(BluetoothDevice device, int rssi, int status) {
     }
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
index f44dc5c0..d63d97e 100644
--- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java
+++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
@@ -21,8 +21,7 @@
 import java.util.UUID;
 
 /**
- * Represents a Bluetooth Gatt Characteristic
- * @hide
+ * Represents a Bluetooth GATT Characteristic
  */
 public class BluetoothGattCharacteristic {
 
@@ -119,7 +118,7 @@
     public static final int WRITE_TYPE_NO_RESPONSE = 0x01;
 
     /**
-     * Write characteristic including and authenticated signature
+     * Write characteristic including authentication signature
      */
     public static final int WRITE_TYPE_SIGNED = 0x04;
 
@@ -219,12 +218,30 @@
     protected List<BluetoothGattDescriptor> mDescriptors;
 
     /**
+     * Create a new BluetoothGattCharacteristic.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param uuid The UUID for this characteristic
+     * @param properties Properties of this characteristic
+     * @param permissions Permissions for this characteristic
+     */
+    public BluetoothGattCharacteristic(UUID uuid, int properties, int permissions) {
+        initCharacteristic(null, uuid, 0, properties, permissions);
+    }
+
+    /**
      * Create a new BluetoothGattCharacteristic
      * @hide
      */
     /*package*/ BluetoothGattCharacteristic(BluetoothGattService service,
                                             UUID uuid, int instanceId,
                                             int properties, int permissions) {
+        initCharacteristic(service, uuid, instanceId, properties, permissions);
+    }
+
+    private void initCharacteristic(BluetoothGattService service,
+                                    UUID uuid, int instanceId,
+                                    int properties, int permissions) {
         mUuid = uuid;
         mInstance = instanceId;
         mProperties = properties;
@@ -249,11 +266,16 @@
     }
 
     /**
-     * Add a descriptor to this characteristic
-     * @hide
+     * Adds a descriptor to this characteristic.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param descriptor Descriptor to be added to this characteristic.
+     * @return true, if the descriptor was added to the characteristic
      */
-    /*package*/ void addDescriptor(BluetoothGattDescriptor descriptor) {
+    public boolean addDescriptor(BluetoothGattDescriptor descriptor) {
         mDescriptors.add(descriptor);
+        descriptor.setCharacteristic(this);
+        return true;
     }
 
     /**
@@ -265,8 +287,15 @@
     }
 
     /**
+     * Sets the service associated with this device.
+     * @hide
+     */
+    /*package*/ void setService(BluetoothGattService service) {
+        mService = service;
+    }
+
+    /**
      * Returns the UUID of this characteristic
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return UUID of this characteristic
      */
@@ -280,8 +309,6 @@
      * <p>If a remote device offers multiple characteristics with the same UUID,
      * the instance ID is used to distuinguish between characteristics.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @return Instance ID of this characteristic
      */
     public int getInstanceId() {
@@ -294,8 +321,6 @@
      * <p>The properties contain a bit mask of property flags indicating
      * the features of this characteristic.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @return Properties of this characteristic
      */
     public int getProperties() {
@@ -304,7 +329,6 @@
 
     /**
      * Returns the permissions for this characteristic.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return Permissions of this characteristic
      */
@@ -314,7 +338,6 @@
 
     /**
      * Gets the write type for this characteristic.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return Write type for this characteristic
      */
@@ -329,11 +352,6 @@
      * {@link BluetoothGatt#writeCharacteristic} function write this
      * characteristic.
      *
-     * <p>The default write type for a characteristic is
-     * {@link #WRITE_TYPE_DEFAULT}.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @param writeType The write type to for this characteristic. Can be one
      *                  of:
      *                  {@link #WRITE_TYPE_DEFAULT},
@@ -345,8 +363,15 @@
     }
 
     /**
+     * Set the desired key size.
+     * @hide
+     */
+    public void setKeySize(int keySize) {
+        mKeySize = keySize;
+    }
+
+    /**
      * Returns a list of descriptors for this characteristic.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return Descriptors for this characteristic
      */
@@ -358,9 +383,7 @@
      * Returns a descriptor with a given UUID out of the list of
      * descriptors for this characteristic.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @return Gatt descriptor object or null if no descriptor with the
+     * @return GATT descriptor object or null if no descriptor with the
      *         given UUID was found.
      */
     public BluetoothGattDescriptor getDescriptor(UUID uuid) {
@@ -376,12 +399,10 @@
      * Get the stored value for this characteristic.
      *
      * <p>This function returns the stored value for this characteristic as
-     * retrieved by calling {@link BluetoothGatt#readCharacteristic}. To cached
+     * retrieved by calling {@link BluetoothGatt#readCharacteristic}. The cached
      * value of the characteristic is updated as a result of a read characteristic
      * operation or if a characteristic update notification has been received.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @return Cached value of the characteristic
      */
     public byte[] getValue() {
@@ -397,8 +418,6 @@
      * characteristic value at the given offset are interpreted to generate the
      * return value.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @param formatType The format type used to interpret the characteristic
      *                   value.
      * @param offset Offset at which the integer value can be found.
@@ -436,7 +455,6 @@
     /**
      * Return the stored value of this characteristic.
      * <p>See {@link #getValue} for details.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @param formatType The format type used to interpret the characteristic
      *                   value.
@@ -462,7 +480,7 @@
     /**
      * Return the stored value of this characteristic.
      * <p>See {@link #getValue} for details.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
      * @param offset Offset at which the string value can be found.
      * @return Cached value of the characteristic
      */
@@ -481,8 +499,6 @@
      * {@link BluetoothGatt#writeCharacteristic} to send the value to the
      * remote device.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @param value New value for this characteristic
      * @return true if the locally stored value has been set, false if the
      *              requested value could not be stored locally.
@@ -495,7 +511,6 @@
     /**
      * Set the locally stored value of this characteristic.
      * <p>See {@link #setValue(byte[])} for details.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @param value New value for this characteristic
      * @param formatType Integer format type used to transform the value parameter
@@ -542,7 +557,7 @@
     /**
      * Set the locally stored value of this characteristic.
      * <p>See {@link #setValue(byte[])} for details.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
      * @param mantissa Mantissa for this characteristic
      * @param exponent  exponent value for this characteristic
      * @param formatType Float format type used to transform the value parameter
@@ -582,7 +597,7 @@
     /**
      * Set the locally stored value of this characteristic.
      * <p>See {@link #setValue(byte[])} for details.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
      * @param value New value for this characteristic
      * @return true if the locally stored value has been set
      */
@@ -593,7 +608,6 @@
 
     /**
      * Returns the size of a give value type.
-     * @hide
      */
     private int getTypeLen(int formatType) {
         return formatType & 0xF;
@@ -601,7 +615,6 @@
 
     /**
      * Convert a signed byte to an unsigned int.
-     * @hide
      */
     private int unsignedByteToInt(byte b) {
         return b & 0xFF;
@@ -609,7 +622,6 @@
 
     /**
      * Convert signed bytes to a 16-bit unsigned int.
-     * @hide
      */
     private int unsignedBytesToInt(byte b0, byte b1) {
         return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8));
@@ -617,7 +629,6 @@
 
     /**
      * Convert signed bytes to a 32-bit unsigned int.
-     * @hide
      */
     private int unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3) {
         return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8))
@@ -626,7 +637,6 @@
 
     /**
      * Convert signed bytes to a 16-bit short float value.
-     * @hide
      */
     private float bytesToFloat(byte b0, byte b1) {
         int mantissa = unsignedToSigned(unsignedByteToInt(b0)
@@ -637,7 +647,6 @@
 
     /**
      * Convert signed bytes to a 32-bit short float value.
-     * @hide
      */
     private float bytesToFloat(byte b0, byte b1, byte b2, byte b3) {
         int mantissa = unsignedToSigned(unsignedByteToInt(b0)
@@ -649,7 +658,6 @@
     /**
      * Convert an unsigned integer value to a two's-complement encoded
      * signed value.
-     * @hide
      */
     private int unsignedToSigned(int unsigned, int size) {
         if ((unsigned & (1 << size-1)) != 0) {
@@ -660,7 +668,6 @@
 
     /**
      * Convert an integer into the signed bits of a given length.
-     * @hide
      */
     private int intToSignedBits(int i, int size) {
         if (i < 0) {
diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java
index ba1f28a..6ba2db7 100644
--- a/core/java/android/bluetooth/BluetoothGattDescriptor.java
+++ b/core/java/android/bluetooth/BluetoothGattDescriptor.java
@@ -19,8 +19,7 @@
 import java.util.UUID;
 
 /**
- * Represents a Bluetooth Gatt Descriptor
- * @hide
+ * Represents a Bluetooth GATT Descriptor
  */
 public class BluetoothGattDescriptor {
 
@@ -109,12 +108,28 @@
      * Create a new BluetoothGattDescriptor.
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
+     * @param uuid The UUID for this descriptor
+     * @param permissions Permissions for this descriptor
+     */
+    public BluetoothGattDescriptor(UUID uuid, int permissions) {
+        initDescriptor(null, uuid, permissions);
+    }
+
+    /**
+     * Create a new BluetoothGattDescriptor.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
      * @param characteristic The characteristic this descriptor belongs to
      * @param uuid The UUID for this descriptor
      * @param permissions Permissions for this descriptor
      */
     /*package*/ BluetoothGattDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid,
                                     int permissions) {
+        initDescriptor(characteristic, uuid, permissions);
+    }
+
+    private void initDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid,
+                                int permissions) {
         mCharacteristic = characteristic;
         mUuid = uuid;
         mPermissions = permissions;
@@ -129,8 +144,15 @@
     }
 
     /**
+     * Set the back-reference to the associated characteristic
+     * @hide
+     */
+    /*package*/ void setCharacteristic(BluetoothGattCharacteristic characteristic) {
+        mCharacteristic = characteristic;
+    }
+
+    /**
      * Returns the UUID of this descriptor.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return UUID of this descriptor
      */
@@ -140,7 +162,6 @@
 
     /**
      * Returns the permissions for this descriptor.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return Permissions of this descriptor
      */
@@ -152,12 +173,10 @@
      * Returns the stored value for this descriptor
      *
      * <p>This function returns the stored value for this descriptor as
-     * retrieved by calling {@link BluetoothGatt#readDescriptor}. To cached
+     * retrieved by calling {@link BluetoothGatt#readDescriptor}. The cached
      * value of the descriptor is updated as a result of a descriptor read
      * operation.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @return Cached value of the descriptor
      */
     public byte[] getValue() {
@@ -172,8 +191,6 @@
      * {@link BluetoothGatt#writeDescriptor} to send the value to the
      * remote device.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @param value New value for this descriptor
      * @return true if the locally stored value has been set, false if the
      *              requested value could not be stored locally.
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 6b69377..d1f4b82 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -38,88 +38,30 @@
 import java.util.UUID;
 
 /**
- * Public API for the Bluetooth Gatt Profile server role.
+ * Public API for the Bluetooth GATT Profile server role.
  *
- * <p>This class provides Bluetooth Gatt server role functionality,
+ * <p>This class provides Bluetooth GATT server role functionality,
  * allowing applications to create and advertise Bluetooth Smart services
  * and characteristics.
  *
  * <p>BluetoothGattServer is a proxy object for controlling the Bluetooth Service
  * via IPC.  Use {@link BluetoothAdapter#getProfileProxy} to get the
  * BluetoothGatt proxy object.
- * @hide
  */
 public final class BluetoothGattServer implements BluetoothProfile {
     private static final String TAG = "BluetoothGattServer";
     private static final boolean DBG = true;
 
-    private Context mContext;
-    private ServiceListener mServiceListener;
+    private final Context mContext;
     private BluetoothAdapter mAdapter;
     private IBluetoothGatt mService;
     private BluetoothGattServerCallback mCallback;
-    private int mServerIf;
 
+    private Object mServerIfLock = new Object();
+    private int mServerIf;
     private List<BluetoothGattService> mServices;
 
-    /**
-     * Bluetooth state change handlers
-     */
-    private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
-        new IBluetoothStateChangeCallback.Stub() {
-            public void onBluetoothStateChange(boolean up) {
-                if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
-                if (!up) {
-                    if (DBG) Log.d(TAG,"Unbinding service...");
-                    synchronized (mConnection) {
-                        try {
-                            mService = null;
-                            mContext.unbindService(mConnection);
-                        } catch (Exception re) {
-                            Log.e(TAG,"",re);
-                        }
-                    }
-                } else {
-                    synchronized (mConnection) {
-                        try {
-                            if (mService == null) {
-                                if (DBG) Log.d(TAG,"Binding service...");
-                                if (!mContext.bindService(new
-                                        Intent(IBluetoothGatt.class.getName()),
-                                        mConnection, 0)) {
-                                    Log.e(TAG, "Could not bind to Bluetooth GATT Service");
-                                }
-                            }
-                        } catch (Exception re) {
-                            Log.e(TAG,"",re);
-                        }
-                    }
-                }
-            }
-        };
-
-    /**
-     * Service binder handling
-     */
-    private ServiceConnection mConnection = new ServiceConnection() {
-            public void onServiceConnected(ComponentName className, IBinder service) {
-                if (DBG) Log.d(TAG, "Proxy object connected");
-                mService = IBluetoothGatt.Stub.asInterface(service);
-                ServiceListener serviceListner = mServiceListener;
-                if (serviceListner != null) {
-                    serviceListner.onServiceConnected(BluetoothProfile.GATT_SERVER,
-                                                      BluetoothGattServer.this);
-                }
-            }
-            public void onServiceDisconnected(ComponentName className) {
-                if (DBG) Log.d(TAG, "Proxy object disconnected");
-                mService = null;
-                ServiceListener serviceListner = mServiceListener;
-                if (serviceListner != null) {
-                    serviceListner.onServiceDisconnected(BluetoothProfile.GATT_SERVER);
-                }
-            }
-        };
+    private static final int CALLBACK_REG_TIMEOUT = 10000;
 
     /**
      * Bluetooth GATT interface callbacks
@@ -133,11 +75,14 @@
             public void onServerRegistered(int status, int serverIf) {
                 if (DBG) Log.d(TAG, "onServerRegistered() - status=" + status
                     + " serverIf=" + serverIf);
-                mServerIf = serverIf;
-                try {
-                    mCallback.onAppRegistered(status);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                synchronized(mServerIfLock) {
+                    if (mCallback != null) {
+                        mServerIf = serverIf;
+                        mServerIfLock.notify();
+                    } else {
+                        // registration timeout
+                        Log.e(TAG, "onServerRegistered: mCallback is null");
+                    }
                 }
             }
 
@@ -147,13 +92,7 @@
              */
             public void onScanResult(String address, int rssi, byte[] advData) {
                 if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
-
-                try {
-                    mCallback.onScanResult(mAdapter.getRemoteDevice(address),
-                                           rssi, advData);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
-                }
+                // no op
             }
 
             /**
@@ -209,8 +148,7 @@
                 BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
                 if (service == null) return;
 
-                BluetoothGattCharacteristic characteristic = service.getCharacteristic(
-                    charUuid);
+                BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);
                 if (characteristic == null) return;
 
                 try {
@@ -340,31 +278,13 @@
     /**
      * Create a BluetoothGattServer proxy object.
      */
-    /*package*/ BluetoothGattServer(Context context, ServiceListener l) {
+    /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt) {
         mContext = context;
-        mServiceListener = l;
+        mService = iGatt;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
+        mCallback = null;
+        mServerIf = 0;
         mServices = new ArrayList<BluetoothGattService>();
-
-        IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE);
-        if (b != null) {
-            IBluetoothManager mgr = IBluetoothManager.Stub.asInterface(b);
-            try {
-                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
-            } catch (RemoteException re) {
-                Log.e(TAG, "Unable to register BluetoothStateChangeCallback", re);
-            }
-        } else {
-            Log.e(TAG, "Unable to get BluetoothManager interface.");
-            throw new RuntimeException("BluetoothManager inactive");
-        }
-
-        //Bind to the service only if the Bluetooth is ON
-        if(mAdapter.isEnabled()){
-            if (!context.bindService(new Intent(IBluetoothGatt.class.getName()), mConnection, 0)) {
-                Log.e(TAG, "Could not bind to Bluetooth Gatt Service");
-            }
-        }
     }
 
     /**
@@ -372,29 +292,75 @@
      */
     /*package*/ void close() {
         if (DBG) Log.d(TAG, "close()");
+        unregisterCallback();
+    }
 
-        unregisterApp();
-        mServiceListener = null;
+    /**
+     * Register an application callback to start using GattServer.
+     *
+     * <p>This is an asynchronous call. The callback is used to notify
+     * success or failure if the function returns true.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param callback GATT callback handler that will receive asynchronous
+     *                 callbacks.
+     * @return true, the callback will be called to notify success or failure,
+     *         false on immediate error
+     */
+    /*package*/ boolean registerCallback(BluetoothGattServerCallback callback) {
+        if (DBG) Log.d(TAG, "registerCallback()");
+        if (mService == null) {
+            Log.e(TAG, "GATT service not available");
+            return false;
+        }
+        UUID uuid = UUID.randomUUID();
+        if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid);
 
-        IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE);
-        if (b != null) {
-            IBluetoothManager mgr = IBluetoothManager.Stub.asInterface(b);
+        synchronized(mServerIfLock) {
+            if (mCallback != null) {
+                Log.e(TAG, "App can register callback only once");
+                return false;
+            }
+
+            mCallback = callback;
             try {
-                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
-            } catch (RemoteException re) {
-                Log.e(TAG, "Unable to unregister BluetoothStateChangeCallback", re);
+                mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG,"",e);
+                mCallback = null;
+                return false;
+            }
+
+            try {
+                mServerIfLock.wait(CALLBACK_REG_TIMEOUT);
+            } catch (InterruptedException e) {
+                Log.e(TAG, "" + e);
+                mCallback = null;
+            }
+
+            if (mServerIf == 0) {
+                mCallback = null;
+                return false;
+            } else {
+                return true;
             }
         }
+    }
 
-        synchronized (mConnection) {
-            if (mService != null) {
-                try {
-                    mService = null;
-                    mContext.unbindService(mConnection);
-                } catch (Exception re) {
-                    Log.e(TAG,"",re);
-                }
-            }
+    /**
+     * Unregister the current application and callbacks.
+     */
+    private void unregisterCallback() {
+        if (DBG) Log.d(TAG, "unregisterCallback() - mServerIf=" + mServerIf);
+        if (mService == null || mServerIf == 0) return;
+
+        try {
+            mCallback = null;
+            mService.unregisterServer(mServerIf);
+            mServerIf = 0;
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
         }
     }
 
@@ -414,123 +380,7 @@
     }
 
     /**
-     * Register an application callback to start using Gatt.
-     *
-     * <p>This is an asynchronous call. The callback is used to notify
-     * success or failure if the function returns true.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param callback Gatt callback handler that will receive asynchronous
-     *          callbacks.
-     * @return true, if application was successfully registered.
-     */
-    public boolean registerApp(BluetoothGattServerCallback callback) {
-        if (DBG) Log.d(TAG, "registerApp()");
-        if (mService == null) return false;
-
-        mCallback = callback;
-        UUID uuid = UUID.randomUUID();
-        if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid);
-
-        try {
-            mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Unregister the current application and callbacks.
-     */
-    public void unregisterApp() {
-        if (DBG) Log.d(TAG, "unregisterApp() - mServerIf=" + mServerIf);
-        if (mService == null || mServerIf == 0) return;
-
-        try {
-            mCallback = null;
-            mService.unregisterServer(mServerIf);
-            mServerIf = 0;
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-        }
-    }
-
-    /**
-     * Starts a scan for Bluetooth LE devices.
-     *
-     * <p>Results of the scan are reported using the
-     * {@link BluetoothGattServerCallback#onScanResult} callback.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @return true, if the scan was started successfully
-     */
-    public boolean startScan() {
-        if (DBG) Log.d(TAG, "startScan()");
-        if (mService == null || mServerIf == 0) return false;
-
-        try {
-            mService.startScan(mServerIf, true);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Starts a scan for Bluetooth LE devices, looking for devices that
-     * advertise given services.
-     *
-     * <p>Devices which advertise all specified services are reported using the
-     * {@link BluetoothGattServerCallback#onScanResult} callback.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param serviceUuids Array of services to look for
-     * @return true, if the scan was started successfully
-     */
-    public boolean startScan(UUID[] serviceUuids) {
-        if (DBG) Log.d(TAG, "startScan() - with UUIDs");
-        if (mService == null || mServerIf == 0) return false;
-
-        try {
-            ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length];
-            for(int i = 0; i != uuids.length; ++i) {
-                uuids[i] = new ParcelUuid(serviceUuids[i]);
-            }
-            mService.startScanWithUuids(mServerIf, true, uuids);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Stops an ongoing Bluetooth LE device scan.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     */
-    public void stopScan() {
-        if (DBG) Log.d(TAG, "stopScan()");
-        if (mService == null || mServerIf == 0) return;
-
-        try {
-            mService.stopScan(mServerIf, true);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-        }
-    }
-
-    /**
-     * Initiate a connection to a Bluetooth Gatt capable device.
+     * Initiate a connection to a Bluetooth GATT capable device.
      *
      * <p>The connection may not be established right away, but will be
      * completed when the remote device is available. A
@@ -542,11 +392,10 @@
      * when the remote device is in range/available. Generally, the first ever
      * connection to a device should be direct (autoConnect set to false) and
      * subsequent connections to known devices should be invoked with the
-     * autoConnect parameter set to false.
+     * autoConnect parameter set to true.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param device Remote device to connect to
      * @param autoConnect Whether to directly connect to the remote device (false)
      *                    or to automatically connect as soon as the remote
      *                    device becomes available (true).
@@ -590,7 +439,7 @@
      * Send a response to a read or write request to a remote device.
      *
      * <p>This function must be invoked in when a remote read/write request
-     * is received by one of these callback methots:
+     * is received by one of these callback methods:
      *
      * <ul>
      *      <li>{@link BluetoothGattServerCallback#onCharacteristicReadRequest}
@@ -662,17 +511,17 @@
     }
 
     /**
-     * Add a service to the list of services to be advertised.
+     * Add a service to the list of services to be hosted.
      *
      * <p>Once a service has been addded to the the list, the service and it's
-     * included characteristics will be advertised by the local device.
+     * included characteristics will be provided by the local device.
      *
-     * <p>If the local device is already advertising services when this function
+     * <p>If the local device has already exposed services when this function
      * is called, a service update notification will be sent to all clients.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param service Service to be added to the list of services advertised
+     * @param service Service to be added to the list of services provided
      *                by this device.
      * @return true, if the service has been added successfully
      */
@@ -721,11 +570,11 @@
     }
 
     /**
-     * Removes a service from the list of services to be advertised.
+     * Removes a service from the list of services to be provided.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param service Service to beremoved.
+     * @param service Service to be removed.
      * @return true, if the service has been removed
      */
     public boolean removeService(BluetoothGattService service) {
@@ -749,7 +598,7 @@
     }
 
     /**
-     * Remove all services from the list of advertised services.
+     * Remove all services from the list of provided services.
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      */
     public void clearServices() {
@@ -765,7 +614,7 @@
     }
 
     /**
-     * Returns a list of GATT services offered bu this device.
+     * Returns a list of GATT services offered by this device.
      *
      * <p>An application must call {@link #addService} to add a serice to the
      * list of services offered by this device.
@@ -802,99 +651,40 @@
         return null;
     }
 
+
     /**
-     * Get the current connection state of the profile.
+     * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
+     * with {@link BluetoothProfile#GATT} as argument
      *
-     * <p>This is not specific to any application configuration but represents
-     * the connection state of the local Bluetooth adapter for this profile.
-     * This can be used by applications like status bar which would just like
-     * to know the state of the local adapter.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param device Remote bluetooth device.
-     * @return State of the profile connection. One of
-     *               {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
-     *               {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
+     * @throws UnsupportedOperationException
      */
     @Override
     public int getConnectionState(BluetoothDevice device) {
-        if (DBG) Log.d(TAG,"getConnectionState()");
-        if (mService == null) return STATE_DISCONNECTED;
-
-        List<BluetoothDevice> connectedDevices = getConnectedDevices();
-        for(BluetoothDevice connectedDevice : connectedDevices) {
-            if (device.equals(connectedDevice)) {
-                return STATE_CONNECTED;
-            }
-        }
-
-        return STATE_DISCONNECTED;
+        throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
     }
 
     /**
-     * Get connected devices for the Gatt profile.
+     * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
+     * with {@link BluetoothProfile#GATT} as argument
      *
-     * <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
-     *
-     * <p>This is not specific to any application configuration but represents
-     * the connection state of the local Bluetooth adapter for this profile.
-     * This can be used by applications like status bar which would just like
-     * to know the state of the local adapter.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @return List of devices. The list will be empty on error.
+     * @throws UnsupportedOperationException
      */
     @Override
     public List<BluetoothDevice> getConnectedDevices() {
-        if (DBG) Log.d(TAG,"getConnectedDevices");
-
-        List<BluetoothDevice> connectedDevices = new ArrayList<BluetoothDevice>();
-        if (mService == null) return connectedDevices;
-
-        try {
-            connectedDevices = mService.getDevicesMatchingConnectionStates(
-                new int[] { BluetoothProfile.STATE_CONNECTED });
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-        }
-
-        return connectedDevices;
+        throw new UnsupportedOperationException
+            ("Use BluetoothManager#getConnectedDevices instead.");
     }
 
     /**
-     * Get a list of devices that match any of the given connection
-     * states.
+     * Not supported - please use
+     * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])}
+     * with {@link BluetoothProfile#GATT} as first argument
      *
-     * <p> If none of the devices match any of the given states,
-     * an empty list will be returned.
-     *
-     * <p>This is not specific to any application configuration but represents
-     * the connection state of the local Bluetooth adapter for this profile.
-     * This can be used by applications like status bar which would just like
-     * to know the state of the local adapter.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param states Array of states. States can be one of
-     *              {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
-     *              {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
-     * @return List of devices. The list will be empty on error.
+     * @throws UnsupportedOperationException
      */
     @Override
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
-        if (DBG) Log.d(TAG,"getDevicesMatchingConnectionStates");
-
-        List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
-        if (mService == null) return devices;
-
-        try {
-            devices = mService.getDevicesMatchingConnectionStates(states);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-        }
-
-        return devices;
+        throw new UnsupportedOperationException
+            ("Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothGattServerCallback.java b/core/java/android/bluetooth/BluetoothGattServerCallback.java
index 4f608ff..f9f1d97 100644
--- a/core/java/android/bluetooth/BluetoothGattServerCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattServerCallback.java
@@ -22,30 +22,8 @@
 
 /**
  * This abstract class is used to implement {@link BluetoothGattServer} callbacks.
- * @hide
  */
 public abstract class BluetoothGattServerCallback {
-    /**
-     * Callback to inform change in registration state of the  application.
-     *
-     * @param status Returns {@link BluetoothGatt#GATT_SUCCESS} if the application
-     *               was successfully registered.
-     */
-    public void onAppRegistered(int status) {
-    }
-
-    /**
-     * Callback reporting an LE device found during a device scan initiated
-     * by the {@link BluetoothGattServer#startScan} function.
-     *
-     * @param device Identifies the remote device
-     * @param rssi The RSSI value for the remote device as reported by the
-     *             Bluetooth hardware. 0 if no RSSI value is available.
-     * @param scanRecord The content of the advertisement record offered by
-     *                   the remote device.
-     */
-    public void onScanResult(BluetoothDevice device, int rssi, byte[] scanRecord) {
-    }
 
     /**
      * Callback indicating when a remote device has been connected or disconnected.
@@ -101,9 +79,9 @@
      * @param value The value the client wants to assign to the characteristic
      */
     public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
-                            BluetoothGattCharacteristic characteristic,
-                            boolean preparedWrite, boolean responseNeeded,
-                            int offset, byte[] value) {
+                                             BluetoothGattCharacteristic characteristic,
+                                             boolean preparedWrite, boolean responseNeeded,
+                                             int offset, byte[] value) {
     }
 
     /**
@@ -118,7 +96,7 @@
      * @param descriptor Descriptor to be read
      */
     public void onDescriptorReadRequest(BluetoothDevice device, int requestId,
-                            int offset, BluetoothGattDescriptor descriptor) {
+                                        int offset, BluetoothGattDescriptor descriptor) {
     }
 
     /**
@@ -137,9 +115,9 @@
      * @param value The value the client wants to assign to the descriptor
      */
     public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
-                            BluetoothGattDescriptor descriptor,
-                            boolean preparedWrite, boolean responseNeeded,
-                            int offset,  byte[] value) {
+                                         BluetoothGattDescriptor descriptor,
+                                         boolean preparedWrite, boolean responseNeeded,
+                                         int offset,  byte[] value) {
     }
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothGattService.java b/core/java/android/bluetooth/BluetoothGattService.java
index 6a3ce66e..c3b3cfe 100644
--- a/core/java/android/bluetooth/BluetoothGattService.java
+++ b/core/java/android/bluetooth/BluetoothGattService.java
@@ -22,8 +22,7 @@
 import java.util.UUID;
 
 /**
- * Represents a Bluetooth Gatt Service
- * @hide
+ * Represents a Bluetooth GATT Service
  */
 public class BluetoothGattService {
 
@@ -81,9 +80,14 @@
 
     /**
      * Create a new BluetoothGattService.
-     * @hide
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param uuid The UUID for this service
+     * @param serviceType The type of this service,
+     *        {@link BluetoothGattService#SERVICE_TYPE_PRIMARY} or
+     *        {@link BluetoothGattService#SERVICE_TYPE_SECONDARY}
      */
-    /*package*/ BluetoothGattService(UUID uuid, int serviceType) {
+    public BluetoothGattService(UUID uuid, int serviceType) {
         mDevice = null;
         mUuid = uuid;
         mInstanceId = 0;
@@ -115,11 +119,28 @@
     }
 
     /**
-     * Add a characteristic to this service.
-     * @hide
+     * Add an included service to this service.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param service The service to be added
+     * @return true, if the included service was added to the service
      */
-    /*package*/ void addCharacteristic(BluetoothGattCharacteristic characteristic) {
+    public boolean addService(BluetoothGattService service) {
+        mIncludedServices.add(service);
+        return true;
+    }
+
+    /**
+     * Add a characteristic to this service.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param characteristic The characteristics to be added
+     * @return true, if the characteristic was added to the service
+     */
+    public boolean addCharacteristic(BluetoothGattCharacteristic characteristic) {
         mCharacteristics.add(characteristic);
+        characteristic.setService(this);
+        return true;
     }
 
     /**
@@ -136,6 +157,15 @@
     }
 
     /**
+     * Force the instance ID.
+     * This is needed for conformance testing only.
+     * @hide
+     */
+    public void setInstanceId(int instanceId) {
+        mInstanceId = instanceId;
+    }
+
+    /**
      * Get the handle count override (conformance testing.
      * @hide
      */
@@ -144,6 +174,15 @@
     }
 
     /**
+     * Force the number of handles to reserve for this service.
+     * This is needed for conformance testing only.
+     * @hide
+     */
+    public void setHandles(int handles) {
+        mHandles = handles;
+    }
+
+    /**
      * Add an included service to the internal map.
      * @hide
      */
@@ -153,7 +192,6 @@
 
     /**
      * Returns the UUID of this service
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return UUID of this service
      */
@@ -168,8 +206,6 @@
      * (ex. multiple battery services for different batteries), the instance
      * ID is used to distuinguish services.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @return Instance ID of this service
      */
     public int getInstanceId() {
@@ -178,15 +214,13 @@
 
     /**
      * Get the type of this service (primary/secondary)
-     * @hide
      */
     public int getType() {
         return mServiceType;
     }
 
     /**
-     * Get the list of included Gatt services for this service.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     * Get the list of included GATT services for this service.
      *
      * @return List of included services or empty list if no included services
      *         were discovered.
@@ -197,7 +231,6 @@
 
     /**
      * Returns a list of characteristics included in this service.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return Characteristics included in this service
      */
@@ -217,9 +250,7 @@
      * UUID, the first instance of a characteristic with the given UUID
      * is returned.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @return Gatt characteristic object or null if no characteristic with the
+     * @return GATT characteristic object or null if no characteristic with the
      *         given UUID was found.
      */
     public BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
new file mode 100644
index 0000000..19083b5
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2013 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.content.Context;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * High level manager used to obtain an instance of an {@link BluetoothAdapter}
+ * and to conduct overall Bluetooth Management.
+ * <p>
+ * Use {@link android.content.Context#getSystemService(java.lang.String)}
+ * with {@link Context#BLUETOOTH_SERVICE} to create an {@link BluetoothManager},
+ * then call {@link #getAdapter} to obtain the {@link BluetoothAdapter}.
+ * <p>
+ * Alternately, you can just call the static helper
+ * {@link BluetoothAdapter#getDefaultAdapter()}.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about using BLUETOOTH, read the
+ * <a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide.</p>
+ * </div>
+ *
+ * @see Context#getSystemService
+ * @see BluetoothAdapter#getDefaultAdapter()
+ */
+public final class BluetoothManager {
+    private static final String TAG = "BluetoothManager";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = true;
+
+    private final BluetoothAdapter mAdapter;
+
+    /**
+     * @hide
+     */
+    public BluetoothManager(Context context) {
+        context = context.getApplicationContext();
+        if (context == null) {
+            throw new IllegalArgumentException(
+                    "context not associated with any application (using a mock context?)");
+        }
+        // Legacy api - getDefaultAdapter does not take in the context
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
+    }
+
+    /**
+     * Get the default BLUETOOTH Adapter for this device.
+     *
+     * @return the default BLUETOOTH Adapter
+     */
+    public BluetoothAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Get the current connection state of the profile to the remote device.
+     *
+     * <p>This is not specific to any application configuration but represents
+     * the connection state of the local Bluetooth adapter for certain profile.
+     * This can be used by applications like status bar which would just like
+     * to know the state of Bluetooth.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param device Remote bluetooth device.
+     * @param profile GATT or GATT_SERVER
+     * @return State of the profile connection. One of
+     *         {@link BluetoothProfile#STATE_CONNECTED}, {@link BluetoothProfile#STATE_CONNECTING},
+     *         {@link BluetoothProfile#STATE_DISCONNECTED},
+     *         {@link BluetoothProfile#STATE_DISCONNECTING}
+     */
+    public int getConnectionState(BluetoothDevice device, int profile) {
+        if (DBG) Log.d(TAG,"getConnectionState()");
+
+        List<BluetoothDevice> connectedDevices = getConnectedDevices(profile);
+        for(BluetoothDevice connectedDevice : connectedDevices) {
+            if (device.equals(connectedDevice)) {
+                return BluetoothProfile.STATE_CONNECTED;
+            }
+        }
+
+        return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    /**
+     * Get connected devices for the specified profile.
+     *
+     * <p> Return the set of devices which are in state {@link BluetoothProfile#STATE_CONNECTED}
+     *
+     * <p>This is not specific to any application configuration but represents
+     * the connection state of Bluetooth for this profile.
+     * This can be used by applications like status bar which would just like
+     * to know the state of Bluetooth.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param profile GATT or GATT_SERVER
+     * @return List of devices. The list will be empty on error.
+     */
+    public List<BluetoothDevice> getConnectedDevices(int profile) {
+        if (DBG) Log.d(TAG,"getConnectedDevices");
+        if (profile != BluetoothProfile.GATT && profile != BluetoothProfile.GATT_SERVER) {
+            throw new IllegalArgumentException("Profile not supported: " + profile);
+        }
+
+        List<BluetoothDevice> connectedDevices = new ArrayList<BluetoothDevice>();
+
+        try {
+            IBluetoothManager managerService = mAdapter.getBluetoothManager();
+            IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
+            if (iGatt == null) return connectedDevices;
+
+            connectedDevices = iGatt.getDevicesMatchingConnectionStates(
+                new int[] { BluetoothProfile.STATE_CONNECTED });
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+        }
+
+        return connectedDevices;
+    }
+
+    /**
+     * 
+     * Get a list of devices that match any of the given connection
+     * states.
+     *
+     * <p> If none of the devices match any of the given states,
+     * an empty list will be returned.
+     *
+     * <p>This is not specific to any application configuration but represents
+     * the connection state of the local Bluetooth adapter for this profile.
+     * This can be used by applications like status bar which would just like
+     * to know the state of the local adapter.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param profile GATT or GATT_SERVER
+     * @param states Array of states. States can be one of
+     *        {@link BluetoothProfile#STATE_CONNECTED}, {@link BluetoothProfile#STATE_CONNECTING},
+     *        {@link BluetoothProfile#STATE_DISCONNECTED},
+     *        {@link BluetoothProfile#STATE_DISCONNECTING},
+     * @return List of devices. The list will be empty on error.
+     */
+    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int profile, int[] states) {
+        if (DBG) Log.d(TAG,"getDevicesMatchingConnectionStates");
+
+        if (profile != BluetoothProfile.GATT && profile != BluetoothProfile.GATT_SERVER) {
+            throw new IllegalArgumentException("Profile not supported: " + profile);
+        }
+
+        List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
+
+        try {
+            IBluetoothManager managerService = mAdapter.getBluetoothManager();
+            IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
+            if (iGatt == null) return devices;
+            devices = iGatt.getDevicesMatchingConnectionStates(states);
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+        }
+
+        return devices;
+    }
+
+    /**
+     * Open a GATT Server
+     * The callback is used to deliver results to Caller, such as connection status as well
+     * as the results of any other GATT server operations.
+     * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer
+     * to conduct GATT server operations.
+     * @param context App context
+     * @param callback GATT server callback handler that will receive asynchronous callbacks.
+     * @return BluetoothGattServer instance
+     */
+    public BluetoothGattServer openGattServer(Context context,
+                                              BluetoothGattServerCallback callback) {
+        if (context == null || callback == null) {
+            throw new IllegalArgumentException("null parameter: " + context + " " + callback);
+        }
+
+        // TODO(Bluetooth) check whether platform support BLE
+        //     Do the check here or in GattServer?
+
+        try {
+            IBluetoothManager managerService = mAdapter.getBluetoothManager();
+            IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
+            if (iGatt == null) {
+                Log.e(TAG, "Fail to get GATT Server connection");
+                return null;
+            }
+            BluetoothGattServer mGattServer = new BluetoothGattServer(context, iGatt);
+            Boolean regStatus = mGattServer.registerCallback(callback);
+            return regStatus? mGattServer : null;
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+            return null;
+        }
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 9ee202a..43079f4 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -89,13 +89,11 @@
 
     /**
      * GATT
-     * @hide
      */
     static public final int GATT = 7;
 
     /**
      * GATT_SERVER
-     * @hide
      */
     static public final int GATT_SERVER = 8;
 
diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
index ed8777c..493d2f8 100755
--- a/core/java/android/bluetooth/IBluetoothManager.aidl
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -17,6 +17,7 @@
 package android.bluetooth;
 
 import android.bluetooth.IBluetooth;
+import android.bluetooth.IBluetoothGatt;
 import android.bluetooth.IBluetoothManagerCallback;
 import android.bluetooth.IBluetoothStateChangeCallback;
 
@@ -35,6 +36,7 @@
     boolean enable();
     boolean enableNoAutoConnect();
     boolean disable(boolean persist);
+    IBluetoothGatt getBluetoothGatt();
 
     String getAddress();
     String getName();
diff --git a/core/java/android/bluetooth/MutableBluetoothGattCharacteristic.java b/core/java/android/bluetooth/MutableBluetoothGattCharacteristic.java
deleted file mode 100644
index c05abb2..0000000
--- a/core/java/android/bluetooth/MutableBluetoothGattCharacteristic.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2013 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 java.util.ArrayList;
-import java.util.IllegalFormatConversionException;
-import java.util.List;
-import java.util.UUID;
-
-/**
- * Mutable variant of a Bluetooth Gatt Characteristic
- * @hide
- */
-public class MutableBluetoothGattCharacteristic extends BluetoothGattCharacteristic {
-
-    /**
-     * Create a new MutableBluetoothGattCharacteristic.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param uuid The UUID for this characteristic
-     * @param properties Properties of this characteristic
-     * @param permissions Permissions for this characteristic
-     */
-    public MutableBluetoothGattCharacteristic(UUID uuid, int properties, int permissions) {
-        super(null, uuid, 0, properties, permissions);
-    }
-
-    /**
-     * Adds a descriptor to this characteristic.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param descriptor Descriptor to be added to this characteristic.
-     */
-    public void addDescriptor(MutableBluetoothGattDescriptor descriptor) {
-        mDescriptors.add(descriptor);
-        descriptor.setCharacteristic(this);
-    }
-
-    /**
-     * Set the desired key size.
-     * @hide
-     */
-    public void setKeySize(int keySize) {
-        mKeySize = keySize;
-    }
-
-    /**
-     * Sets the service associated with this device.
-     * @hide
-     */
-    /*package*/ void setService(BluetoothGattService service) {
-        mService = service;
-    }
-}
diff --git a/core/java/android/bluetooth/MutableBluetoothGattDescriptor.java b/core/java/android/bluetooth/MutableBluetoothGattDescriptor.java
deleted file mode 100644
index e455392..0000000
--- a/core/java/android/bluetooth/MutableBluetoothGattDescriptor.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2013 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 java.util.UUID;
-
-/**
- * Mutable variant of a Bluetooth Gatt Descriptor
- * @hide
- */
-public class MutableBluetoothGattDescriptor extends BluetoothGattDescriptor {
-
-    /**
-     * Create a new BluetoothGattDescriptor.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param uuid The UUID for this descriptor
-     * @param permissions Permissions for this descriptor
-     */
-    public MutableBluetoothGattDescriptor(UUID uuid, int permissions) {
-        super(null, uuid, permissions);
-    }
-
-    /**
-     * Set the back-reference to the associated characteristic
-     * @hide
-     */
-    /*package*/ void setCharacteristic(BluetoothGattCharacteristic characteristic) {
-        mCharacteristic = characteristic;
-    }
-}
diff --git a/core/java/android/bluetooth/MutableBluetoothGattService.java b/core/java/android/bluetooth/MutableBluetoothGattService.java
deleted file mode 100644
index 927f5ab..0000000
--- a/core/java/android/bluetooth/MutableBluetoothGattService.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2013 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.bluetooth.BluetoothDevice;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-/**
- * Represents a Bluetooth Gatt Service
- * @hide
- */
-public class MutableBluetoothGattService extends BluetoothGattService {
-
-    /**
-     * Create a new MutableBluetoothGattService.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param uuid The UUID for this service
-     * @param serviceType The type of this service (primary/secondary)
-     */
-    public MutableBluetoothGattService(UUID uuid, int serviceType) {
-        super(uuid, serviceType);
-    }
-
-    /**
-     * Add an included service to this service.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param service The service to be added
-     * @return true, if the included service was added to the service
-     */
-    public boolean addService(BluetoothGattService service) {
-        mIncludedServices.add(service);
-        return true;
-    }
-
-    /**
-     * Add a characteristic to this service.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param characteristic The characteristics to be added
-     * @return true, if the characteristic was added to the service
-     */
-    public boolean addCharacteristic(MutableBluetoothGattCharacteristic characteristic) {
-        mCharacteristics.add(characteristic);
-        characteristic.setService(this);
-        return true;
-    }
-
-    /**
-     * Force the instance ID.
-     * This is needed for conformance testing only.
-     * @hide
-     */
-    public void setInstanceId(int instanceId) {
-        mInstanceId = instanceId;
-    }
-
-    /**
-     * Force the number of handles to reserve for this service.
-     * This is needed for conformance testing only.
-     * @hide
-     */
-    public void setHandles(int handles) {
-        mHandles = handles;
-    }
-}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 7dd76cd..ef9b0bf 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2203,7 +2203,6 @@
      * {@link android.bluetooth.BluetoothAdapter} for using Bluetooth.
      *
      * @see #getSystemService
-     * @hide
      */
     public static final String BLUETOOTH_SERVICE = "bluetooth";