Merge "Improve RestrictionEntry API" into jb-mr2-dev
diff --git a/api/current.txt b/api/current.txt
index 6035322..6f0575c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2210,6 +2210,7 @@
     field public static final java.lang.String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
     field public static final java.lang.String AUTHENTICATOR_META_DATA_NAME = "android.accounts.AccountAuthenticator";
     field public static final int ERROR_CODE_BAD_ARGUMENTS = 7; // 0x7
+    field public static final int ERROR_CODE_BAD_AUTHENTICATION = 9; // 0x9
     field public static final int ERROR_CODE_BAD_REQUEST = 8; // 0x8
     field public static final int ERROR_CODE_CANCELED = 4; // 0x4
     field public static final int ERROR_CODE_INVALID_RESPONSE = 5; // 0x5
@@ -4613,8 +4614,13 @@
     method public boolean isEnabled();
     method public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException;
     method public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException;
+    method public boolean registerCallback(android.bluetooth.BluetoothAdapterCallback);
     method public boolean setName(java.lang.String);
     method public boolean startDiscovery();
+    method public boolean startLeScan();
+    method public boolean startLeScan(java.util.UUID[]);
+    method public void stopLeScan();
+    method public boolean unRegisterCallback(android.bluetooth.BluetoothAdapterCallback);
     field public static final java.lang.String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
     field public static final java.lang.String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
     field public static final java.lang.String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
@@ -4645,6 +4651,14 @@
     field public static final int STATE_TURNING_ON = 11; // 0xb
   }
 
+  public abstract class BluetoothAdapterCallback {
+    ctor public BluetoothAdapterCallback();
+    method public void onCallbackRegistration(int);
+    method public void onLeScan(android.bluetooth.BluetoothDevice, int, byte[]);
+    field public static final int CALLBACK_REGISTERED = 0; // 0x0
+    field public static final int CALLBACK_REGISTRATION_FAILURE = 1; // 0x1
+  }
+
   public class BluetoothAssignedNumbers {
     field public static final int ACCEL_SEMICONDUCTOR = 74; // 0x4a
     field public static final int ALCATEL = 36; // 0x24
@@ -4837,6 +4851,7 @@
   }
 
   public final class BluetoothDevice implements android.os.Parcelable {
+    method public android.bluetooth.BluetoothGatt connectGattServer(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
     method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
     method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
     method public int describeContents();
@@ -4869,6 +4884,159 @@
     field public static final java.lang.String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
   }
 
+  public final class BluetoothGatt implements android.bluetooth.BluetoothProfile {
+    method public void abortReliableWrite(android.bluetooth.BluetoothDevice);
+    method public boolean beginReliableWrite();
+    method public void disconnect();
+    method public boolean discoverServices();
+    method public boolean executeReliableWrite();
+    method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+    method public int getConnectionState(android.bluetooth.BluetoothDevice);
+    method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+    method public android.bluetooth.BluetoothGattService getService(java.util.UUID);
+    method public java.util.List<android.bluetooth.BluetoothGattService> getServices();
+    method public boolean readCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
+    method public boolean readDescriptor(android.bluetooth.BluetoothGattDescriptor);
+    method public boolean readRemoteRssi();
+    method public boolean setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic, boolean);
+    method public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
+    method public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor);
+    field public static final int GATT_FAILURE = 0; // 0x0
+    field public static final int GATT_INSUFFICIENT_AUTHENTICATION = 5; // 0x5
+    field public static final int GATT_INSUFFICIENT_ENCRYPTION = 15; // 0xf
+    field public static final int GATT_INVALID_ATTRIBUTE_LENGTH = 13; // 0xd
+    field public static final int GATT_INVALID_OFFSET = 7; // 0x7
+    field public static final int GATT_READ_NOT_PERMITTED = 2; // 0x2
+    field public static final int GATT_REQUEST_NOT_SUPPORTED = 6; // 0x6
+    field public static final int GATT_SUCCESS = 0; // 0x0
+    field public static final int GATT_WRITE_NOT_PERMITTED = 3; // 0x3
+  }
+
+  public abstract class BluetoothGattCallback {
+    ctor public BluetoothGattCallback();
+    method public void onCharacteristicChanged(android.bluetooth.BluetoothGattCharacteristic);
+    method public void onCharacteristicRead(android.bluetooth.BluetoothGattCharacteristic, int);
+    method public void onCharacteristicWrite(android.bluetooth.BluetoothGattCharacteristic, int);
+    method public void onConnectionStateChange(android.bluetooth.BluetoothDevice, int, int);
+    method public void onDescriptorRead(android.bluetooth.BluetoothGattDescriptor, int);
+    method public void onDescriptorWrite(android.bluetooth.BluetoothGattDescriptor, int);
+    method public void onReadRemoteRssi(android.bluetooth.BluetoothDevice, int, int);
+    method public void onReliableWriteCompleted(android.bluetooth.BluetoothDevice, int);
+    method public void onServicesDiscovered(android.bluetooth.BluetoothDevice, int);
+  }
+
+  public class BluetoothGattCharacteristic {
+    ctor public BluetoothGattCharacteristic(java.util.UUID, int, int);
+    method public boolean addDescriptor(android.bluetooth.BluetoothGattDescriptor);
+    method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID);
+    method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors();
+    method public java.lang.Float getFloatValue(int, int);
+    method public int getInstanceId();
+    method public java.lang.Integer getIntValue(int, int);
+    method public int getPermissions();
+    method public int getProperties();
+    method public android.bluetooth.BluetoothGattService getService();
+    method public java.lang.String getStringValue(int);
+    method public java.util.UUID getUuid();
+    method public byte[] getValue();
+    method public int getWriteType();
+    method public boolean setValue(byte[]);
+    method public boolean setValue(int, int, int);
+    method public boolean setValue(int, int, int, int);
+    method public boolean setValue(java.lang.String);
+    method public void setWriteType(int);
+    field public static final int FORMAT_FLOAT = 52; // 0x34
+    field public static final int FORMAT_SFLOAT = 50; // 0x32
+    field public static final int FORMAT_SINT16 = 34; // 0x22
+    field public static final int FORMAT_SINT32 = 36; // 0x24
+    field public static final int FORMAT_SINT8 = 33; // 0x21
+    field public static final int FORMAT_UINT16 = 18; // 0x12
+    field public static final int FORMAT_UINT32 = 20; // 0x14
+    field public static final int FORMAT_UINT8 = 17; // 0x11
+    field public static final int PERMISSION_READ = 1; // 0x1
+    field public static final int PERMISSION_READ_ENCRYPTED = 2; // 0x2
+    field public static final int PERMISSION_READ_ENCRYPTED_MITM = 4; // 0x4
+    field public static final int PERMISSION_WRITE = 16; // 0x10
+    field public static final int PERMISSION_WRITE_ENCRYPTED = 32; // 0x20
+    field public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 64; // 0x40
+    field public static final int PERMISSION_WRITE_SIGNED = 128; // 0x80
+    field public static final int PERMISSION_WRITE_SIGNED_MITM = 256; // 0x100
+    field public static final int PROPERTY_BROADCAST = 1; // 0x1
+    field public static final int PROPERTY_EXTENDED_PROPS = 128; // 0x80
+    field public static final int PROPERTY_INDICATE = 32; // 0x20
+    field public static final int PROPERTY_NOTIFY = 16; // 0x10
+    field public static final int PROPERTY_READ = 2; // 0x2
+    field public static final int PROPERTY_SIGNED_WRITE = 64; // 0x40
+    field public static final int PROPERTY_WRITE = 8; // 0x8
+    field public static final int PROPERTY_WRITE_NO_RESPONSE = 4; // 0x4
+    field public static final int WRITE_TYPE_DEFAULT = 2; // 0x2
+    field public static final int WRITE_TYPE_NO_RESPONSE = 1; // 0x1
+    field public static final int WRITE_TYPE_SIGNED = 4; // 0x4
+    field protected java.util.List mDescriptors;
+  }
+
+  public class BluetoothGattDescriptor {
+    ctor public BluetoothGattDescriptor(java.util.UUID, int);
+    method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic();
+    method public int getPermissions();
+    method public java.util.UUID getUuid();
+    method public byte[] getValue();
+    method public boolean setValue(byte[]);
+    field public static final byte[] DISABLE_NOTIFICATION_VALUE;
+    field public static final byte[] ENABLE_INDICATION_VALUE;
+    field public static final byte[] ENABLE_NOTIFICATION_VALUE;
+    field public static final int PERMISSION_READ = 1; // 0x1
+    field public static final int PERMISSION_READ_ENCRYPTED = 2; // 0x2
+    field public static final int PERMISSION_READ_ENCRYPTED_MITM = 4; // 0x4
+    field public static final int PERMISSION_WRITE = 16; // 0x10
+    field public static final int PERMISSION_WRITE_ENCRYPTED = 32; // 0x20
+    field public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 64; // 0x40
+    field public static final int PERMISSION_WRITE_SIGNED = 128; // 0x80
+    field public static final int PERMISSION_WRITE_SIGNED_MITM = 256; // 0x100
+  }
+
+  public final class BluetoothGattServer implements android.bluetooth.BluetoothProfile {
+    method public boolean addService(android.bluetooth.BluetoothGattService);
+    method public void cancelConnection(android.bluetooth.BluetoothDevice);
+    method public void clearServices();
+    method public boolean connect(android.bluetooth.BluetoothDevice, boolean);
+    method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+    method public int getConnectionState(android.bluetooth.BluetoothDevice);
+    method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+    method public android.bluetooth.BluetoothGattService getService(java.util.UUID);
+    method public java.util.List<android.bluetooth.BluetoothGattService> getServices();
+    method public boolean notifyCharacteristicChanged(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothGattCharacteristic, boolean);
+    method public boolean removeService(android.bluetooth.BluetoothGattService);
+    method public boolean sendResponse(android.bluetooth.BluetoothDevice, int, int, int, byte[]);
+  }
+
+  public abstract class BluetoothGattServerCallback {
+    ctor public BluetoothGattServerCallback();
+    method public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice, int, int, android.bluetooth.BluetoothGattCharacteristic);
+    method public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice, int, android.bluetooth.BluetoothGattCharacteristic, boolean, boolean, int, byte[]);
+    method public void onConnectionStateChange(android.bluetooth.BluetoothDevice, int, int);
+    method public void onDescriptorReadRequest(android.bluetooth.BluetoothDevice, int, int, android.bluetooth.BluetoothGattDescriptor);
+    method public void onDescriptorWriteRequest(android.bluetooth.BluetoothDevice, int, android.bluetooth.BluetoothGattDescriptor, boolean, boolean, int, byte[]);
+    method public void onExecuteWrite(android.bluetooth.BluetoothDevice, int, boolean);
+    method public void onServiceAdded(int, android.bluetooth.BluetoothGattService);
+  }
+
+  public class BluetoothGattService {
+    ctor public BluetoothGattService(java.util.UUID, int);
+    method public boolean addCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
+    method public boolean addService(android.bluetooth.BluetoothGattService);
+    method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic(java.util.UUID);
+    method public java.util.List<android.bluetooth.BluetoothGattCharacteristic> getCharacteristics();
+    method public java.util.List<android.bluetooth.BluetoothGattService> getIncludedServices();
+    method public int getInstanceId();
+    method public int getType();
+    method public java.util.UUID getUuid();
+    field public static final int SERVICE_TYPE_PRIMARY = 0; // 0x0
+    field public static final int SERVICE_TYPE_SECONDARY = 1; // 0x1
+    field protected java.util.List mCharacteristics;
+    field protected java.util.List mIncludedServices;
+  }
+
   public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
     method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
     method public int getConnectionState(android.bluetooth.BluetoothDevice);
@@ -4931,6 +5099,14 @@
     method public void onHealthChannelStateChange(android.bluetooth.BluetoothHealthAppConfiguration, android.bluetooth.BluetoothDevice, int, int, android.os.ParcelFileDescriptor, int);
   }
 
+  public final class BluetoothManager {
+    method public android.bluetooth.BluetoothAdapter getAdapter();
+    method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
+    method public int getConnectionState(android.bluetooth.BluetoothDevice, int);
+    method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int, int[]);
+    method public android.bluetooth.BluetoothGattServer openGattServer(android.content.Context, android.bluetooth.BluetoothGattServerCallback);
+  }
+
   public abstract interface BluetoothProfile {
     method public abstract java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
     method public abstract int getConnectionState(android.bluetooth.BluetoothDevice);
@@ -4938,6 +5114,8 @@
     field public static final int A2DP = 2; // 0x2
     field public static final java.lang.String EXTRA_PREVIOUS_STATE = "android.bluetooth.profile.extra.PREVIOUS_STATE";
     field public static final java.lang.String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
+    field public static final int GATT = 7; // 0x7
+    field public static final int GATT_SERVER = 8; // 0x8
     field public static final int HEADSET = 1; // 0x1
     field public static final int HEALTH = 3; // 0x3
     field public static final int STATE_CONNECTED = 2; // 0x2
@@ -5495,6 +5673,7 @@
     field public static final int BIND_IMPORTANT = 64; // 0x40
     field public static final int BIND_NOT_FOREGROUND = 4; // 0x4
     field public static final int BIND_WAIVE_PRIORITY = 32; // 0x20
+    field public static final java.lang.String BLUETOOTH_SERVICE = "bluetooth";
     field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
     field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
     field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 313260f..bdc882a 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -151,6 +151,7 @@
     public static final int ERROR_CODE_UNSUPPORTED_OPERATION = 6;
     public static final int ERROR_CODE_BAD_ARGUMENTS = 7;
     public static final int ERROR_CODE_BAD_REQUEST = 8;
+    public static final int ERROR_CODE_BAD_AUTHENTICATION = 9;
 
     /** @hide */
     public static final int ERROR_CODE_USER_RESTRICTED = 100;
@@ -964,10 +965,10 @@
      */
     @Deprecated
     public AccountManagerFuture<Bundle> getAuthToken(
-            final Account account, final String authTokenType, 
+            final Account account, final String authTokenType,
             final boolean notifyAuthFailure,
             AccountManagerCallback<Bundle> callback, Handler handler) {
-        return getAuthToken(account, authTokenType, null, notifyAuthFailure, callback, 
+        return getAuthToken(account, authTokenType, null, notifyAuthFailure, callback,
                 handler);
     }
 
@@ -1913,7 +1914,7 @@
      * <p>
      * The most common case is to call this with one account type, e.g.:
      * <p>
-     * <pre>  newChooseAccountsIntent(null, null, new String[]{"com.google"}, false, null,
+     * <pre>  newChooseAccountIntent(null, null, new String[]{"com.google"}, false, null,
      * null, null, null);</pre>
      * @param selectedAccount if specified, indicates that the {@link Account} is the currently
      * selected one, according to the caller's definition of selected.
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/app/Service.java b/core/java/android/app/Service.java
index 02cf3aa..4fbca73 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -666,7 +666,9 @@
     
     /**
      * Print the Service's state into the given stream.  This gets invoked if
-     * you run "adb shell dumpsys activity service &lt;yourservicename&gt;".
+     * you run "adb shell dumpsys activity service &lt;yourservicename&gt;"
+     * (note that for this command to work, the service must be running, and
+     * you must specify a fully-qualified service name).
      * This is distinct from "dumpsys &lt;servicename&gt;", which only works for
      * named system services and which invokes the {@link IBinder#dump} method
      * on the {@link IBinder} interface registered with ServiceManager.
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 100644
--- 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 100644
--- 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";
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 9afbe6f..da15e3b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2862,16 +2862,16 @@
 
     /**
      * @deprecated This function no longer does anything; it was an old
-     * approach to managing preferred activities, which has been superceeded
-     * (and conflicts with) the modern activity-based preferences.
+     * approach to managing preferred activities, which has been superseded
+     * by (and conflicts with) the modern activity-based preferences.
      */
     @Deprecated
     public abstract void addPackageToPreferred(String packageName);
 
     /**
      * @deprecated This function no longer does anything; it was an old
-     * approach to managing preferred activities, which has been superceeded
-     * (and conflicts with) the modern activity-based preferences.
+     * approach to managing preferred activities, which has been superseded
+     * by (and conflicts with) the modern activity-based preferences.
      */
     @Deprecated
     public abstract void removePackageFromPreferred(String packageName);
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index c0d2fae..7f94794 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -572,7 +572,10 @@
      *        are received faster. The value must be one of
      *        {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
      *        {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}
-     *        or, the desired delay between events in microsecond.
+     *        or, the desired delay between events in microseconds.
+     *        Specifying the delay in microseconds only works from Android
+     *        2.3 (API level 9) onwards. For earlier releases, you must use
+     *        one of the {@code SENSOR_DELAY_*} constants.
      *
      * @return <code>true</code> if the sensor is supported and successfully
      *         enabled.
@@ -604,7 +607,10 @@
      *        are received faster. The value must be one of
      *        {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
      *        {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}.
-     *        or, the desired delay between events in microsecond.
+     *        or, the desired delay between events in microseconds.
+     *        Specifying the delay in microseconds only works from Android
+     *        2.3 (API level 9) onwards. For earlier releases, you must use
+     *        one of the {@code SENSOR_DELAY_*} constants.
      *
      * @param handler
      *        The {@link android.os.Handler Handler} the
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 90bcf1c..66083c8 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1359,7 +1359,7 @@
      * status definitions. Automatically computed as the highest presence of all
      * constituent raw contacts. The provider may choose not to store this value
      * in persistent storage. The expectation is that presence status will be
-     * updated on a regular basic.</td>
+     * updated on a regular basis.</td>
      * </tr>
      * <tr>
      * <td>String</td>
@@ -4181,7 +4181,7 @@
      * all IM rows. See {@link StatusUpdates} for individual status definitions.
      * The provider may choose not to store this value
      * in persistent storage. The expectation is that presence status will be
-     * updated on a regular basic.
+     * updated on a regular basis.
      * </td>
      * </tr>
      * <tr>
diff --git a/core/java/android/security/IKeystoreService.java b/core/java/android/security/IKeystoreService.java
index a890d9b..c365643 100644
--- a/core/java/android/security/IKeystoreService.java
+++ b/core/java/android/security/IKeystoreService.java
@@ -427,6 +427,23 @@
                 }
                 return _result;
             }
+
+            @Override
+            public int is_hardware_backed() throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    mRemote.transact(Stub.TRANSACTION_is_hardware_backed, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
         }
 
         private static final String DESCRIPTOR = "android.security.keystore";
@@ -452,6 +469,7 @@
         static final int TRANSACTION_ungrant = IBinder.FIRST_CALL_TRANSACTION + 18;
         static final int TRANSACTION_getmtime = IBinder.FIRST_CALL_TRANSACTION + 19;
         static final int TRANSACTION_duplicate = IBinder.FIRST_CALL_TRANSACTION + 20;
+        static final int TRANSACTION_is_hardware_backed = IBinder.FIRST_CALL_TRANSACTION + 21;
 
         /**
          * Cast an IBinder object into an IKeystoreService interface, generating
@@ -539,4 +557,6 @@
 
     public int duplicate(String srcKey, int srcUid, String destKey, int destUid)
             throws RemoteException;
+
+    public int is_hardware_backed() throws RemoteException;
 }
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 9051285..1291279 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -340,7 +340,7 @@
                         w += widths[j - paraStart];
                     }
 
-                    boolean isSpaceOrTab = c == CHAR_SPACE || c == CHAR_TAB;
+                    boolean isSpaceOrTab = c == CHAR_SPACE || c == CHAR_TAB || c == CHAR_ZWSP;
 
                     if (w <= width || isSpaceOrTab) {
                         fitWidth = w;
@@ -956,6 +956,7 @@
     private static final char CHAR_SPACE = ' ';
     private static final char CHAR_SLASH = '/';
     private static final char CHAR_HYPHEN = '-';
+    private static final char CHAR_ZWSP = '\u200B';
 
     private static final double EXTRA_ROUNDING = 0.5;
 
diff --git a/core/java/android/util/AttributeSet.java b/core/java/android/util/AttributeSet.java
index 470526c..74942ba 100644
--- a/core/java/android/util/AttributeSet.java
+++ b/core/java/android/util/AttributeSet.java
@@ -151,7 +151,7 @@
      * Return the value of 'attribute' as a resource identifier.
      * 
      * <p>Note that this is different than {@link #getAttributeNameResource}
-     * in that it returns a the value contained in this attribute as a
+     * in that it returns the value contained in this attribute as a
      * resource identifier (i.e., a value originally of the form
      * "@package:type/resource"); the other method returns a resource
      * identifier that identifies the name of the attribute.
@@ -230,7 +230,7 @@
      * Return the value of attribute at 'index' as a resource identifier.
      * 
      * <p>Note that this is different than {@link #getAttributeNameResource}
-     * in that it returns a the value contained in this attribute as a
+     * in that it returns the value contained in this attribute as a
      * resource identifier (i.e., a value originally of the form
      * "@package:type/resource"); the other method returns a resource
      * identifier that identifies the name of the attribute.
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 987ff785..40b6a08 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -1054,8 +1054,7 @@
                 String categoryPrefix =
                         property.category().length() != 0 ? property.category() + ":" : "";
 
-                if (type == int.class) {
-
+                if (type == int.class || type == byte.class) {
                     if (property.resolveId() && context != null) {
                         final int id = field.getInt(view);
                         fieldValue = resolveId(context, id);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index dd36022..725502d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5882,18 +5882,40 @@
          */
         public static final int DEFAULT_MARGIN_RELATIVE = Integer.MIN_VALUE;
 
-        // Layout direction is LTR by default
-        private int mLayoutDirection = LAYOUT_DIRECTION_LTR;
+        /**
+         * Bit  0: layout direction
+         * Bit  1: layout direction
+         * Bit  2: left margin undefined
+         * Bit  3: right margin undefined
+         * Bit  4: is RTL compatibility mode
+         * Bit  5: need resolution
+         *
+         * Bit 6 to 7 not used
+         *
+         * @hide
+         */
+        @ViewDebug.ExportedProperty(category = "layout", flagMapping = {
+                @ViewDebug.FlagToString(mask = LAYOUT_DIRECTION_MASK,
+                        equals = LAYOUT_DIRECTION_MASK, name = "LAYOUT_DIRECTION"),
+                @ViewDebug.FlagToString(mask = LEFT_MARGIN_UNDEFINED_MASK,
+                        equals = LEFT_MARGIN_UNDEFINED_MASK, name = "LEFT_MARGIN_UNDEFINED_MASK"),
+                @ViewDebug.FlagToString(mask = RIGHT_MARGIN_UNDEFINED_MASK,
+                        equals = RIGHT_MARGIN_UNDEFINED_MASK, name = "RIGHT_MARGIN_UNDEFINED_MASK"),
+                @ViewDebug.FlagToString(mask = RTL_COMPATIBILITY_MODE_MASK,
+                        equals = RTL_COMPATIBILITY_MODE_MASK, name = "RTL_COMPATIBILITY_MODE_MASK"),
+                @ViewDebug.FlagToString(mask = NEED_RESOLUTION_MASK,
+                        equals = NEED_RESOLUTION_MASK, name = "NEED_RESOLUTION_MASK")
+        })
+        byte mMarginFlags;
 
-        private static int DEFAULT_MARGIN_RESOLVED = 0;
+        private static final int LAYOUT_DIRECTION_MASK = 0x00000003;
+        private static final int LEFT_MARGIN_UNDEFINED_MASK = 0x00000004;
+        private static final int RIGHT_MARGIN_UNDEFINED_MASK = 0x00000008;
+        private static final int RTL_COMPATIBILITY_MODE_MASK = 0x00000010;
+        private static final int NEED_RESOLUTION_MASK = 0x00000020;
 
-        private boolean mNeedResolution = false;
-        private boolean mIsRtlCompatibilityMode = true;
-
-        private static int UNDEFINED_MARGIN = DEFAULT_MARGIN_RELATIVE;
-
-        private boolean mLeftMarginUndefined = false;
-        private boolean mRightMarginUndefined = false;
+        private static final int DEFAULT_MARGIN_RESOLVED = 0;
+        private static final int UNDEFINED_MARGIN = DEFAULT_MARGIN_RELATIVE;
 
         /**
          * Creates a new set of layout parameters. The values are extracted from
@@ -5923,14 +5945,14 @@
                         R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
                         UNDEFINED_MARGIN);
                 if (leftMargin == UNDEFINED_MARGIN) {
-                    mLeftMarginUndefined = true;
+                    mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
                     leftMargin = DEFAULT_MARGIN_RESOLVED;
                 }
                 rightMargin = a.getDimensionPixelSize(
                         R.styleable.ViewGroup_MarginLayout_layout_marginRight,
                         UNDEFINED_MARGIN);
                 if (rightMargin == UNDEFINED_MARGIN) {
-                    mRightMarginUndefined = true;
+                    mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
                     rightMargin = DEFAULT_MARGIN_RESOLVED;
                 }
 
@@ -5948,12 +5970,19 @@
                         R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
                         DEFAULT_MARGIN_RELATIVE);
 
-                mNeedResolution = isMarginRelative();
+                if (isMarginRelative()) {
+                   mMarginFlags |= NEED_RESOLUTION_MASK;
+                }
             }
 
             final boolean hasRtlSupport = c.getApplicationInfo().hasRtlSupport();
             final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
-            mIsRtlCompatibilityMode = targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport;
+            if (targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport) {
+                mMarginFlags |= RTL_COMPATIBILITY_MODE_MASK;
+            }
+
+            // Layout direction is LTR by default
+            mMarginFlags |= LAYOUT_DIRECTION_LTR;
 
             a.recycle();
         }
@@ -5964,11 +5993,11 @@
         public MarginLayoutParams(int width, int height) {
             super(width, height);
 
-            mLeftMarginUndefined = true;
-            mRightMarginUndefined = true;
+            mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
+            mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
 
-            mNeedResolution = false;
-            mIsRtlCompatibilityMode = false;
+            mMarginFlags &= ~NEED_RESOLUTION_MASK;
+            mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
         }
 
         /**
@@ -5987,13 +6016,7 @@
             this.startMargin = source.startMargin;
             this.endMargin = source.endMargin;
 
-            this.mLeftMarginUndefined = source.mLeftMarginUndefined;
-            this.mRightMarginUndefined = source.mRightMarginUndefined;
-
-            this.mNeedResolution = source.mNeedResolution;
-            this.mIsRtlCompatibilityMode = source.mIsRtlCompatibilityMode;
-
-            setLayoutDirection(source.mLayoutDirection);
+            this.mMarginFlags = source.mMarginFlags;
         }
 
         /**
@@ -6002,11 +6025,11 @@
         public MarginLayoutParams(LayoutParams source) {
             super(source);
 
-            mLeftMarginUndefined = true;
-            mRightMarginUndefined = true;
+            mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
+            mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
 
-            mNeedResolution = false;
-            mIsRtlCompatibilityMode = false;
+            mMarginFlags &= ~NEED_RESOLUTION_MASK;
+            mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
         }
 
         /**
@@ -6029,9 +6052,13 @@
             topMargin = top;
             rightMargin = right;
             bottomMargin = bottom;
-            mLeftMarginUndefined = false;
-            mRightMarginUndefined = false;
-            mNeedResolution = isMarginRelative();
+            mMarginFlags &= ~LEFT_MARGIN_UNDEFINED_MASK;
+            mMarginFlags &= ~RIGHT_MARGIN_UNDEFINED_MASK;
+            if (isMarginRelative()) {
+                mMarginFlags |= NEED_RESOLUTION_MASK;
+            } else {
+                mMarginFlags &= ~NEED_RESOLUTION_MASK;
+            }
         }
 
         /**
@@ -6057,7 +6084,7 @@
             topMargin = top;
             endMargin = end;
             bottomMargin = bottom;
-            mNeedResolution = true;
+            mMarginFlags |= NEED_RESOLUTION_MASK;
         }
 
         /**
@@ -6069,7 +6096,7 @@
          */
         public void setMarginStart(int start) {
             startMargin = start;
-            mNeedResolution = true;
+            mMarginFlags |= NEED_RESOLUTION_MASK;
         }
 
         /**
@@ -6081,10 +6108,10 @@
          */
         public int getMarginStart() {
             if (startMargin != DEFAULT_MARGIN_RELATIVE) return startMargin;
-            if (mNeedResolution) {
+            if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
                 doResolveMargins();
             }
-            switch(mLayoutDirection) {
+            switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
                 case View.LAYOUT_DIRECTION_RTL:
                     return rightMargin;
                 case View.LAYOUT_DIRECTION_LTR:
@@ -6102,7 +6129,7 @@
          */
         public void setMarginEnd(int end) {
             endMargin = end;
-            mNeedResolution = true;
+            mMarginFlags |= NEED_RESOLUTION_MASK;
         }
 
         /**
@@ -6114,10 +6141,10 @@
          */
         public int getMarginEnd() {
             if (endMargin != DEFAULT_MARGIN_RELATIVE) return endMargin;
-            if (mNeedResolution) {
+            if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
                 doResolveMargins();
             }
-            switch(mLayoutDirection) {
+            switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
                 case View.LAYOUT_DIRECTION_RTL:
                     return leftMargin;
                 case View.LAYOUT_DIRECTION_LTR:
@@ -6147,9 +6174,14 @@
         public void setLayoutDirection(int layoutDirection) {
             if (layoutDirection != View.LAYOUT_DIRECTION_LTR &&
                     layoutDirection != View.LAYOUT_DIRECTION_RTL) return;
-            if (layoutDirection != this.mLayoutDirection) {
-                this.mLayoutDirection = layoutDirection;
-                this.mNeedResolution = isMarginRelative();
+            if (layoutDirection != (mMarginFlags & LAYOUT_DIRECTION_MASK)) {
+                mMarginFlags &= ~LAYOUT_DIRECTION_MASK;
+                mMarginFlags |= (layoutDirection & LAYOUT_DIRECTION_MASK);
+                if (isMarginRelative()) {
+                    mMarginFlags |= NEED_RESOLUTION_MASK;
+                } else {
+                    mMarginFlags &= ~NEED_RESOLUTION_MASK;
+                }
             }
         }
 
@@ -6160,7 +6192,7 @@
          * @return the layout direction.
          */
         public int getLayoutDirection() {
-            return mLayoutDirection;
+            return (mMarginFlags & LAYOUT_DIRECTION_MASK);
         }
 
         /**
@@ -6173,28 +6205,30 @@
 
             // No relative margin or pre JB-MR1 case or no need to resolve, just dont do anything
             // Will use the left and right margins if no relative margin is defined.
-            if (!isMarginRelative() || !mNeedResolution) return;
+            if (!isMarginRelative() ||
+                    (mMarginFlags & NEED_RESOLUTION_MASK) != NEED_RESOLUTION_MASK) return;
 
             // Proceed with resolution
             doResolveMargins();
         }
 
         private void doResolveMargins() {
-
-            if (mIsRtlCompatibilityMode) {
+            if ((mMarginFlags & RTL_COMPATIBILITY_MODE_MASK) == RTL_COMPATIBILITY_MODE_MASK) {
                 // if left or right margins are not defined and if we have some start or end margin
                 // defined then use those start and end margins.
-                if (mLeftMarginUndefined && startMargin > DEFAULT_MARGIN_RELATIVE) {
+                if ((mMarginFlags & LEFT_MARGIN_UNDEFINED_MASK) == LEFT_MARGIN_UNDEFINED_MASK
+                        && startMargin > DEFAULT_MARGIN_RELATIVE) {
                     leftMargin = startMargin;
                 }
-                if (mRightMarginUndefined && endMargin > DEFAULT_MARGIN_RELATIVE) {
+                if ((mMarginFlags & RIGHT_MARGIN_UNDEFINED_MASK) == RIGHT_MARGIN_UNDEFINED_MASK
+                        && endMargin > DEFAULT_MARGIN_RELATIVE) {
                     rightMargin = endMargin;
                 }
             } else {
                 // We have some relative margins (either the start one or the end one or both). So use
                 // them and override what has been defined for left and right margins. If either start
                 // or end margin is not defined, just set it to default "0".
-                switch(mLayoutDirection) {
+                switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
                     case View.LAYOUT_DIRECTION_RTL:
                         leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
                                 endMargin : DEFAULT_MARGIN_RESOLVED;
@@ -6210,14 +6244,14 @@
                         break;
                 }
             }
-            mNeedResolution = false;
+            mMarginFlags &= ~NEED_RESOLUTION_MASK;
         }
 
         /**
          * @hide
          */
         public boolean isLayoutRtl() {
-            return (mLayoutDirection == View.LAYOUT_DIRECTION_RTL);
+            return ((mMarginFlags & LAYOUT_DIRECTION_MASK) == View.LAYOUT_DIRECTION_RTL);
         }
 
         /**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7b34ce1..7790f92 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -258,12 +258,12 @@
     QueuedInputEvent mPendingInputEventHead;
     QueuedInputEvent mPendingInputEventTail;
     int mPendingInputEventCount;
-    QueuedInputEvent mCurrentInputEventHead;
-    QueuedInputEvent mCurrentInputEventTail;
-    int mCurrentInputEventCount;
+    QueuedInputEvent mActiveInputEventHead;
+    QueuedInputEvent mActiveInputEventTail;
+    int mActiveInputEventCount;
     boolean mProcessInputEventsScheduled;
     String mPendingInputEventQueueLengthCounterName = "pq";
-    String mCurrentInputEventQueueLengthCounterName = "cq";
+    String mActiveInputEventQueueLengthCounterName = "aq";
 
     boolean mWindowAttributesChanged = false;
     int mWindowAttributesChangesFlag = 0;
@@ -661,7 +661,7 @@
                 }
 
                 mPendingInputEventQueueLengthCounterName = "pq:" + attrs.getTitle();
-                mCurrentInputEventQueueLengthCounterName = "cq:" + attrs.getTitle();
+                mActiveInputEventQueueLengthCounterName = "aq:" + attrs.getTitle();
             }
         }
     }
@@ -4443,7 +4443,7 @@
     void doProcessInputEvents() {
         // Handle all of the available pending input events. Currently this will immediately
         // process all of the events it can until it encounters one that must go through the IME.
-        // After that it will continue adding events to the current input queue but will wait for a
+        // After that it will continue adding events to the active input queue but will wait for a
         // response from the IME, regardless of whether that particular event needs it or not, in
         // order to guarantee ordering consistency. This could be slightly improved by only
         // queueing events whose source has previously encountered something that needs to be
@@ -4466,18 +4466,18 @@
             if (result == EVENT_HANDLED || result == EVENT_NOT_HANDLED) {
                 finishInputEvent(q, result == EVENT_HANDLED);
             } else if (result == EVENT_PENDING_IME) {
-                enqueueCurrentInputEvent(q);
+                enqueueActiveInputEvent(q);
             } else {
                 q.mFlags |= QueuedInputEvent.FLAG_DELIVER_POST_IME;
                 // If the IME decided not to handle this event, and we have no events already being
                 // handled by the IME, go ahead and handle this one and then continue to the next
                 // input event. Otherwise, queue it up and handle it after whatever in front of it
                 // in the queue has been handled.
-                if (mCurrentInputEventHead == null) {
+                if (mActiveInputEventHead == null) {
                     result = deliverInputEventPostIme(q);
                     finishInputEvent(q, result == EVENT_HANDLED);
                 } else {
-                    enqueueCurrentInputEvent(q);
+                    enqueueActiveInputEvent(q);
                 }
             }
         }
@@ -4490,29 +4490,54 @@
         }
     }
 
-    private void enqueueCurrentInputEvent(QueuedInputEvent q) {
-        if (mCurrentInputEventHead == null) {
-            mCurrentInputEventHead = q;
-            mCurrentInputEventTail = q;
+    private void enqueueActiveInputEvent(QueuedInputEvent q) {
+        if (mActiveInputEventHead == null) {
+            mActiveInputEventHead = q;
+            mActiveInputEventTail = q;
         } else {
-            mCurrentInputEventTail.mNext = q;
-            mCurrentInputEventTail = q;
+            mActiveInputEventTail.mNext = q;
+            mActiveInputEventTail = q;
         }
-        mCurrentInputEventCount += 1;
-        Trace.traceCounter(Trace.TRACE_TAG_INPUT, mCurrentInputEventQueueLengthCounterName,
-                mCurrentInputEventCount);
+        mActiveInputEventCount += 1;
+        Trace.traceCounter(Trace.TRACE_TAG_INPUT, mActiveInputEventQueueLengthCounterName,
+                mActiveInputEventCount);
     }
 
-    private QueuedInputEvent dequeueCurrentInputEvent() {
-        QueuedInputEvent q = mCurrentInputEventHead;
-        mCurrentInputEventHead = q.mNext;
-        if (mCurrentInputEventHead == null) {
-            mCurrentInputEventTail = null;
+    private QueuedInputEvent dequeueActiveInputEvent() {
+        return dequeueActiveInputEvent(mActiveInputEventHead);
+    }
+
+
+    private QueuedInputEvent dequeueActiveInputEvent(QueuedInputEvent q) {
+        QueuedInputEvent curr = mActiveInputEventHead;
+        QueuedInputEvent prev = null;
+        while (curr != null && curr != q) {
+            prev = curr;
+            curr = curr.mNext;
         }
-        q.mNext = null;
-        mCurrentInputEventCount -= 1;
-        Trace.traceCounter(Trace.TRACE_TAG_INPUT, mCurrentInputEventQueueLengthCounterName,
-                mCurrentInputEventCount);
+        if (curr != null) {
+            if (mActiveInputEventHead == curr) {
+                mActiveInputEventHead = curr.mNext;
+            } else {
+                prev.mNext = curr.mNext;
+            }
+            if (mActiveInputEventTail == curr) {
+                mActiveInputEventTail = prev;
+            }
+            curr.mNext = null;
+
+            mActiveInputEventCount -= 1;
+            Trace.traceCounter(Trace.TRACE_TAG_INPUT, mActiveInputEventQueueLengthCounterName,
+                    mActiveInputEventCount);
+        }
+        return curr;
+    }
+
+    private QueuedInputEvent findActiveInputEvent(int seq) {
+        QueuedInputEvent q = mActiveInputEventHead;
+        while (q != null && q.mEvent.getSequenceNumber() != seq) {
+            q = q.mNext;
+        }
         return q;
     }
 
@@ -4532,36 +4557,35 @@
     }
 
     void handleImeFinishedEvent(int seq, boolean handled) {
-        QueuedInputEvent q = mCurrentInputEventHead;
-        if (q != null && q.mEvent.getSequenceNumber() == seq) {
-            dequeueCurrentInputEvent();
+        QueuedInputEvent q = findActiveInputEvent(seq);
+        if (q != null) {
             if (DEBUG_IMF) {
                 Log.v(TAG, "IME finished event: seq=" + seq
                         + " handled=" + handled + " event=" + q);
             }
 
-            if (!handled) {
+            if (handled) {
+                dequeueActiveInputEvent(q);
+                finishInputEvent(q, true);
+            } else {
+                q.mFlags |= QueuedInputEvent.FLAG_DELIVER_POST_IME;
+            }
+
+
+            // Flush all of the input events that are no longer waiting on the IME
+            while (mActiveInputEventHead != null && (mActiveInputEventHead.mFlags &
+                        QueuedInputEvent.FLAG_DELIVER_POST_IME) != 0) {
+                q = dequeueActiveInputEvent();
                 // If the window doesn't currently have input focus, then drop
                 // this event.  This could be an event that came back from the
                 // IME dispatch but the window has lost focus in the meantime.
+                handled = false;
                 if (!mAttachInfo.mHasWindowFocus && !isTerminalInputEvent(q.mEvent)) {
                     Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
                 } else {
-                    final int result = deliverInputEventPostIme(q);
-                    if (result == EVENT_HANDLED) {
-                        handled = true;
-                    }
+                    handled = (deliverInputEventPostIme(q) == EVENT_HANDLED);
                 }
-            }
-
-            finishInputEvent(q, handled);
-
-            // Flush all of the input events that are no longer waiting on the IME
-            while (mCurrentInputEventHead != null && (mCurrentInputEventHead.mFlags &
-                        QueuedInputEvent.FLAG_DELIVER_POST_IME) != 0) {
-                q = dequeueCurrentInputEvent();
-                final int result = deliverInputEventPostIme(q);
-                finishInputEvent(q, result == EVENT_HANDLED);
+                finishInputEvent(q, handled);
             }
         } else {
             if (DEBUG_IMF) {
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index e711b94..9c00b7f 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -468,7 +468,8 @@
         // Force reloading the image resource
         sc.icon.setImageDrawable(null);
         sc.icon.setImageResource(muted ? sc.iconMuteRes : sc.iconRes);
-        if (sc.streamType == AudioManager.STREAM_RING &&
+        if (((sc.streamType == AudioManager.STREAM_RING) ||
+                (sc.streamType == AudioManager.STREAM_NOTIFICATION)) &&
                 mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
             sc.icon.setImageResource(R.drawable.ic_audio_ring_notif_vibrate);
         }
diff --git a/core/java/com/android/internal/widget/TransportControlView.java b/core/java/com/android/internal/widget/TransportControlView.java
index c33f038..8ebe94c 100644
--- a/core/java/com/android/internal/widget/TransportControlView.java
+++ b/core/java/com/android/internal/widget/TransportControlView.java
@@ -143,7 +143,8 @@
             mLocalHandler = new WeakReference<Handler>(handler);
         }
 
-        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs) {
+        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
+                long currentPosMs, float speed) {
             Handler handler = mLocalHandler.get();
             if (handler != null) {
                 handler.obtainMessage(MSG_UPDATE_STATE, generationId, state).sendToTarget();
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 90161fd..5454c08 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -383,7 +383,8 @@
         return descent - ascent + leading;
     }
 
-    static jfloat measureText_CII(JNIEnv* env, jobject jpaint, jcharArray text, int index, int count) {
+    static jfloat measureText_CIII(JNIEnv* env, jobject jpaint, jcharArray text, int index, int count,
+            jint bidiFlags) {
         NPE_CHECK_RETURN_ZERO(env, jpaint);
         NPE_CHECK_RETURN_ZERO(env, text);
 
@@ -401,13 +402,14 @@
         jfloat result = 0;
 
         TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength,
-                paint->getFlags(), NULL /* dont need all advances */, &result);
+                bidiFlags, NULL /* dont need all advances */, &result);
 
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
         return result;
     }
 
-    static jfloat measureText_StringII(JNIEnv* env, jobject jpaint, jstring text, int start, int end) {
+    static jfloat measureText_StringIII(JNIEnv* env, jobject jpaint, jstring text, int start, int end,
+            jint bidiFlags) {
         NPE_CHECK_RETURN_ZERO(env, jpaint);
         NPE_CHECK_RETURN_ZERO(env, text);
 
@@ -426,13 +428,13 @@
         jfloat width = 0;
 
         TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength,
-                paint->getFlags(), NULL /* dont need all advances */, &width);
+                bidiFlags, NULL /* dont need all advances */, &width);
 
         env->ReleaseStringChars(text, textArray);
         return width;
     }
 
-    static jfloat measureText_String(JNIEnv* env, jobject jpaint, jstring text) {
+    static jfloat measureText_StringI(JNIEnv* env, jobject jpaint, jstring text, jint bidiFlags) {
         NPE_CHECK_RETURN_ZERO(env, jpaint);
         NPE_CHECK_RETURN_ZERO(env, text);
 
@@ -446,13 +448,14 @@
         jfloat width = 0;
 
         TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength,
-                paint->getFlags(), NULL /* dont need all advances */, &width);
+                bidiFlags, NULL /* dont need all advances */, &width);
 
         env->ReleaseStringChars(text, textArray);
         return width;
     }
 
-    static int dotextwidths(JNIEnv* env, SkPaint* paint, const jchar text[], int count, jfloatArray widths) {
+    static int dotextwidths(JNIEnv* env, SkPaint* paint, const jchar text[], int count, jfloatArray widths,
+            jint bidiFlags) {
         NPE_CHECK_RETURN_ZERO(env, paint);
         NPE_CHECK_RETURN_ZERO(env, text);
 
@@ -473,23 +476,24 @@
         jfloat* widthsArray = autoWidths.ptr();
 
         TextLayout::getTextRunAdvances(paint, text, 0, count, count,
-                paint->getFlags(), widthsArray, NULL /* dont need totalAdvance */);
+                bidiFlags, widthsArray, NULL /* dont need totalAdvance */);
 
         return count;
     }
 
-    static int getTextWidths___CII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text, int index, int count, jfloatArray widths) {
+    static int getTextWidths___CIII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text,
+            int index, int count, jint bidiFlags, jfloatArray widths) {
         const jchar* textArray = env->GetCharArrayElements(text, NULL);
-        count = dotextwidths(env, paint, textArray + index, count, widths);
+        count = dotextwidths(env, paint, textArray + index, count, widths, bidiFlags);
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
                                       JNI_ABORT);
         return count;
     }
 
-    static int getTextWidths__StringII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text,
-            int start, int end, jfloatArray widths) {
+    static int getTextWidths__StringIII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text,
+            int start, int end, jint bidiFlags, jfloatArray widths) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        int count = dotextwidths(env, paint, textArray + start, end - start, widths);
+        int count = dotextwidths(env, paint, textArray + start, end - start, widths, bidiFlags);
         env->ReleaseStringChars(text, textArray);
         return count;
     }
@@ -685,10 +689,10 @@
     }
 
     static int breakText(JNIEnv* env, SkPaint& paint, const jchar text[],
-                         int count, float maxWidth, jfloatArray jmeasured,
+                         int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
                          SkPaint::TextBufferDirection tbd) {
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
-                text, 0, count, count, paint.getFlags());
+                text, 0, count, count, bidiFlags);
         if (value == NULL) {
             return 0;
         }
@@ -706,7 +710,7 @@
     }
 
     static int breakTextC(JNIEnv* env, jobject jpaint, jcharArray jtext,
-            int index, int count, float maxWidth, jfloatArray jmeasuredWidth) {
+            int index, int count, float maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
         NPE_CHECK_RETURN_ZERO(env, jpaint);
         NPE_CHECK_RETURN_ZERO(env, jtext);
 
@@ -727,14 +731,14 @@
         SkPaint*     paint = GraphicsJNI::getNativePaint(env, jpaint);
         const jchar* text = env->GetCharArrayElements(jtext, NULL);
         count = breakText(env, *paint, text + index, count, maxWidth,
-                          jmeasuredWidth, tbd);
+                          bidiFlags, jmeasuredWidth, tbd);
         env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
                                       JNI_ABORT);
         return count;
     }
 
     static int breakTextS(JNIEnv* env, jobject jpaint, jstring jtext,
-                bool forwards, float maxWidth, jfloatArray jmeasuredWidth) {
+                bool forwards, float maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
         NPE_CHECK_RETURN_ZERO(env, jpaint);
         NPE_CHECK_RETURN_ZERO(env, jtext);
 
@@ -745,22 +749,20 @@
         SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
         int count = env->GetStringLength(jtext);
         const jchar* text = env->GetStringChars(jtext, NULL);
-        count = breakText(env, *paint, text, count, maxWidth,
-                          jmeasuredWidth, tbd);
+        count = breakText(env, *paint, text, count, maxWidth, bidiFlags, jmeasuredWidth, tbd);
         env->ReleaseStringChars(jtext, text);
         return count;
     }
 
     static void doTextBounds(JNIEnv* env, const jchar* text, int count,
-                             jobject bounds, const SkPaint& paint)
-    {
+                             jobject bounds, const SkPaint& paint, jint bidiFlags) {
         SkRect  r;
         r.set(0,0,0,0);
 
         SkIRect ir;
 
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
-                text, 0, count, count, paint.getFlags());
+                text, 0, count, count, bidiFlags);
         if (value == NULL) {
             return;
         }
@@ -770,18 +772,16 @@
     }
 
     static void getStringBounds(JNIEnv* env, jobject, const SkPaint* paint,
-                                jstring text, int start, int end, jobject bounds)
-    {
+                                jstring text, int start, int end, jint bidiFlags, jobject bounds) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        doTextBounds(env, textArray + start, end - start, bounds, *paint);
+        doTextBounds(env, textArray + start, end - start, bounds, *paint, bidiFlags);
         env->ReleaseStringChars(text, textArray);
     }
 
     static void getCharArrayBounds(JNIEnv* env, jobject, const SkPaint* paint,
-                        jcharArray text, int index, int count, jobject bounds)
-    {
+                        jcharArray text, int index, int count, jint bidiFlags, jobject bounds) {
         const jchar* textArray = env->GetCharArrayElements(text, NULL);
-        doTextBounds(env, textArray + index, count, bounds, *paint);
+        doTextBounds(env, textArray + index, count, bounds, *paint, bidiFlags);
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
                                       JNI_ABORT);
     }
@@ -841,13 +841,13 @@
     {"descent","()F", (void*) SkPaintGlue::descent},
     {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)SkPaintGlue::getFontMetrics},
     {"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)SkPaintGlue::getFontMetricsInt},
-    {"native_measureText","([CII)F", (void*) SkPaintGlue::measureText_CII},
-    {"native_measureText","(Ljava/lang/String;)F", (void*) SkPaintGlue::measureText_String},
-    {"native_measureText","(Ljava/lang/String;II)F", (void*) SkPaintGlue::measureText_StringII},
-    {"native_breakText","([CIIF[F)I", (void*) SkPaintGlue::breakTextC},
-    {"native_breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS},
-    {"native_getTextWidths","(I[CII[F)I", (void*) SkPaintGlue::getTextWidths___CII_F},
-    {"native_getTextWidths","(ILjava/lang/String;II[F)I", (void*) SkPaintGlue::getTextWidths__StringII_F},
+    {"native_measureText","([CIII)F", (void*) SkPaintGlue::measureText_CIII},
+    {"native_measureText","(Ljava/lang/String;I)F", (void*) SkPaintGlue::measureText_StringI},
+    {"native_measureText","(Ljava/lang/String;III)F", (void*) SkPaintGlue::measureText_StringIII},
+    {"native_breakText","([CIIFI[F)I", (void*) SkPaintGlue::breakTextC},
+    {"native_breakText","(Ljava/lang/String;ZFI[F)I", (void*) SkPaintGlue::breakTextS},
+    {"native_getTextWidths","(I[CIII[F)I", (void*) SkPaintGlue::getTextWidths___CIII_F},
+    {"native_getTextWidths","(ILjava/lang/String;III[F)I", (void*) SkPaintGlue::getTextWidths__StringIII_F},
     {"native_getTextRunAdvances","(I[CIIIII[FI)F",
         (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FI},
     {"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FI)F",
@@ -861,9 +861,9 @@
         (void*) SkPaintGlue::getTextRunCursor__String},
     {"native_getTextPath","(II[CIIFFI)V", (void*) SkPaintGlue::getTextPath___C},
     {"native_getTextPath","(IILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__String},
-    {"nativeGetStringBounds", "(ILjava/lang/String;IILandroid/graphics/Rect;)V",
+    {"nativeGetStringBounds", "(ILjava/lang/String;IIILandroid/graphics/Rect;)V",
                                         (void*) SkPaintGlue::getStringBounds },
-    {"nativeGetCharArrayBounds", "(I[CIILandroid/graphics/Rect;)V",
+    {"nativeGetCharArrayBounds", "(I[CIIILandroid/graphics/Rect;)V",
                                     (void*) SkPaintGlue::getCharArrayBounds },
     {"nSetShadowLayer", "(FFFI)V", (void*)SkPaintGlue::setShadowLayer}
 };
diff --git a/core/res/res/layout-xlarge/activity_list.xml b/core/res/res/layout-xlarge/activity_list.xml
index edf6ee6..bf46af8 100644
--- a/core/res/res/layout-xlarge/activity_list.xml
+++ b/core/res/res/layout-xlarge/activity_list.xml
@@ -52,7 +52,8 @@
                 android:singleLine="true"
                 android:ellipsize="end"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
+                android:layout_height="wrap_content"
+                android:textAlignment="viewStart" />
         </LinearLayout>
         <View android:id="@+id/titleDivider"
             android:layout_width="match_parent"
diff --git a/core/res/res/layout/alert_dialog.xml b/core/res/res/layout/alert_dialog.xml
index 35552d3..59e56af 100644
--- a/core/res/res/layout/alert_dialog.xml
+++ b/core/res/res/layout/alert_dialog.xml
@@ -55,7 +55,8 @@
                 android:singleLine="true"
                 android:ellipsize="end"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
+                android:layout_height="wrap_content"
+                android:textAlignment="viewStart" />
         </LinearLayout>
         <ImageView android:id="@+id/titleDivider"
             android:layout_width="match_parent"
diff --git a/core/res/res/layout/alert_dialog_holo.xml b/core/res/res/layout/alert_dialog_holo.xml
index 3f1fa3c..34cb21d 100644
--- a/core/res/res/layout/alert_dialog_holo.xml
+++ b/core/res/res/layout/alert_dialog_holo.xml
@@ -53,7 +53,8 @@
                 android:singleLine="true"
                 android:ellipsize="end"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
+                android:layout_height="wrap_content"
+                android:textAlignment="viewStart" />
         </LinearLayout>
         <View android:id="@+id/titleDivider"
             android:layout_width="match_parent"
diff --git a/core/res/res/layout/wifi_p2p_dialog_row.xml b/core/res/res/layout/wifi_p2p_dialog_row.xml
index ef810a0..2c88b10 100644
--- a/core/res/res/layout/wifi_p2p_dialog_row.xml
+++ b/core/res/res/layout/wifi_p2p_dialog_row.xml
@@ -23,5 +23,6 @@
     <TextView
             android:id="@+id/value"
             style="@style/wifi_item_content"
-            android:textStyle="bold" />
+            android:textStyle="bold"
+            android:textAlignment="viewStart" />
 </LinearLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 5282df3..8c7a374 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2092,11 +2092,11 @@
             <!-- Don't use a layer. -->
             <enum name="none" value="0" />
             <!-- Use a software layer. Refer to
-                 {@link android.view.View#setLayerType(int, android.graphics.Paint) for
+                 {@link android.view.View#setLayerType(int, android.graphics.Paint)} for
                  more information. -->
             <enum name="software" value="1" />
             <!-- Use a hardware layer. Refer to
-                 {@link android.view.View#setLayerType(int, android.graphics.Paint) for
+                 {@link android.view.View#setLayerType(int, android.graphics.Paint)} for
                  more information. -->
             <enum name="hardware" value="2" />
         </attr>
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index 999ddc4..744b15d 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -78,17 +78,50 @@
     </family>
     <family>
         <fileset>
-            <file>AnjaliNewLipi-light.ttf</file>
+            <file variant="elegant">NotoSansMalayalam-Regular.ttf</file>
+            <file variant="elegant">NotoSansMalayalam-Bold.ttf</file>
         </fileset>
     </family>
     <family>
         <fileset>
-            <file>Lohit-Bengali.ttf</file>
+            <file variant="compact">NotoSansMalayalamUI-Regular.ttf</file>
+            <file variant="compact">NotoSansMalayalamUI-Bold.ttf</file>
         </fileset>
     </family>
     <family>
         <fileset>
-            <file>Lohit-Kannada.ttf</file>
+            <file variant="elegant">NotoSansBengali-Regular.ttf</file>
+            <file variant="elegant">NotoSansBengali-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="compact">NotoSansBengaliUI-Regular.ttf</file>
+            <file variant="compact">NotoSansBengaliUI-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="elegant">NotoSansTelugu-Regular.ttf</file>
+            <file variant="elegant">NotoSansTelugu-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="compact">NotoSansTeluguUI-Regular.ttf</file>
+            <file variant="compact">NotoSansTeluguUI-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="elegant">NotoSansKannada-Regular.ttf</file>
+            <file variant="elegant">NotoSansKannada-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="compact">NotoSansKannadaUI-Regular.ttf</file>
+            <file variant="compact">NotoSansKannadaUI-Bold.ttf</file>
         </fileset>
     </family>
     <family>
@@ -103,11 +136,6 @@
     </family>
     <family>
         <fileset>
-            <file>Lohit-Telugu.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
             <file>DroidSansFallback.ttf</file>
         </fileset>
     </family>
diff --git a/docs/html/google/gcm/gcm.jd b/docs/html/google/gcm/gcm.jd
index f8ba7b4..089baf5 100644
--- a/docs/html/google/gcm/gcm.jd
+++ b/docs/html/google/gcm/gcm.jd
@@ -777,10 +777,11 @@
 
 <p class="note"><strong>Note:</strong> If your organization has a firewall 
 that restricts the traffic to or 
-from the Internet, you need to configure it to allow connectivity with GCM. 
+from the Internet, you need to configure it to allow connectivity with GCM in order for
+your Android devices to receive messages. 
 The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but 
 it sometimes uses 5229 and 5230. GCM doesn't provide specific IPs, so you should 
-allow your server to accept incoming connections from all IP addresses 
+allow your firewall to accept incoming connections from all IP addresses 
 contained in the IP blocks listed in Google's ASN of 15169.</p>
 
 
diff --git a/docs/html/tools/devices/emulator.jd b/docs/html/tools/devices/emulator.jd
index cee6473..bae3985 100644
--- a/docs/html/tools/devices/emulator.jd
+++ b/docs/html/tools/devices/emulator.jd
@@ -1254,7 +1254,7 @@
 <td>&nbsp;</td>
 </tr>
 <tr>
-  <td><code>power health &lt;percent&gt;</code></td>
+  <td><code>capacity &lt;percent&gt;</code></td>
   <td>Set remaining battery capacity state (0-100).</td>
 <td>&nbsp;</td>
 </tr>
diff --git a/docs/html/tools/testing/testing_otheride.jd b/docs/html/tools/testing/testing_otheride.jd
index 0678f52..9484158 100644
--- a/docs/html/tools/testing/testing_otheride.jd
+++ b/docs/html/tools/testing/testing_otheride.jd
@@ -75,9 +75,9 @@
 <p>
     You use the <code>android</code> tool to create test projects.
     You also use <code>android</code> to convert existing test code into an Android test project,
-    or to add the <code>run-tests</code> Ant target to an existing Android test project.
+    or to add the <code>test</code> Ant target to an existing Android test project.
     These operations are described in more detail in the section <a href="#UpdateTestProject">
-    Updating a test project</a>. The <code>run-tests</code> target is described in
+    Updating a test project</a>. The <code>test</code> target is described in
     <a href="#RunTestsAnt">Quick build and run with Ant</a>.
 </p>
 <h3 id="CreateTestProject">Creating a test project</h3>
@@ -300,7 +300,7 @@
 <h3 id="RunTestsAnt">Quick build and run with Ant</h3>
 <p>
     You can use Ant to run all the tests in your test project, using the target
-    <code>run-tests</code>, which is created automatically when you create a test project with
+    <code>test</code>, which is created automatically when you create a test project with
     the <code>android</code> tool.
 </p>
 <p>
diff --git a/docs/html/training/basics/data-storage/databases.jd b/docs/html/training/basics/data-storage/databases.jd
index 9976bb1..61fb758 100644
--- a/docs/html/training/basics/data-storage/databases.jd
+++ b/docs/html/training/basics/data-storage/databases.jd
@@ -284,7 +284,7 @@
 // Define 'where' part of query.
 String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + &quot; LIKE ?&quot;;
 // Specify arguments in placeholder order.
-String[] selelectionArgs = { String.valueOf(rowId) };
+String[] selectionArgs = { String.valueOf(rowId) };
 // Issue SQL statement.
 db.delete(table_name, selection, selectionArgs);
 </pre>
@@ -309,7 +309,7 @@
 
 // Which row to update, based on the ID
 String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + &quot; LIKE ?&quot;;
-String[] selelectionArgs = { String.valueOf(rowId) };
+String[] selectionArgs = { String.valueOf(rowId) };
 
 int count = db.update(
     FeedReaderDbHelper.FeedEntry.TABLE_NAME,
diff --git a/graphics/java/android/graphics/DashPathEffect.java b/graphics/java/android/graphics/DashPathEffect.java
index 4f16dc4..2bdecce 100644
--- a/graphics/java/android/graphics/DashPathEffect.java
+++ b/graphics/java/android/graphics/DashPathEffect.java
@@ -26,7 +26,7 @@
      * controls the length of the dashes. The paint's strokeWidth controls the
      * thickness of the dashes.
      * Note: this patheffect only affects drawing with the paint's style is set
-     * to STROKE or STROKE_AND_FILL. It is ignored if the drawing is done with
+     * to STROKE or FILL_AND_STROKE. It is ignored if the drawing is done with
      * style == FILL.
      * @param intervals array of ON and OFF distances
      * @param phase offset into the intervals array
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index d5cee3a..1485d8d 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1295,17 +1295,17 @@
             return 0f;
         }
         if (!mHasCompatScaling) {
-            return (float) Math.ceil(native_measureText(text, index, count));
+            return (float) Math.ceil(native_measureText(text, index, count, mBidiFlags));
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        float w = native_measureText(text, index, count);
+        float w = native_measureText(text, index, count, mBidiFlags);
         setTextSize(oldSize);
         return (float) Math.ceil(w*mInvCompatScaling);
     }
 
-    private native float native_measureText(char[] text, int index, int count);
+    private native float native_measureText(char[] text, int index, int count, int bidiFlags);
     
     /**
      * Return the width of the text.
@@ -1327,17 +1327,17 @@
             return 0f;
         }
         if (!mHasCompatScaling) {
-            return (float) Math.ceil(native_measureText(text, start, end));
+            return (float) Math.ceil(native_measureText(text, start, end, mBidiFlags));
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        float w = native_measureText(text, start, end);
+        float w = native_measureText(text, start, end, mBidiFlags);
         setTextSize(oldSize);
         return (float) Math.ceil(w*mInvCompatScaling);
     }
 
-    private native float native_measureText(String text, int start, int end);
+    private native float native_measureText(String text, int start, int end, int bidiFlags);
     
     /**
      * Return the width of the text.
@@ -1355,16 +1355,16 @@
         }
 
         if (!mHasCompatScaling) {
-            return (float) Math.ceil(native_measureText(text));
+            return (float) Math.ceil(native_measureText(text, mBidiFlags));
         }
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        float w = native_measureText(text);
+        float w = native_measureText(text, mBidiFlags);
         setTextSize(oldSize);
         return (float) Math.ceil(w*mInvCompatScaling);
     }
 
-    private native float native_measureText(String text);
+    private native float native_measureText(String text, int bidiFlags);
     
     /**
      * Return the width of the text.
@@ -1431,12 +1431,12 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            return native_breakText(text, index, count, maxWidth, measuredWidth);
+            return native_breakText(text, index, count, maxWidth, mBidiFlags, measuredWidth);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        int res = native_breakText(text, index, count, maxWidth*mCompatScaling,
+        int res = native_breakText(text, index, count, maxWidth*mCompatScaling, mBidiFlags,
                 measuredWidth);
         setTextSize(oldSize);
         if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
@@ -1444,7 +1444,7 @@
     }
 
     private native int native_breakText(char[] text, int index, int count,
-                                        float maxWidth, float[] measuredWidth);
+                                        float maxWidth, int bidiFlags, float[] measuredWidth);
 
     /**
      * Measure the text, stopping early if the measured width exceeds maxWidth.
@@ -1521,12 +1521,12 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            return native_breakText(text, measureForwards, maxWidth, measuredWidth);
+            return native_breakText(text, measureForwards, maxWidth, mBidiFlags, measuredWidth);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        int res = native_breakText(text, measureForwards, maxWidth*mCompatScaling,
+        int res = native_breakText(text, measureForwards, maxWidth*mCompatScaling, mBidiFlags,
                 measuredWidth);
         setTextSize(oldSize);
         if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
@@ -1534,7 +1534,7 @@
     }
 
     private native int native_breakText(String text, boolean measureForwards,
-                                        float maxWidth, float[] measuredWidth);
+                                        float maxWidth, int bidiFlags, float[] measuredWidth);
 
     /**
      * Return the advance widths for the characters in the string.
@@ -1560,12 +1560,12 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            return native_getTextWidths(mNativePaint, text, index, count, widths);
+            return native_getTextWidths(mNativePaint, text, index, count, mBidiFlags, widths);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        int res = native_getTextWidths(mNativePaint, text, index, count, widths);
+        int res = native_getTextWidths(mNativePaint, text, index, count, mBidiFlags, widths);
         setTextSize(oldSize);
         for (int i=0; i<res; i++) {
             widths[i] *= mInvCompatScaling;
@@ -1642,12 +1642,12 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            return native_getTextWidths(mNativePaint, text, start, end, widths);
+            return native_getTextWidths(mNativePaint, text, start, end, mBidiFlags, widths);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        int res = native_getTextWidths(mNativePaint, text, start, end, widths);
+        int res = native_getTextWidths(mNativePaint, text, start, end, mBidiFlags, widths);
         setTextSize(oldSize);
         for (int i=0; i<res; i++) {
             widths[i] *= mInvCompatScaling;
@@ -2073,7 +2073,7 @@
         if (bounds == null) {
             throw new NullPointerException("need bounds Rect");
         }
-        nativeGetStringBounds(mNativePaint, text, start, end, bounds);
+        nativeGetStringBounds(mNativePaint, text, start, end, mBidiFlags, bounds);
     }
     
     /**
@@ -2093,7 +2093,7 @@
         if (bounds == null) {
             throw new NullPointerException("need bounds Rect");
         }
-        nativeGetCharArrayBounds(mNativePaint, text, index, count, bounds);
+        nativeGetCharArrayBounds(mNativePaint, text, index, count, mBidiFlags, bounds);
     }
     
     @Override
@@ -2140,9 +2140,9 @@
                                                     String locale);
 
     private static native int native_getTextWidths(int native_object,
-                            char[] text, int index, int count, float[] widths);
+                            char[] text, int index, int count, int bidiFlags, float[] widths);
     private static native int native_getTextWidths(int native_object,
-                            String text, int start, int end, float[] widths);
+                            String text, int start, int end, int bidiFlags, float[] widths);
 
     private static native int native_getTextGlyphs(int native_object,
             String text, int start, int end, int contextStart, int contextEnd,
@@ -2165,8 +2165,8 @@
     private static native void native_getTextPath(int native_object, int bidiFlags,
                 String text, int start, int end, float x, float y, int path);
     private static native void nativeGetStringBounds(int nativePaint,
-                                String text, int start, int end, Rect bounds);
+                                String text, int start, int end, int bidiFlags, Rect bounds);
     private static native void nativeGetCharArrayBounds(int nativePaint,
-                                char[] text, int index, int count, Rect bounds);
+                                char[] text, int index, int count, int bidiFlags, Rect bounds);
     private static native void finalizer(int nativePaint);
 }
diff --git a/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
index 79a7630..83faf35 100644
--- a/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
@@ -28,10 +28,28 @@
 import javax.security.auth.x500.X500Principal;
 
 /**
- * This provides the required parameters needed for initializing the KeyPair
- * generator that works with
- * <a href="{@docRoot}guide/topics/security/keystore.html">Android KeyStore
- * facility</a>.
+ * This provides the required parameters needed for initializing the
+ * {@code KeyPairGenerator} that works with <a href="{@docRoot}
+ * guide/topics/security/keystore.html">Android KeyStore facility</a>. The
+ * Android KeyStore facility is accessed through a
+ * {@link java.security.KeyPairGenerator} API using the
+ * {@code AndroidKeyPairGenerator} provider. The {@code context} passed in may
+ * be used to pop up some UI to ask the user to unlock or initialize the Android
+ * keystore facility.
+ * <p>
+ * After generation, the {@code keyStoreAlias} is used with the
+ * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)}
+ * interface to retrieve the {@link PrivateKey} and its associated
+ * {@link Certificate} chain.
+ * <p>
+ * The KeyPair generator will create a self-signed certificate with the subject
+ * as its X.509v3 Subject Distinguished Name and as its X.509v3 Issuer
+ * Distinguished Name along with the other parameters specified with the
+ * {@link Builder}.
+ * <p>
+ * The self-signed certificate may be replaced at a later time by a certificate
+ * signed by a real Certificate Authority.
+ *
  * @hide
  */
 public class AndroidKeyPairGeneratorSpec implements AlgorithmParameterSpec {
@@ -74,6 +92,7 @@
      *            period
      * @throws IllegalArgumentException when any argument is {@code null} or
      *             {@code endDate} is before {@code startDate}.
+     * @hide should be built with AndroidKeyPairGeneratorSpecBuilder
      */
     public AndroidKeyPairGeneratorSpec(Context context, String keyStoreAlias,
             X500Principal subjectDN, BigInteger serialNumber, Date startDate, Date endDate) {
@@ -142,4 +161,121 @@
     Date getEndDate() {
         return mEndDate;
     }
+
+    /**
+     * Builder class for {@link AndroidKeyPairGeneratorSpec} objects.
+     * <p>
+     * This will build a parameter spec for use with the <a href="{@docRoot}
+     * guide/topics/security/keystore.html">Android KeyStore facility</a>.
+     * <p>
+     * The required fields must be filled in with the builder.
+     * <p>
+     * Example:
+     *
+     * <pre class="prettyprint">
+     * Calendar start = new Calendar();
+     * Calendar end = new Calendar();
+     * end.add(1, Calendar.YEAR);
+     *
+     * AndroidKeyPairGeneratorSpec spec = new AndroidKeyPairGeneratorSpec.Builder(mContext)
+     *         .setAlias("myKey")
+     *         .setSubject(new X500Principal("CN=myKey"))
+     *         .setSerial(BigInteger.valueOf(1337))
+     *         .setStartDate(start.getTime())
+     *         .setEndDate(end.getTime())
+     *         .build();
+     * </pre>
+     */
+    public static class Builder {
+        private final Context mContext;
+
+        private String mKeystoreAlias;
+
+        private X500Principal mSubjectDN;
+
+        private BigInteger mSerialNumber;
+
+        private Date mStartDate;
+
+        private Date mEndDate;
+
+        public Builder(Context context) {
+            if (context == null) {
+                throw new NullPointerException("context == null");
+            }
+            mContext = context;
+        }
+
+        /**
+         * Sets the alias to be used to retrieve the key later from a
+         * {@link java.security.KeyStore} instance using the
+         * {@code AndroidKeyStore} provider.
+         */
+        public Builder setAlias(String alias) {
+            if (alias == null) {
+                throw new NullPointerException("alias == null");
+            }
+            mKeystoreAlias = alias;
+            return this;
+        }
+
+        /**
+         * Sets the subject used for the self-signed certificate of the
+         * generated key pair.
+         */
+        public Builder setSubject(X500Principal subject) {
+            if (subject == null) {
+                throw new NullPointerException("subject == null");
+            }
+            mSubjectDN = subject;
+            return this;
+        }
+
+        /**
+         * Sets the serial number used for the self-signed certificate of the
+         * generated key pair.
+         */
+        public Builder setSerialNumber(BigInteger serialNumber) {
+            if (serialNumber == null) {
+                throw new NullPointerException("serialNumber == null");
+            }
+            mSerialNumber = serialNumber;
+            return this;
+        }
+
+        /**
+         * Sets the start of the validity period for the self-signed certificate
+         * of the generated key pair.
+         */
+        public Builder setStartDate(Date startDate) {
+            if (startDate == null) {
+                throw new NullPointerException("startDate == null");
+            }
+            mStartDate = startDate;
+            return this;
+        }
+
+        /**
+         * Sets the end of the validity period for the self-signed certificate
+         * of the generated key pair.
+         */
+        public Builder setEndDate(Date endDate) {
+            if (endDate == null) {
+                throw new NullPointerException("endDate == null");
+            }
+            mEndDate = endDate;
+            return this;
+        }
+
+        /**
+         * Builds the instance of the {@code AndroidKeyPairGeneratorSpec}.
+         *
+         * @throws IllegalArgumentException if a required field is missing
+         * @return built instance of {@code AndroidKeyPairGeneratorSpec}
+         */
+        public AndroidKeyPairGeneratorSpec build() {
+            return new AndroidKeyPairGeneratorSpec(mContext, mKeystoreAlias, mSubjectDN,
+                    mSerialNumber, mStartDate, mEndDate);
+        }
+    }
 }
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 12c0ed8..2037472 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -296,6 +296,15 @@
         }
     }
 
+    public boolean isHardwareBacked() {
+        try {
+            return mBinder.is_hardware_backed() == NO_ERROR;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return false;
+        }
+    }
+
     public int getLastError() {
         return mError;
     }
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
index e6a3750..3d275cd 100644
--- a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
+++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
@@ -53,6 +53,26 @@
         assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate());
     }
 
+    public void testBuilder_Success() throws Exception {
+        AndroidKeyPairGeneratorSpec spec = new AndroidKeyPairGeneratorSpec.Builder(getContext())
+                .setAlias(TEST_ALIAS_1)
+                .setSubject(TEST_DN_1)
+                .setSerialNumber(SERIAL_1)
+                .setStartDate(NOW)
+                .setEndDate(NOW_PLUS_10_YEARS)
+                .build();
+
+        assertEquals("Context should be the one specified", getContext(), spec.getContext());
+
+        assertEquals("Alias should be the one specified", TEST_ALIAS_1, spec.getKeystoreAlias());
+
+        assertEquals("subjectDN should be the one specified", TEST_DN_1, spec.getSubjectDN());
+
+        assertEquals("startDate should be the one specified", NOW, spec.getStartDate());
+
+        assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate());
+    }
+
     public void testConstructor_NullContext_Failure() throws Exception {
         try {
             new AndroidKeyPairGeneratorSpec(null, TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW,
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 7f4977a..63bb73f 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -165,10 +165,13 @@
             dirtyRect.right, dirtyRect.bottom, !isBlend());
 
     displayList->defer(deferredState, 0);
+
+    deferredUpdateScheduled = false;
+    displayList = NULL;
 }
 
 void Layer::flush() {
-    if (deferredList && !deferredList->isEmpty()) {
+    if (deferredList) {
         renderer->setViewport(layer.getWidth(), layer.getHeight());
         renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
                 !isBlend());
@@ -183,5 +186,21 @@
     }
 }
 
+void Layer::render() {
+    renderer->setViewport(layer.getWidth(), layer.getHeight());
+    renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
+            !isBlend());
+
+    renderer->drawDisplayList(displayList, dirtyRect, DisplayList::kReplayFlag_ClipChildren);
+
+    renderer->finish();
+    renderer = NULL;
+
+    dirtyRect.setEmpty();
+
+    deferredUpdateScheduled = false;
+    displayList = NULL;
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 0e00191..27e0cf1 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -275,6 +275,7 @@
 
     void defer();
     void flush();
+    void render();
 
     /**
      * Bounds of the layer.
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index aeabe366..4a5785c 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -540,13 +540,7 @@
         }
 
         if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) {
-            OpenGLRenderer* renderer = layer->renderer;
-            renderer->setViewport(layer->layer.getWidth(), layer->layer.getHeight());
-            renderer->prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom,
-                    !layer->isBlend());
-            renderer->drawDisplayList(layer->displayList, dirty,
-                    DisplayList::kReplayFlag_ClipChildren);
-            renderer->finish();
+            layer->render();
         } else {
             layer->defer();
         }
@@ -556,13 +550,6 @@
             startTiling(mSnapshot);
         }
 
-        if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) {
-            dirty.setEmpty();
-            layer->renderer = NULL;
-        }
-
-        layer->deferredUpdateScheduled = false;
-        layer->displayList = NULL;
         layer->debugDrawUpdate = mCaches.debugLayersUpdates;
 
         return true;
@@ -609,11 +596,12 @@
         // Note: it is very important to update the layers in reverse order
         for (int i = count - 1; i >= 0; i--) {
             sprintf(layerName, "Layer #%d", i);
-            startMark(layerName); {
-                Layer* layer = mLayerUpdates.itemAt(i);
-                layer->flush();
-                mCaches.resourceCache.decrementRefcount(layer);
-            }
+            startMark(layerName);
+
+            Layer* layer = mLayerUpdates.itemAt(i);
+            layer->flush();
+            mCaches.resourceCache.decrementRefcount(layer);
+
             endMark();
         }
 
@@ -626,6 +614,15 @@
 
 void OpenGLRenderer::pushLayerUpdate(Layer* layer) {
     if (layer) {
+        // Make sure we don't introduce duplicates.
+        // SortedVector would do this automatically but we need to respect
+        // the insertion order. The linear search is not an issue since
+        // this list is usually very short (typically one item, at most a few)
+        for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
+            if (mLayerUpdates.itemAt(i) == layer) {
+                return;
+            }
+        }
         mLayerUpdates.push_back(layer);
         mCaches.resourceCache.incrementRefcount(layer);
     }
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 38cdb8a..32c1406e 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -166,6 +166,7 @@
     private static final int MSG_PROMOTE_RCC = 29;
     private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 30;
     private static final int MSG_UNLOAD_SOUND_EFFECTS = 31;
+    private static final int MSG_RCC_NEW_PLAYBACK_STATE = 32;
 
 
     // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be
@@ -1533,7 +1534,9 @@
             // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
             // SCO connections not started by the application changing the mode
             if (newModeOwnerPid != 0) {
-                 disconnectBluetoothSco(newModeOwnerPid);
+                final long ident = Binder.clearCallingIdentity();
+                disconnectBluetoothSco(newModeOwnerPid);
+                Binder.restoreCallingIdentity(ident);
             }
         }
 
@@ -3739,6 +3742,10 @@
                     onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */,
                             (IRemoteVolumeObserver)msg.obj /* rvo */);
                     break;
+                case MSG_RCC_NEW_PLAYBACK_STATE:
+                    onNewPlaybackStateForRcc(msg.arg1 /* rccId */, msg.arg2 /* state */,
+                            (RccPlaybackState)msg.obj /* newState */);
+                    break;
 
                 case MSG_SET_RSX_CONNECTION_STATE:
                     onSetRsxConnectionState(msg.arg1/*available*/, msg.arg2/*address*/);
@@ -4999,6 +5006,59 @@
      */
     private boolean mHasRemotePlayback;
 
+    private static class RccPlaybackState {
+        public int mState;
+        public long mPositionMs;
+        public float mSpeed;
+
+        public RccPlaybackState(int state, long positionMs, float speed) {
+            mState = state;
+            mPositionMs = positionMs;
+            mSpeed = speed;
+        }
+
+        public void reset() {
+            mState = RemoteControlClient.PLAYSTATE_STOPPED;
+            mPositionMs = RemoteControlClient.PLAYBACK_POSITION_INVALID;
+            mSpeed = RemoteControlClient.PLAYBACK_SPEED_1X;
+        }
+
+        @Override
+        public String toString() {
+            return stateToString() + ", "
+                    + ((mPositionMs == RemoteControlClient.PLAYBACK_POSITION_INVALID) ?
+                            "PLAYBACK_POSITION_INVALID ," : String.valueOf(mPositionMs)) + "ms ,"
+                    + mSpeed + "X";
+        }
+
+        private String stateToString() {
+            switch (mState) {
+                case RemoteControlClient.PLAYSTATE_NONE:
+                    return "PLAYSTATE_NONE";
+                case RemoteControlClient.PLAYSTATE_STOPPED:
+                    return "PLAYSTATE_STOPPED";
+                case RemoteControlClient.PLAYSTATE_PAUSED:
+                    return "PLAYSTATE_PAUSED";
+                case RemoteControlClient.PLAYSTATE_PLAYING:
+                    return "PLAYSTATE_PLAYING";
+                case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+                    return "PLAYSTATE_FAST_FORWARDING";
+                case RemoteControlClient.PLAYSTATE_REWINDING:
+                    return "PLAYSTATE_REWINDING";
+                case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+                    return "PLAYSTATE_SKIPPING_FORWARDS";
+                case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+                    return "PLAYSTATE_SKIPPING_BACKWARDS";
+                case RemoteControlClient.PLAYSTATE_BUFFERING:
+                    return "PLAYSTATE_BUFFERING";
+                case RemoteControlClient.PLAYSTATE_ERROR:
+                    return "PLAYSTATE_ERROR";
+                default:
+                    return "[invalid playstate]";
+            }
+        }
+    }
+
     private static class RemoteControlStackEntry {
         public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
         /**
@@ -5027,7 +5087,7 @@
         public int mPlaybackVolumeMax;
         public int mPlaybackVolumeHandling;
         public int mPlaybackStream;
-        public int mPlaybackState;
+        public RccPlaybackState mPlaybackState;
         public IRemoteVolumeObserver mRemoteVolumeObs;
 
         public void resetPlaybackInfo() {
@@ -5036,7 +5096,7 @@
             mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
             mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
             mPlaybackStream = AudioManager.STREAM_MUSIC;
-            mPlaybackState = RemoteControlClient.PLAYSTATE_STOPPED;
+            mPlaybackState.reset();
             mRemoteVolumeObs = null;
         }
 
@@ -6005,21 +6065,6 @@
                             case RemoteControlClient.PLAYBACKINFO_USES_STREAM:
                                 rcse.mPlaybackStream = value;
                                 break;
-                            case RemoteControlClient.PLAYBACKINFO_PLAYSTATE:
-                                rcse.mPlaybackState = value;
-                                synchronized (mMainRemote) {
-                                    if (rccId == mMainRemote.mRccId) {
-                                        mMainRemoteIsActive = isPlaystateActive(value);
-                                        postReevaluateRemote();
-                                    }
-                                }
-                                // an RCC moving to a "playing" state should become the media button
-                                //   event receiver so it can be controlled, without requiring the
-                                //   app to re-register its receiver
-                                if (isPlaystateActive(value)) {
-                                    postPromoteRcc(rccId);
-                                }
-                                break;
                             default:
                                 Log.e(TAG, "unhandled key " + key + " for RCC " + rccId);
                                 break;
@@ -6029,7 +6074,45 @@
                 }//for
             } catch (ArrayIndexOutOfBoundsException e) {
                 // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+                Log.e(TAG, "Wrong index mRCStack on onNewPlaybackInfoForRcc, lock error? ", e);
+            }
+        }
+    }
+
+    public void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) {
+        sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_STATE, SENDMSG_QUEUE,
+                rccId /* arg1 */, state /* arg2 */,
+                new RccPlaybackState(state, timeMs, speed) /* obj */, 0 /* delay */);
+    }
+
+    public void onNewPlaybackStateForRcc(int rccId, int state, RccPlaybackState newState) {
+        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackStateForRcc(id=" + rccId + ", state=" + state
+                + ", time=" + newState.mPositionMs + ", speed=" + newState.mSpeed + ")");
+        synchronized(mRCStack) {
+            // iterating from top of stack as playback information changes are more likely
+            //   on entries at the top of the remote control stack
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    if (rcse.mRccId == rccId) {
+                        rcse.mPlaybackState = newState;
+                        synchronized (mMainRemote) {
+                            if (rccId == mMainRemote.mRccId) {
+                                mMainRemoteIsActive = isPlaystateActive(state);
+                                postReevaluateRemote();
+                            }
+                        }
+                        // an RCC moving to a "playing" state should become the media button
+                        //   event receiver so it can be controlled, without requiring the
+                        //   app to re-register its receiver
+                        if (isPlaystateActive(state)) {
+                            postPromoteRcc(rccId);
+                        }
+                    }
+                }//for
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index on mRCStack in onNewPlaybackStateForRcc, lock error? ", e);
             }
         }
     }
@@ -6073,7 +6156,7 @@
                 for (int index = mRCStack.size()-1; index >= 0; index--) {
                     final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
                     if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE)
-                            && isPlaystateActive(rcse.mPlaybackState)
+                            && isPlaystateActive(rcse.mPlaybackState.mState)
                             && (rcse.mPlaybackStream == streamType)) {
                         if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType
                                 + ", vol =" + rcse.mPlaybackVolume);
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index efa8089..e21b26b 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -159,6 +159,7 @@
     oneway void remoteControlDisplayUsesBitmapSize(in IRemoteControlDisplay rcd, int w, int h);
 
     oneway void setPlaybackInfoForRcc(int rccId, int what, int value);
+           void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed);
            int  getRemoteStreamMaxVolume();
            int  getRemoteStreamVolume();
     oneway void registerRemoteVolumeObserverForRcc(int rccId, in IRemoteVolumeObserver rvo);
diff --git a/media/java/android/media/IRemoteControlDisplay.aidl b/media/java/android/media/IRemoteControlDisplay.aidl
index 204de3c..095cf80 100644
--- a/media/java/android/media/IRemoteControlDisplay.aidl
+++ b/media/java/android/media/IRemoteControlDisplay.aidl
@@ -40,7 +40,8 @@
     void setCurrentClientId(int clientGeneration, in PendingIntent clientMediaIntent,
             boolean clearing);
 
-    void setPlaybackState(int generationId, int state, long stateChangeTimeMs);
+    void setPlaybackState(int generationId, int state, long stateChangeTimeMs, long currentPosMs,
+            float speed);
 
     void setTransportControlFlags(int generationId, int transportControlFlags);
 
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 11f4180..85a32ca 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -328,8 +328,8 @@
  *         the state. Calling this method in an invalid state transfers the
  *         object to the <em>Error</em> state. </p></td></tr>
  * <tr><td>pause </p></td>
- *     <td>{Started, Paused}</p></td>
- *     <td>{Idle, Initialized, Prepared, Stopped, PlaybackCompleted, Error}</p></td>
+ *     <td>{Started, Paused, PlaybackCompleted}</p></td>
+ *     <td>{Idle, Initialized, Prepared, Stopped, Error}</p></td>
  *     <td>Successful invoke of this method in a valid state transfers the
  *         object to the <em>Paused</em> state. Calling this method in an
  *         invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 9a0ecdf..f186000 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -172,6 +172,17 @@
      */
     public final static int PLAYBACKINFO_INVALID_VALUE = Integer.MIN_VALUE;
 
+    /**
+     * @hide
+     * An unknown or invalid playback position value.
+     */
+    public final static long PLAYBACK_POSITION_INVALID = -1;
+    /**
+     * @hide
+     * The default playback speed, 1x.
+     */
+    public final static float PLAYBACK_SPEED_1X = 1.0f;
+
     //==========================================
     // Public keys for playback information
     /**
@@ -208,15 +219,7 @@
     public final static int PLAYBACKINFO_USES_STREAM = 5;
 
     //==========================================
-    // Private keys for playback information
-    /**
-     * @hide
-     * Used internally to relay playback state (set by the application with
-     * {@link #setPlaybackState(int)}) to AudioService
-     */
-    public final static int PLAYBACKINFO_PLAYSTATE = 255;
-
-
+    // Public flags for the supported transport control capabililities
     /**
      * Flag indicating a RemoteControlClient makes use of the "previous" media key.
      *
@@ -273,6 +276,15 @@
      * @see android.view.KeyEvent#KEYCODE_MEDIA_NEXT
      */
     public final static int FLAG_KEY_MEDIA_NEXT = 1 << 7;
+    /**
+     * @hide
+     * (to be un-hidden and added in javadoc of setTransportControlFlags(int))
+     * Flag indicating a RemoteControlClient can receive changes in the media playback position
+     * through the {@link #OnPlaybackPositionUpdateListener} interface.
+     *
+     * @see #setTransportControlFlags(int)
+     */
+    public final static int FLAG_KEY_MEDIA_POSITION_UPDATE = 1 << 8;
 
     /**
      * @hide
@@ -588,17 +600,54 @@
      *       {@link #PLAYSTATE_ERROR}.
      */
     public void setPlaybackState(int state) {
+        setPlaybackState(state, PLAYBACK_POSITION_INVALID, PLAYBACK_SPEED_1X);
+    }
+
+    /**
+     * @hide
+     * (to be un-hidden)
+     * Sets the current playback state and the matching media position for the current playback
+     *   speed.
+     * @param state The current playback state, one of the following values:
+     *       {@link #PLAYSTATE_STOPPED},
+     *       {@link #PLAYSTATE_PAUSED},
+     *       {@link #PLAYSTATE_PLAYING},
+     *       {@link #PLAYSTATE_FAST_FORWARDING},
+     *       {@link #PLAYSTATE_REWINDING},
+     *       {@link #PLAYSTATE_SKIPPING_FORWARDS},
+     *       {@link #PLAYSTATE_SKIPPING_BACKWARDS},
+     *       {@link #PLAYSTATE_BUFFERING},
+     *       {@link #PLAYSTATE_ERROR}.
+     * @param timeInMs a 0 or positive value for the current media position expressed in ms
+     *    (same unit as for when sending the media duration, if applicable, with
+     *    {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} in the
+     *    {@link RemoteControlClient.MetadataEditor}). Negative values imply that position is not
+     *    known (e.g. listening to a live stream of a radio) or not applicable (e.g. when state
+     *    is {@link #PLAYSTATE_BUFFERING} and nothing had played yet).
+     * @param playbackSpeed a value expressed as a ratio of 1x playback: 1.0f is normal playback,
+     *    2.0f is 2x, 0.5f is half-speed, -2.0f is rewind at 2x speed. 0.0f means nothing is
+     *    playing (e.g. when state is {@link #PLAYSTATE_ERROR}).
+     */
+    public void setPlaybackState(int state, long timeInMs, float playbackSpeed) {
         synchronized(mCacheLock) {
-            if (mPlaybackState != state) {
+            if (timeInMs != PLAYBACK_POSITION_INVALID) {
+                mPlaybackPositionCapabilities |= MEDIA_POSITION_READABLE;
+            } else {
+                mPlaybackPositionCapabilities &= ~MEDIA_POSITION_READABLE;
+            }
+            if ((mPlaybackState != state) || (mPlaybackPositionMs != timeInMs)
+                    || (mPlaybackSpeed != playbackSpeed)) {
                 // store locally
                 mPlaybackState = state;
+                mPlaybackPositionMs = timeInMs;
+                mPlaybackSpeed = playbackSpeed;
                 // keep track of when the state change occurred
                 mPlaybackStateChangeTimeMs = SystemClock.elapsedRealtime();
 
                 // send to remote control display if conditions are met
                 sendPlaybackState_syncCacheLock();
                 // update AudioService
-                sendAudioServiceNewPlaybackInfo_syncCacheLock(PLAYBACKINFO_PLAYSTATE, state);
+                sendAudioServiceNewPlaybackState_syncCacheLock();
             }
         }
     }
@@ -625,6 +674,65 @@
         }
     }
 
+    /**
+     * @hide
+     * (to be un-hidden)
+     * Interface definition for a callback to be invoked when the media playback position is
+     * requested to be updated.
+     */
+    public interface OnPlaybackPositionUpdateListener {
+        /**
+         * Called on the listener to notify it that the playback head should be set at the given
+         * position. If the position can be changed from its current value, the implementor of
+         * the interface should also update the playback position using
+         * {@link RemoteControlClient#setPlaybackState(int, long, int)} to reflect the actual new
+         * position being used, regardless of whether it differs from the requested position.
+         * @param newPositionMs the new requested position in the current media, expressed in ms.
+         */
+        void onPlaybackPositionUpdate(long newPositionMs);
+    }
+
+    /**
+     * @hide
+     * (to be un-hidden)
+     * Sets the listener RemoteControlClient calls whenever the media playback position is requested
+     * to be updated.
+     * Notifications will be received in the same thread as the one in which RemoteControlClient
+     * was created.
+     * @param l
+     */
+    public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener l) {
+        synchronized(mCacheLock) {
+            if ((mPositionUpdateListener == null) && (l != null)) {
+                mPlaybackPositionCapabilities |= MEDIA_POSITION_WRITABLE;
+                // tell RCDs and AudioService this RCC accepts position updates
+                // TODO implement
+            } else if ((mPositionUpdateListener != null) && (l == null)) {
+                mPlaybackPositionCapabilities &= ~MEDIA_POSITION_WRITABLE;
+                // tell RCDs and AudioService this RCC doesn't handle position updates
+                // TODO implement
+            }
+            mPositionUpdateListener = l;
+        }
+    }
+
+    /**
+     * @hide
+     * Flag to reflect that the application controlling this RemoteControlClient sends playback
+     * position updates. The playback position being "readable" is considered from the application's
+     * point of view.
+     */
+    public static int MEDIA_POSITION_READABLE = 1 << 0;
+    /**
+     * @hide
+     * Flag to reflect that the application controlling this RemoteControlClient can receive
+     * playback position updates. The playback position being "writable"
+     * is considered from the application's point of view.
+     */
+    public static int MEDIA_POSITION_WRITABLE = 1 << 1;
+
+    private int mPlaybackPositionCapabilities = 0;
+
     /** @hide */
     public final static int DEFAULT_PLAYBACK_VOLUME_HANDLING = PLAYBACK_VOLUME_VARIABLE;
     /** @hide */
@@ -756,6 +864,14 @@
      */
     private long mPlaybackStateChangeTimeMs = 0;
     /**
+     * Last playback position in ms reported by the user
+     */
+    private long mPlaybackPositionMs = PLAYBACK_POSITION_INVALID;
+    /**
+     * Last playback speed reported by the user
+     */
+    private float mPlaybackSpeed = PLAYBACK_SPEED_1X;
+    /**
      * Cache for the artwork bitmap.
      * Access synchronized on mCacheLock
      * Artwork and metadata are not kept in one Bundle because the bitmap sometimes needs to be
@@ -774,9 +890,13 @@
      * This is re-initialized in apply() and so cannot be final.
      */
     private Bundle mMetadata = new Bundle();
-
     /**
-     * The current remote control client generation ID across the system
+     * Listener registered by user of RemoteControlClient to receive requests for playback position
+     * update requests.
+     */
+    private OnPlaybackPositionUpdateListener mPositionUpdateListener;
+    /**
+     * The current remote control client generation ID across the system, as known by this object
      */
     private int mCurrentClientGenId = -1;
     /**
@@ -789,7 +909,8 @@
 
     /**
      * The media button intent description associated with this remote control client
-     * (can / should include target component for intent handling)
+     * (can / should include target component for intent handling, used when persisting media
+     *    button event receiver across reboots).
      */
     private final PendingIntent mRcMediaIntent;
 
@@ -990,7 +1111,8 @@
                 final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
                 try {
                     di.mRcDisplay.setPlaybackState(mInternalClientGenId,
-                            mPlaybackState, mPlaybackStateChangeTimeMs);
+                            mPlaybackState, mPlaybackStateChangeTimeMs, mPlaybackPositionMs,
+                            mPlaybackSpeed);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error in setPlaybackState(), dead display " + di.mRcDisplay, e);
                     displayIterator.remove();
@@ -1109,7 +1231,20 @@
         try {
             service.setPlaybackInfoForRcc(mRcseId, what, value);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in sendAudioServiceNewPlaybackInfo_syncCacheLock", e);
+            Log.e(TAG, "Dead object in setPlaybackInfoForRcc", e);
+        }
+    }
+
+    private void sendAudioServiceNewPlaybackState_syncCacheLock() {
+        if (mRcseId == RCSE_ID_UNREGISTERED) {
+            return;
+        }
+        IAudioService service = getService();
+        try {
+            service.setPlaybackStateForRcc(mRcseId,
+                    mPlaybackState, mPlaybackPositionMs, mPlaybackSpeed);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in setPlaybackStateForRcc", e);
         }
     }
 
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 262000e..015c0cc 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -4,13 +4,10 @@
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-    ../../../ex/carousel/java/com/android/ex/carousel/carousel.rs \
     src/com/android/systemui/EventLogTags.logtags
 
 LOCAL_JAVA_LIBRARIES := services telephony-common
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-common-carousel
-
 LOCAL_PACKAGE_NAME := SystemUI
 LOCAL_CERTIFICATE := platform
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
index 9712ea8..d5798d7 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
@@ -132,7 +132,8 @@
             mLocalHandler = new WeakReference<Handler>(handler);
         }
 
-        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs) {
+        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
+                long currentPosMs, float speed) {
             Handler handler = mLocalHandler.get();
             if (handler != null) {
                 handler.obtainMessage(MSG_UPDATE_STATE, generationId, state).sendToTarget();
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
index 27d816e..e958e9a 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
@@ -200,7 +200,8 @@
     private final IRemoteControlDisplay.Stub mRemoteControlDisplay =
                 new IRemoteControlDisplay.Stub() {
 
-        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs) {
+        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
+                long currentPosMs, float speed) {
             Message msg = mHandler.obtainMessage(MSG_SET_PLAYBACK_STATE,
                     generationId, state, stateChangeTimeMs);
             mHandler.sendMessage(msg);
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
index 924b9df..ea7b696 100644
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.IBluetooth;
+import android.bluetooth.IBluetoothGatt;
 import android.bluetooth.IBluetoothCallback;
 import android.bluetooth.IBluetoothManager;
 import android.bluetooth.IBluetoothManagerCallback;
@@ -87,6 +88,9 @@
     // and Airplane mode will have higher priority.
     private static final int BLUETOOTH_ON_AIRPLANE=2;
 
+    private static final int SERVICE_IBLUETOOTH = 1;
+    private static final int SERVICE_IBLUETOOTHGATT = 2;
+
     private final Context mContext;
 
     // Locks are not provided for mName and mAddress.
@@ -97,6 +101,7 @@
     private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
     private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
     private IBluetooth mBluetooth;
+    private IBluetoothGatt mBluetoothGatt;
     private boolean mBinding;
     private boolean mUnbinding;
     // used inside handler thread
@@ -463,6 +468,11 @@
         }
     }
 
+    public IBluetoothGatt getBluetoothGatt() {
+        // sync protection
+        return mBluetoothGatt;
+    }
+
     private void sendBluetoothStateCallback(boolean isUp) {
         int n = mStateChangeCallbacks.beginBroadcast();
         if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
@@ -575,16 +585,35 @@
         }
 
         public void onServiceConnected(ComponentName className, IBinder service) {
-            if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
+            if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
             Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
+            // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
+            if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
+                msg.arg1 = SERVICE_IBLUETOOTH;
+                // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
+            } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
+                msg.arg1 = SERVICE_IBLUETOOTHGATT;
+            } else {
+                Log.e(TAG, "Unknown service connected: " + className.getClassName());
+                return;
+            }
             msg.obj = service;
             mHandler.sendMessage(msg);
         }
 
         public void onServiceDisconnected(ComponentName className) {
             // Called if we unexpected disconnected.
-            if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
+            if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
+                           className.getClassName());
             Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
+            if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
+                msg.arg1 = SERVICE_IBLUETOOTH;
+            } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
+                msg.arg1 = SERVICE_IBLUETOOTHGATT;
+            } else {
+                Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
+                return;
+            }
             mHandler.sendMessage(msg);
         }
     }
@@ -746,13 +775,18 @@
                 }
                 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
                 {
-                    if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
-
-                    //Remove timeout
-                    mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
+                    if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
 
                     IBinder service = (IBinder) msg.obj;
                     synchronized(mConnection) {
+                        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
+                            mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
+                            break;
+                        } // else must be SERVICE_IBLUETOOTH
+
+                        //Remove timeout
+                            mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
+
                         mBinding = false;
                         mBluetooth = IBluetooth.Stub.asInterface(service);
 
@@ -816,11 +850,19 @@
                 }
                 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
                 {
-                    Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
+                    Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
                     synchronized(mConnection) {
-                        // if service is unbinded already, do nothing and return
-                        if (mBluetooth == null) return;
-                        mBluetooth = null;
+                        if (msg.arg1 == SERVICE_IBLUETOOTH) {
+                            // if service is unbinded already, do nothing and return
+                            if (mBluetooth == null) break;
+                            mBluetooth = null;
+                        } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
+                            mBluetoothGatt = null;
+                            break;
+                        } else {
+                            Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
+                            break;
+                        }
                     }
 
                     if (mEnable) {
@@ -1048,10 +1090,19 @@
                 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
                 sendBluetoothStateCallback(isUp);
 
-                //If Bluetooth is off, send service down event to proxy objects, and unbind
-                if (!isUp && canUnbindBluetoothService()) {
-                    sendBluetoothServiceDownCallback();
-                    unbindAndFinish();
+                if (isUp) {
+                    // connect to GattService
+                    Intent i = new Intent(IBluetoothGatt.class.getName());
+                    if (!mContext.bindServiceAsUser(i, mConnection, Context.BIND_AUTO_CREATE,
+                                                    UserHandle.CURRENT)) {
+                        Log.e(TAG, "Fail to bind to: " + IBluetoothGatt.class.getName());
+                    }
+                } else {
+                    //If Bluetooth is off, send service down event to proxy objects, and unbind
+                    if (!isUp && canUnbindBluetoothService()) {
+                        sendBluetoothServiceDownCallback();
+                        unbindAndFinish();
+                    }
                 }
             }
 
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 0bb0366..9e06db8 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -2285,9 +2285,17 @@
         }
 
         // Update 464xlat state.
-        // TODO: Move to handleConnect()
         NetworkStateTracker tracker = mNetTrackers[netType];
         if (mClat.requiresClat(netType, tracker)) {
+            // If the connection was previously using clat, but is not using it now, stop the clat
+            // daemon. Normally, this happens automatically when the connection disconnects, but if
+            // the disconnect is not reported, or if the connection's LinkProperties changed for
+            // some other reason (e.g., handoff changes the IP addresses on the link), it would
+            // still be running. If it's not running, then stopping it is a no-op.
+            if (Nat464Xlat.isRunningClat(curLp) && !Nat464Xlat.isRunningClat(newLp)) {
+                mClat.stopClat();
+            }
+            // If the link requires clat to be running, then start the daemon now.
             if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
                 mClat.startClat(tracker);
             } else {
diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java
index 03679a5..944bf33 100644
--- a/services/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/java/com/android/server/accounts/AccountManagerService.java
@@ -541,6 +541,7 @@
         }
     }
 
+    @Override
     public boolean addAccount(Account account, String password, Bundle extras) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "addAccount: " + account
@@ -549,9 +550,13 @@
         }
         if (account == null) throw new IllegalArgumentException("account is null");
         checkAuthenticateAccountsPermission(account);
-        if (!canUserModifyAccounts(Binder.getCallingUid())) {
-            return false;
-        }
+        /*
+         * Child users are not allowed to add accounts. Only the accounts that are
+         * shared by the parent profile can be added to child profile.
+         *
+         * TODO: Only allow accounts that were shared to be added by
+         *     a limited user.
+         */
 
         UserAccounts accounts = getUserAccountsForCaller();
         // fails if the account already exists
@@ -588,12 +593,9 @@
                         if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
                             // Create a Session for the target user and pass in the bundle
                             completeCloningAccount(result, account, toAccounts);
-                        } else {
-                            clonePassword(fromAccounts, toAccounts, account);
                         }
                         return;
                     } else {
-                        clonePassword(fromAccounts, toAccounts, account);
                         super.onResult(result);
                     }
                 }
@@ -604,23 +606,6 @@
         return true;
     }
 
-    // TODO: Remove fallback - move to authenticator
-    private void clonePassword(UserAccounts fromAccounts, UserAccounts toAccounts,
-            Account account) {
-        long id = clearCallingIdentity();
-        try {
-            String password = readPasswordInternal(fromAccounts, account);
-            String extraFlags = readUserDataInternal(fromAccounts, account, "flags");
-            String extraServices = readUserDataInternal(fromAccounts, account, "services");
-            Bundle extras = new Bundle();
-            extras.putString("flags", extraFlags);
-            extras.putString("services", extraServices);
-            addAccountInternal(toAccounts, account, password, extras, true);
-        } finally {
-            restoreCallingIdentity(id);
-        }
-    }
-
     void completeCloningAccount(final Bundle result, final Account account,
             final UserAccounts targetUser) {
         long id = clearCallingIdentity();
diff --git a/services/java/com/android/server/connectivity/Nat464Xlat.java b/services/java/com/android/server/connectivity/Nat464Xlat.java
index 2884eaf..59403c5 100644
--- a/services/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/java/com/android/server/connectivity/Nat464Xlat.java
@@ -87,6 +87,10 @@
         return netType == TYPE_MOBILE && !lp.hasIPv4Address();
     }
 
+    public static boolean isRunningClat(LinkProperties lp) {
+      return lp != null && lp.getAllInterfaceNames().contains(CLAT_INTERFACE_NAME);
+    }
+
     /**
      * Starts the clat daemon.
      * @param lp The link properties of the interface to start clatd on.
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index e13a17b..70183df 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -1372,6 +1372,7 @@
                     // userId     - application-specific user id
                     // debugFlag  - 0 or 1 if the package is debuggable.
                     // dataPath   - path to package's data path
+                    // seinfo     - seinfo label for the app (assigned at install time)
                     //
                     // NOTE: We prefer not to expose all ApplicationInfo flags for now.
                     //
@@ -1385,6 +1386,8 @@
                     sb.append((int)ai.uid);
                     sb.append(isDebug ? " 1 " : " 0 ");
                     sb.append(dataPath);
+                    sb.append(" ");
+                    sb.append(ai.seinfo);
                     sb.append("\n");
                     str.write(sb.toString().getBytes());
                 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index c501553..a70ebf4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -111,9 +111,9 @@
 
     private void writePackagesList() {
         writeFile(new File(getContext().getFilesDir(), "system/packages.list"),
-                ( "com.google.app1 11000 0 /data/data/com.google.app1"
-                + "com.google.app2 11001 0 /data/data/com.google.app2"
-                + "com.android.app3 11030 0 /data/data/com.android.app3")
+                ( "com.google.app1 11000 0 /data/data/com.google.app1 seinfo1"
+                + "com.google.app2 11001 0 /data/data/com.google.app2 seinfo2"
+                + "com.android.app3 11030 0 /data/data/com.android.app3 seinfo3")
                 .getBytes());
     }
 
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index 2385c24..47f1fbf 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -1468,6 +1468,8 @@
         if (config.enterpriseConfig.migrateOldEapTlsNative(mWifiNative, netId)) {
             saveConfig();
         }
+
+        config.enterpriseConfig.migrateCerts(mKeyStore);
     }
 
     private String removeDoubleQuotes(String string) {
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 95ffb1c..f73a13c 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -17,9 +17,9 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.Process;
 import android.security.Credentials;
 import android.text.TextUtils;
-import android.util.Log;
 
 import com.android.org.bouncycastle.asn1.ASN1InputStream;
 import com.android.org.bouncycastle.asn1.ASN1Sequence;
@@ -481,7 +481,7 @@
         String caCertName = Credentials.CA_CERTIFICATE + name;
         if (mClientCertificate != null) {
             byte[] privKeyData = mClientPrivateKey.getEncoded();
-            ret = keyStore.importKey(privKeyName, privKeyData);
+            ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID);
             if (ret == false) {
                 return ret;
             }
@@ -489,7 +489,7 @@
             ret = putCertInKeyStore(keyStore, userCertName, mClientCertificate);
             if (ret == false) {
                 // Remove private key installed
-                keyStore.delKey(privKeyName);
+                keyStore.delKey(privKeyName, Process.WIFI_UID);
                 return ret;
             }
         }
@@ -499,8 +499,8 @@
             if (ret == false) {
                 if (mClientCertificate != null) {
                     // Remove client key+cert
-                    keyStore.delKey(privKeyName);
-                    keyStore.delete(userCertName);
+                    keyStore.delKey(privKeyName, Process.WIFI_UID);
+                    keyStore.delete(userCertName, Process.WIFI_UID);
                 }
                 return ret;
             }
@@ -525,7 +525,7 @@
             Certificate cert) {
         try {
             byte[] certData = Credentials.convertToPem(cert);
-            return keyStore.put(name, certData);
+            return keyStore.put(name, certData, Process.WIFI_UID);
         } catch (IOException e1) {
             return false;
         } catch (CertificateException e2) {
@@ -537,14 +537,14 @@
         String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX);
         // a valid client certificate is configured
         if (!TextUtils.isEmpty(client)) {
-            keyStore.delKey(Credentials.USER_PRIVATE_KEY + client);
-            keyStore.delete(Credentials.USER_CERTIFICATE + client);
+            keyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID);
+            keyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID);
         }
 
         String ca = getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX);
         // a valid ca certificate is configured
         if (!TextUtils.isEmpty(ca)) {
-            keyStore.delete(Credentials.CA_CERTIFICATE + ca);
+            keyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID);
         }
     }
 
@@ -625,6 +625,29 @@
         return true;
     }
 
+    /** Migrate certs from global pool to wifi UID if not already done */
+    void migrateCerts(android.security.KeyStore keyStore) {
+        String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX);
+        // a valid client certificate is configured
+        if (!TextUtils.isEmpty(client)) {
+            if (!keyStore.contains(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID)) {
+                keyStore.duplicate(Credentials.USER_PRIVATE_KEY + client, -1,
+                        Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID);
+                keyStore.duplicate(Credentials.USER_CERTIFICATE + client, -1,
+                        Credentials.USER_CERTIFICATE + client, Process.WIFI_UID);
+            }
+        }
+
+        String ca = getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX);
+        // a valid ca certificate is configured
+        if (!TextUtils.isEmpty(ca)) {
+            if (!keyStore.contains(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID)) {
+                keyStore.duplicate(Credentials.CA_CERTIFICATE + ca, -1,
+                        Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID);
+            }
+        }
+    }
+
     private String removeDoubleQuotes(String string) {
         int length = string.length();
         if ((length > 1) && (string.charAt(0) == '"')