diff options
author | Wei Wang <weiwa@google.com> | 2014-03-08 02:00:26 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-03-08 02:00:27 +0000 |
commit | b9703de9f4892341e2a1f5ea1908aed19018569f (patch) | |
tree | 8c5a4a5db8df20d3debcf88c8a7fcf10de1e436c | |
parent | e061a83b8cbd872cd9f0fea33717aa57112e6228 (diff) | |
parent | 873b8064cca4d0f32808842a39e54e305dd5b410 (diff) | |
download | android_packages_apps_Bluetooth-b9703de9f4892341e2a1f5ea1908aed19018569f.tar.gz android_packages_apps_Bluetooth-b9703de9f4892341e2a1f5ea1908aed19018569f.tar.bz2 android_packages_apps_Bluetooth-b9703de9f4892341e2a1f5ea1908aed19018569f.zip |
Merge "DO NOT MERGE BLE peripheral mode (2/4): Gatt Service Change." into klp-dev
-rw-r--r-- | jni/com_android_bluetooth_gatt.cpp | 38 | ||||
-rwxr-xr-x | src/com/android/bluetooth/btservice/AdapterService.java | 4 | ||||
-rw-r--r-- | src/com/android/bluetooth/btservice/ProfileService.java | 2 | ||||
-rw-r--r-- | src/com/android/bluetooth/gatt/GattService.java | 319 | ||||
-rw-r--r-- | src/com/android/bluetooth/gatt/HandleMap.java | 17 | ||||
-rw-r--r-- | src/com/android/bluetooth/gatt/ServiceDeclaration.java | 23 |
6 files changed, 327 insertions, 76 deletions
diff --git a/jni/com_android_bluetooth_gatt.cpp b/jni/com_android_bluetooth_gatt.cpp index 854a92500..d2cfd845b 100644 --- a/jni/com_android_bluetooth_gatt.cpp +++ b/jni/com_android_bluetooth_gatt.cpp @@ -158,7 +158,6 @@ static jmethodID method_onGetDescriptor; static jmethodID method_onGetIncludedService; static jmethodID method_onRegisterForNotifications; static jmethodID method_onReadRemoteRssi; -static jmethodID method_onClientListen; /** * Server callback methods @@ -423,14 +422,6 @@ void btgattc_remote_rssi_cb(int client_if,bt_bdaddr_t* bda, int rssi, int status 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 @@ static const btgatt_client_callbacks_t sGattClientCallbacks = { 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 @@ static void classInitNative(JNIEnv* env, jclass clazz) { 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 @@ static void gattClientReadRemoteRssiNative(JNIEnv* env, jobject object, jint cli 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 gattClientListenNative(JNIEnv *env, jobject object, } 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 @@ static JNINativeMethod sMethods[] = { {"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 @@ static JNINativeMethod sMethods[] = { {"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 6c7576a0d..bd419b3ba 100755 --- a/src/com/android/bluetooth/btservice/AdapterService.java +++ b/src/com/android/bluetooth/btservice/AdapterService.java @@ -471,7 +471,7 @@ public class AdapterService extends Service { /** * 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 @@ public class AdapterService extends Service { } } } -} +}
\ 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 e3d9196fe..0c1b70e3f 100644 --- a/src/com/android/bluetooth/btservice/ProfileService.java +++ b/src/com/android/bluetooth/btservice/ProfileService.java @@ -38,6 +38,8 @@ public abstract class ProfileService extends Service { 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 1ab6d87a5..0091ef54d 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 @@ import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; 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 @@ public class GattService extends ProfileService { * 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 @@ public class GattService extends ProfileService { } /** - * 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 @@ public class GattService extends ProfileService { 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 class GattService extends ProfileService { 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 @@ public class GattService extends ProfileService { 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 class GattService extends ProfileService { 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 @@ public class GattService extends ProfileService { 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 @@ public class GattService extends ProfileService { } } - 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 @@ public class GattService extends ProfileService { 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 @@ public class GattService extends ProfileService { 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 @@ public class GattService extends ProfileService { 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 @@ public class GattService extends ProfileService { } 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 @@ public class GattService extends ProfileService { 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 @@ public class GattService extends ProfileService { + 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 @@ public class GattService extends ProfileService { 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 @@ public class GattService extends ProfileService { 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 5d45654b9..187625a43 100644 --- a/src/com/android/bluetooth/gatt/HandleMap.java +++ b/src/com/android/bluetooth/gatt/HandleMap.java @@ -42,6 +42,7 @@ class HandleMap { 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 @@ class HandleMap { 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 @@ class HandleMap { 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 0c9a51b2f..1d0bc4e90 100644 --- a/src/com/android/bluetooth/gatt/ServiceDeclaration.java +++ b/src/com/android/bluetooth/gatt/ServiceDeclaration.java @@ -39,6 +39,7 @@ class ServiceDeclaration { 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 @@ class ServiceDeclaration { 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 @@ class ServiceDeclaration { 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 @@ class ServiceDeclaration { return entry; } + boolean isServiceAdvertisePreferred(UUID uuid) { + for (Entry entry : mEntries) { + if (entry.uuid.equals(uuid)) { + return entry.advertisePreferred; + } + } + return false; + } + int getNumHandles() { return mNumHandles; } |