am b285350d: am b9703de9: Merge "DO NOT MERGE BLE peripheral mode (2/4): Gatt Service Change." into klp-dev

* commit 'b285350d6580a118940a0f7d62857a199e362283':
  DO NOT MERGE BLE peripheral mode (2/4): Gatt Service Change.
diff --git a/jni/com_android_bluetooth_gatt.cpp b/jni/com_android_bluetooth_gatt.cpp
index 854a925..d2cfd84 100644
--- a/jni/com_android_bluetooth_gatt.cpp
+++ b/jni/com_android_bluetooth_gatt.cpp
@@ -158,7 +158,6 @@
 static jmethodID method_onGetIncludedService;
 static jmethodID method_onRegisterForNotifications;
 static jmethodID method_onReadRemoteRssi;
-static jmethodID method_onClientListen;
 
 /**
  * Server callback methods
@@ -423,14 +422,6 @@
     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
 }
 
-void btgattc_listen_cb(int status, int client_if)
-{
-    CHECK_CALLBACK_ENV
-    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClientListen
-        , status, client_if);
-    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
-}
-
 static const btgatt_client_callbacks_t sGattClientCallbacks = {
     btgattc_register_app_cb,
     btgattc_scan_result_cb,
@@ -448,8 +439,7 @@
     btgattc_read_descriptor_cb,
     btgattc_write_descriptor_cb,
     btgattc_execute_write_cb,
-    btgattc_remote_rssi_cb,
-    btgattc_listen_cb
+    btgattc_remote_rssi_cb
 };
 
 
@@ -680,7 +670,6 @@
     method_onAttributeRead= env->GetMethodID(clazz, "onAttributeRead", "(Ljava/lang/String;IIIIZ)V");
     method_onAttributeWrite= env->GetMethodID(clazz, "onAttributeWrite", "(Ljava/lang/String;IIIIIZZ[B)V");
     method_onExecuteWrite= env->GetMethodID(clazz, "onExecuteWrite", "(Ljava/lang/String;III)V");
-    method_onClientListen = env->GetMethodID(clazz, "onClientListen", "(II)V");
 
     info("classInitNative: Success!");
 }
@@ -1058,7 +1047,7 @@
     sGattIf->client->read_remote_rssi(clientif, &bda);
 }
 
-static void gattClientListenNative(JNIEnv *env, jobject object,
+static void gattAdvertiseNative(JNIEnv *env, jobject object,
         jint client_if, jboolean start)
 {
     if (!sGattIf) return;
@@ -1066,17 +1055,28 @@
 }
 
 static void gattSetAdvDataNative(JNIEnv *env, jobject object, jint client_if, jboolean setScanRsp,
-        jboolean inclName, jboolean inclTxPower, jint minInterval, jint maxInterval, jint appearance,
-        jbyteArray manufacturerData)
+        jboolean inclName, jboolean inclTxPower, jint minInterval, jint maxInterval,
+        jint appearance, jbyteArray manufacturerData, jbyteArray serviceData,
+        jbyteArray serviceUuid)
 {
     if (!sGattIf) return;
-    jbyte* arr_data = env->GetByteArrayElements(manufacturerData, 0);
+    jbyte* arr_data = env->GetByteArrayElements(manufacturerData, NULL);
     uint16_t arr_len = (uint16_t) env->GetArrayLength(manufacturerData);
 
+    jbyte* service_data = env->GetByteArrayElements(serviceData, NULL);
+    uint16_t service_data_len = (uint16_t) env->GetArrayLength(serviceData);
+
+    jbyte* service_uuid = env->GetByteArrayElements(serviceUuid, NULL);
+    uint16_t service_uuid_len = (uint16_t) env->GetArrayLength(serviceUuid);
+
     sGattIf->client->set_adv_data(client_if, setScanRsp, inclName, inclTxPower,
-        minInterval, maxInterval, appearance, arr_len, (char*)arr_data);
+        minInterval, maxInterval, appearance, arr_len, (char*)arr_data,
+        service_data_len, (char*)service_data, service_uuid_len,
+        (char*)service_uuid);
 
     env->ReleaseByteArrayElements(manufacturerData, arr_data, JNI_ABORT);
+    env->ReleaseByteArrayElements(serviceData, service_data, JNI_ABORT);
+    env->ReleaseByteArrayElements(serviceUuid, service_uuid, JNI_ABORT);
 }
 
 
@@ -1292,7 +1292,7 @@
     {"gattClientExecuteWriteNative", "(IZ)V", (void *) gattClientExecuteWriteNative},
     {"gattClientRegisterForNotificationsNative", "(ILjava/lang/String;IIJJIJJZ)V", (void *) gattClientRegisterForNotificationsNative},
     {"gattClientReadRemoteRssiNative", "(ILjava/lang/String;)V", (void *) gattClientReadRemoteRssiNative},
-    {"gattClientListenNative", "(IZ)V", (void *) gattClientListenNative},
+    {"gattAdvertiseNative", "(IZ)V", (void *) gattAdvertiseNative},
 
     {"gattServerRegisterAppNative", "(JJ)V", (void *) gattServerRegisterAppNative},
     {"gattServerUnregisterAppNative", "(I)V", (void *) gattServerUnregisterAppNative},
@@ -1309,7 +1309,7 @@
     {"gattServerSendNotificationNative", "(III[B)V", (void *) gattServerSendNotificationNative},
     {"gattServerSendResponseNative", "(IIIIII[BI)V", (void *) gattServerSendResponseNative},
 
-    {"gattSetAdvDataNative", "(IZZZIII[B)V", (void *) gattSetAdvDataNative},
+    {"gattSetAdvDataNative", "(IZZZIII[B[B[B)V", (void *) gattSetAdvDataNative},
     {"gattTestNative", "(IJJLjava/lang/String;IIIII)V", (void *) gattTestNative},
 };
 
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index 6c7576a..bd419b3 100755
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -471,7 +471,7 @@
     /**
      * The Binder implementation must be declared to be a static class, with
      * the AdapterService instance passed in the constructor. Furthermore,
-     * when the AdapterService shuts down, the reference to the AdapterService 
+     * when the AdapterService shuts down, the reference to the AdapterService
      * must be explicitly removed.
      *
      * Otherwise, a memory leak can occur from repeated starting/stopping the
@@ -1432,4 +1432,4 @@
             }
         }
     }
-}
+}
\ No newline at end of file
diff --git a/src/com/android/bluetooth/btservice/ProfileService.java b/src/com/android/bluetooth/btservice/ProfileService.java
index e3d9196..0c1b70e 100644
--- a/src/com/android/bluetooth/btservice/ProfileService.java
+++ b/src/com/android/bluetooth/btservice/ProfileService.java
@@ -38,6 +38,8 @@
     public static final String BLUETOOTH_ADMIN_PERM =
             android.Manifest.permission.BLUETOOTH_ADMIN;
     public static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+    public static final String BLUETOOTH_PRIVILEGED =
+        android.Manifest.permission.BLUETOOTH_PRIVILEGED;
 
     public static interface IProfileServiceBinder extends IBinder {
         public boolean cleanup();
diff --git a/src/com/android/bluetooth/gatt/GattService.java b/src/com/android/bluetooth/gatt/GattService.java
index 1ab6d87..0091ef5 100644
--- a/src/com/android/bluetooth/gatt/GattService.java
+++ b/src/com/android/bluetooth/gatt/GattService.java
@@ -17,31 +17,30 @@
 package com.android.bluetooth.gatt;
 
 import android.app.Service;
-import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
 import android.bluetooth.IBluetoothGatt;
 import android.bluetooth.IBluetoothGattCallback;
 import android.bluetooth.IBluetoothGattServerCallback;
 import android.content.Intent;
 import android.os.IBinder;
-import android.os.IBinder.DeathRecipient;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.bluetooth.btservice.ProfileService;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 
-import com.android.bluetooth.btservice.ProfileService;
-import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder;
-
 /**
  * Provides Bluetooth Gatt profile, as a service in
  * the Bluetooth application.
@@ -50,7 +49,30 @@
 public class GattService extends ProfileService {
     private static final boolean DBG = GattServiceConfig.DBG;
     private static final String TAG = GattServiceConfig.TAG_PREFIX + "GattService";
-    BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();
+    private static final int DEFAULT_SCAN_INTERVAL_MILLIS = 200;
+
+    /**
+     * Max packet size for ble advertising, defined in Bluetooth Specification Version 4.0 [Vol 3].
+     */
+    private static final int ADVERTISING_PACKET_MAX_BYTES = 31;
+    /**
+     * Size overhead for advertising flag.
+     */
+    private static final int ADVERTISING_FLAGS_BYTES = 3;
+    /**
+     * Size overhead per field. Usually it's just one byte of field length and one byte of
+     * field type.
+     */
+    private static final int FIELD_OVERHEAD_BYTES = 2;
+
+    /**
+     * Byte size of 16 bit service uuid.
+     */
+    private static final int SHORT_UUID_BYTES = 2;
+    /**
+     * Byte size of 128 bit service uuid.
+     */
+    private static final int FULL_UUID_BYTES = 16;
 
     /**
      * Search queue to serialize remote onbject inspection.
@@ -74,7 +96,14 @@
      * Server handle map.
      */
     HandleMap mHandleMap = new HandleMap();
+    private List<UUID> mAdvertisingServiceUuids = new ArrayList<UUID>();
 
+    private int mAdvertisingClientIf = 0;
+
+    private byte[] mServiceData = new byte[0];
+    private int mManufacturerCode = -1;
+    private byte[] mManufacturerData = new byte[0];
+    private boolean mIsAdvertising = false;
     /**
      * Pending service declaration queue
      */
@@ -111,7 +140,7 @@
     }
 
     /**
-     * List of clients intereste in scan results.
+     * List of clients interested in scan results.
      */
     private List<ScanClient> mScanQueue = new ArrayList<ScanClient>();
 
@@ -126,7 +155,7 @@
 
     private void removeScanClient(int appIf, boolean isServer) {
         for(ScanClient client : mScanQueue) {
-            if (client.appIf == appIf && client.isServer == isServer) {
+          if (client.appIf == appIf && client.isServer == isServer) {
                 mScanQueue.remove(client);
                 break;
             }
@@ -196,7 +225,11 @@
 
         public void binderDied() {
             if (DBG) Log.d(TAG, "Binder is dead - unregistering client (" + mAppIf + ")!");
-            stopScan(mAppIf, false);
+            if (mAdvertisingClientIf == mAppIf) {
+                stopAdvertising();
+            } else {
+                stopScan(mAppIf, false);
+            }
             unregisterClient(mAppIf);
         }
     }
@@ -287,12 +320,6 @@
             service.clientDisconnect(clientIf, address);
         }
 
-        public void clientListen(int clientIf, boolean start) {
-            GattService service = getService();
-            if (service == null) return;
-            service.clientListen(clientIf, start);
-        }
-
         public void refreshDevice(int clientIf, String address) {
             GattService service = getService();
             if (service == null) return;
@@ -411,11 +438,11 @@
 
         public void beginServiceDeclaration(int serverIf, int srvcType,
                                             int srvcInstanceId, int minHandles,
-                                            ParcelUuid srvcId) {
+                                            ParcelUuid srvcId, boolean advertisePreferred) {
             GattService service = getService();
             if (service == null) return;
             service.beginServiceDeclaration(serverIf, srvcType, srvcInstanceId,
-                               minHandles, srvcId.getUuid());
+                               minHandles, srvcId.getUuid(), advertisePreferred);
         }
 
         public void addIncludedService(int serverIf, int srvcType,
@@ -478,13 +505,68 @@
                 srvcId.getUuid(), charInstanceId, charId.getUuid(), confirm, value);
         }
 
-        public void setAdvData(int serverIf, boolean setScanRsp, boolean inclName,
-                                boolean inclTxPower, int minInterval, int maxInterval,
-                                int appearance, byte[] manufacturerData) {
+        @Override
+        public void startAdvertising(int appIf) throws RemoteException {
             GattService service = getService();
             if (service == null) return;
-            service.setAdvData(serverIf, setScanRsp, inclName, inclTxPower,
-                minInterval, maxInterval, appearance, manufacturerData);
+            service.startAdvertising(appIf);
+        }
+
+        @Override
+        public boolean isAdvertising() {
+            GattService service = getService();
+            if (service == null) return false;
+            return service.isAdvertising();
+        }
+
+        @Override
+        public void stopAdvertising() throws RemoteException {
+            GattService service = getService();
+            if (service == null) return;
+            service.stopAdvertising();
+        }
+
+        @Override
+        public boolean setAdvServiceData(byte[] serviceData) throws RemoteException {
+            GattService service = getService();
+            if (service == null) return false;
+            return service.setAdvServiceData(serviceData);
+        }
+
+        @Override
+        public byte[] getAdvServiceData() throws RemoteException {
+            GattService service = getService();
+            if (service == null) return null;
+            return service.getAdvServiceData();
+        }
+
+        @Override
+        public boolean setAdvManufacturerCodeAndData(int manufactureCode, byte[] manufacturerData)
+            throws RemoteException {
+            GattService service = getService();
+            if (service == null) return false;
+            return service.setAdvManufacturerCodeAndData(manufactureCode, manufacturerData);
+        }
+
+        @Override
+        public byte[] getAdvManufacturerData() throws RemoteException {
+            GattService service = getService();
+            if (service == null) return null;
+            return service.getAdvManufacturerData();
+        }
+
+        @Override
+        public List<ParcelUuid> getAdvServiceUuids() throws RemoteException {
+            GattService service = getService();
+            if (service == null) return null;
+            return service.getAdvServiceUuids();
+        }
+
+        @Override
+        public void removeAdvManufacturerCodeAndData(int manufacturerCode) throws RemoteException {
+            GattService service = getService();
+            if (service == null) return;
+            service.removeAdvManufacturerCodeAndData(manufacturerCode);
         }
     };
 
@@ -835,16 +917,6 @@
         }
     }
 
-    void onClientListen(int status, int clientIf)
-            throws RemoteException {
-        if (DBG) Log.d(TAG, "onClientListen() status=" + status);
-
-        ClientMap.App app = mClientMap.getById(clientIf);
-        if (app == null) return;
-
-        app.callback.onListen(status);
-    }
-
     /**************************************************************************
      * GATT Service functions - Shared CLIENT/SERVER
      *************************************************************************/
@@ -969,9 +1041,128 @@
         gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0);
     }
 
-    void clientListen(int clientIf, boolean start) {
-        if (DBG) Log.d(TAG, "clientListen() - start=" + start);
-        gattClientListenNative(clientIf, start);
+    synchronized boolean setAdvServiceData(byte[] serviceData) {
+        enforcePrivilegedPermission();
+        if (serviceData == null) return false;
+        // Calculate how many more bytes are needed for advertising service data field.
+        int extraBytes = (mServiceData == null) ?
+                FIELD_OVERHEAD_BYTES + serviceData.length :
+                    serviceData.length - mServiceData.length;
+        if (getAvailableSize() < extraBytes) {
+            Log.e(TAG, "cannot set service data, available size " + getAvailableSize());
+            return false;
+        }
+        mServiceData = serviceData;
+        return true;
+    }
+
+    byte[] getAdvServiceData() {
+        enforcePrivilegedPermission();
+        return mServiceData;
+    }
+
+    synchronized boolean setAdvManufacturerCodeAndData(
+        int manufacturerCode, byte[] manufacturerData) {
+        enforcePrivilegedPermission();
+        if (manufacturerCode <= 0 || manufacturerData == null) {
+            return false;
+        }
+        if (mManufacturerCode > 0 && mManufacturerData != null) {
+            Log.e(TAG, "manufacture data is already set");
+            return false;
+        }
+        if (getAvailableSize() <
+            FIELD_OVERHEAD_BYTES + manufacturerData.length) {
+            Log.e(TAG, "cannot set manu data, available size " + getAvailableSize());
+            return false;
+        }
+        this.mManufacturerCode = manufacturerCode;
+        this.mManufacturerData = manufacturerData;
+        return true;
+    }
+
+    void removeAdvManufacturerCodeAndData(int manufacturerCode) {
+        enforcePrivilegedPermission();
+        if (mManufacturerCode != manufacturerCode) {
+            return;
+        }
+        mManufacturerCode = -1;
+        mManufacturerData = new byte[0];
+    }
+
+    byte[] getAdvManufacturerData() {
+        enforcePrivilegedPermission();
+        return mManufacturerData;
+    }
+
+    synchronized List<ParcelUuid> getAdvServiceUuids() {
+        enforcePrivilegedPermission();;
+        boolean fullUuidFound = false;
+        List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
+        for (HandleMap.Entry entry : mHandleMap.mEntries) {
+            if (entry.advertisePreferred) {
+                ParcelUuid parcelUuid = new ParcelUuid(entry.uuid);
+                if (BluetoothUuid.isShortUuid(parcelUuid)) {
+                    serviceUuids.add(parcelUuid);
+                } else {
+                    // Allow at most one 128 bit service uuid to be advertised.
+                    if (!fullUuidFound) {
+                      fullUuidFound = true;
+                      serviceUuids.add(parcelUuid);
+                    }
+                }
+            }
+        }
+        return serviceUuids;
+    }
+
+    boolean isAdvertising() {
+        enforcePrivilegedPermission();
+        return mIsAdvertising;
+    }
+
+    void startAdvertising(int clientIf) {
+        enforcePrivilegedPermission();
+        if (DBG) Log.d(TAG, "start advertising for app - " + clientIf);
+        List<ParcelUuid> serviceUuids = getAdvServiceUuids();
+        int advertisingServiceUuidLength = serviceUuids == null ? 0 : serviceUuids.size();
+
+        // Note according to Bluetooth Spec Version 4.0, for advertising and scan response data
+        // "all numerical multi-byte entities and values shall use little-endian byte order".
+        ByteBuffer advertisingUuidBytes = ByteBuffer.allocate(advertisingServiceUuidLength * 16)
+                .order(ByteOrder.LITTLE_ENDIAN);
+        for (ParcelUuid parcelUuid : serviceUuids) {
+            UUID uuid = parcelUuid.getUuid();
+            // Least signifcant bits first as the advertising uuid should be in little-endian.
+            advertisingUuidBytes.putLong(uuid.getLeastSignificantBits())
+                    .putLong(uuid.getMostSignificantBits());
+        }
+
+        // Set advertising data.
+        gattSetAdvDataNative(clientIf,
+                false,  // not scan response data
+                false,  // no device name
+                false,  // no tx power included
+                DEFAULT_SCAN_INTERVAL_MILLIS,
+                DEFAULT_SCAN_INTERVAL_MILLIS,
+                0,  // no appearance limit
+                mManufacturerData,
+                mServiceData,
+                advertisingUuidBytes.array());
+
+        // Start advertising if advertising is not already started.
+        if (!isAdvertising()) {
+            gattAdvertiseNative(clientIf, true);
+            mAdvertisingClientIf = clientIf;
+            mIsAdvertising = true;
+        }
+    }
+
+    void stopAdvertising() {
+        enforcePrivilegedPermission();
+        gattAdvertiseNative(mAdvertisingClientIf, false);
+        mAdvertisingClientIf = 0;
+        mIsAdvertising = false;
     }
 
     List<String> getConnectedDevices() {
@@ -1133,15 +1324,6 @@
         gattClientReadRemoteRssiNative(clientIf, address);
     }
 
-    void setAdvData(int serverIf, boolean setScanRsp, boolean inclName,
-                boolean inclTxPower, int minInterval, int maxInterval,
-                int appearance, byte[] manufacturerData) {
-        if (DBG) Log.d(TAG, "setAdvData() - setScanRsp=" + setScanRsp);
-        if (minInterval == 0) maxInterval = 0;
-        gattSetAdvDataNative(serverIf, setScanRsp, inclName, inclTxPower,
-            minInterval, maxInterval, appearance, manufacturerData);
-    }
-
     /**************************************************************************
      * Callback functions - SERVER
      *************************************************************************/
@@ -1165,8 +1347,11 @@
         UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb);
         if (DBG) Log.d(TAG, "onServiceAdded() UUID=" + uuid + ", status=" + status
             + ", handle=" + srvcHandle);
-        if (status == 0)
-            mHandleMap.addService(serverIf, srvcHandle, uuid, srvcType, srvcInstId);
+        if (status == 0) {
+            mHandleMap.addService(serverIf, srvcHandle, uuid, srvcType, srvcInstId,
+                mAdvertisingServiceUuids.remove(uuid));
+        }
+
         continueServiceDeclaration(serverIf, status, srvcHandle);
     }
 
@@ -1397,12 +1582,13 @@
     }
 
     void beginServiceDeclaration(int serverIf, int srvcType, int srvcInstanceId,
-                                 int minHandles, UUID srvcUuid) {
+                                 int minHandles, UUID srvcUuid, boolean advertisePreferred) {
         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
 
         if (DBG) Log.d(TAG, "beginServiceDeclaration() - uuid=" + srvcUuid);
         ServiceDeclaration serviceDeclaration = addDeclaration();
-        serviceDeclaration.addService(srvcUuid, srvcType, srvcInstanceId, minHandles);
+        serviceDeclaration.addService(srvcUuid, srvcType, srvcInstanceId, minHandles,
+            advertisePreferred);
     }
 
     void addIncludedService(int serverIf, int srvcType, int srvcInstanceId,
@@ -1511,6 +1697,33 @@
         return type;
     }
 
+    private synchronized int getAvailableSize() {
+        enforcePrivilegedPermission();
+        int availableSize = ADVERTISING_PACKET_MAX_BYTES - ADVERTISING_FLAGS_BYTES;
+
+        for (ParcelUuid parcelUuid : getAdvServiceUuids()) {
+            if (BluetoothUuid.isShortUuid(parcelUuid)) {
+                availableSize -= FIELD_OVERHEAD_BYTES + SHORT_UUID_BYTES;
+            } else {
+                availableSize -= FIELD_OVERHEAD_BYTES + FULL_UUID_BYTES;
+            }
+        }
+        if (mManufacturerCode > 0 && mManufacturerData != null) {
+            availableSize -= (FIELD_OVERHEAD_BYTES + mManufacturerData.length);
+        }
+        if (mServiceData != null) {
+            availableSize -= (FIELD_OVERHEAD_BYTES + mServiceData.length);
+        }
+        return availableSize;
+    }
+
+    // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be
+    // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission.
+    private void enforcePrivilegedPermission() {
+        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
+            "Need BLUETOOTH_PRIVILEGED permission");
+    }
+
     private void continueSearch(int connId, int status) throws RemoteException {
         if (status == 0 && !mSearchQueue.isEmpty()) {
             SearchQueue.Entry svc = mSearchQueue.pop();
@@ -1548,6 +1761,9 @@
                 + entry.type);
             switch(entry.type) {
                 case ServiceDeclaration.TYPE_SERVICE:
+                    if (entry.advertisePreferred) {
+                        mAdvertisingServiceUuids.add(entry.uuid);
+                    }
                     gattServerAddServiceNative(serverIf, entry.serviceType,
                         entry.instance,
                         entry.uuid.getLeastSignificantBits(),
@@ -1592,6 +1808,7 @@
             ServerMap.App app = mServerMap.getById(serverIf);
             if (app != null) {
                 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(srvcHandle);
+
                 if (serviceEntry != null) {
                     app.callback.onServiceAdded(status, serviceEntry.serviceType,
                         serviceEntry.instance, new ParcelUuid(serviceEntry.uuid));
@@ -1772,11 +1989,11 @@
     private native void gattClientReadRemoteRssiNative(int clientIf,
             String address);
 
-    private native void gattClientListenNative(int client_if, boolean start);
+    private native void gattAdvertiseNative(int client_if, boolean start);
 
     private native void gattSetAdvDataNative(int serverIf, boolean setScanRsp, boolean inclName,
             boolean inclTxPower, int minInterval, int maxInterval,
-            int appearance, byte[] manufacturerData);
+            int appearance, byte[] manufacturerData, byte[] serviceData, byte[] serviceUuid);
 
     private native void gattServerRegisterAppNative(long app_uuid_lsb,
                                                     long app_uuid_msb);
diff --git a/src/com/android/bluetooth/gatt/HandleMap.java b/src/com/android/bluetooth/gatt/HandleMap.java
index 5d45654..187625a 100644
--- a/src/com/android/bluetooth/gatt/HandleMap.java
+++ b/src/com/android/bluetooth/gatt/HandleMap.java
@@ -42,6 +42,7 @@
         int serviceHandle = 0;
         int charHandle = 0;
         boolean started = false;
+        boolean advertisePreferred = false;
 
         Entry(int serverIf, int handle, UUID uuid, int serviceType, int instance) {
             this.serverIf = serverIf;
@@ -52,6 +53,17 @@
             this.serviceType = serviceType;
         }
 
+        Entry(int serverIf, int handle, UUID uuid, int serviceType, int instance,
+            boolean advertisePreferred) {
+            this.serverIf = serverIf;
+            this.type = TYPE_SERVICE;
+            this.handle = handle;
+            this.uuid = uuid;
+            this.instance = instance;
+            this.serviceType = serviceType;
+            this.advertisePreferred = advertisePreferred;
+        }
+
         Entry(int serverIf, int type, int handle, UUID uuid, int serviceHandle) {
             this.serverIf = serverIf;
             this.type = type;
@@ -86,8 +98,9 @@
         mRequestMap.clear();
     }
 
-    void addService(int serverIf, int handle, UUID uuid, int serviceType, int instance) {
-        mEntries.add(new Entry(serverIf, handle, uuid, serviceType, instance));
+    void addService(int serverIf, int handle, UUID uuid, int serviceType, int instance,
+        boolean advertisePreferred) {
+        mEntries.add(new Entry(serverIf, handle, uuid, serviceType, instance, advertisePreferred));
     }
 
     void addCharacteristic(int serverIf, int handle, UUID uuid, int serviceHandle) {
diff --git a/src/com/android/bluetooth/gatt/ServiceDeclaration.java b/src/com/android/bluetooth/gatt/ServiceDeclaration.java
index 0c9a51b..1d0bc4e 100644
--- a/src/com/android/bluetooth/gatt/ServiceDeclaration.java
+++ b/src/com/android/bluetooth/gatt/ServiceDeclaration.java
@@ -39,6 +39,7 @@
         int properties = 0;
         int serviceType = 0;
         int serviceHandle = 0;
+        boolean advertisePreferred = false;
 
         Entry(UUID uuid, int serviceType, int instance) {
             this.type = TYPE_SERVICE;
@@ -47,6 +48,14 @@
             this.serviceType = serviceType;
         }
 
+        Entry(UUID uuid, int serviceType, int instance, boolean advertisePreferred) {
+          this.type = TYPE_SERVICE;
+          this.uuid = uuid;
+          this.instance = instance;
+          this.serviceType = serviceType;
+          this.advertisePreferred = advertisePreferred;
+        }
+
         Entry(UUID uuid, int properties, int permissions, int instance) {
             this.type = TYPE_CHARACTERISTIC;
             this.uuid = uuid;
@@ -69,8 +78,9 @@
         mEntries = new ArrayList<Entry>();
     }
 
-    void addService(UUID uuid, int serviceType, int instance, int minHandles) {
-        mEntries.add(new Entry(uuid, serviceType, instance));
+    void addService(UUID uuid, int serviceType, int instance, int minHandles,
+        boolean advertisePreferred) {
+        mEntries.add(new Entry(uuid, serviceType, instance, advertisePreferred));
         if (minHandles == 0) {
             ++mNumHandles;
         } else {
@@ -102,6 +112,15 @@
         return entry;
     }
 
+    boolean isServiceAdvertisePreferred(UUID uuid) {
+      for (Entry entry : mEntries) {
+          if (entry.uuid.equals(uuid)) {
+              return entry.advertisePreferred;
+          }
+      }
+      return false;
+    }
+
     int getNumHandles() {
         return mNumHandles;
     }