Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} + * + * @return true if BLE avertising succeeds, false otherwise. + * @hide + */ + public boolean startAdvertising() { + if (getState() != STATE_ON) return false; + + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported. + return false; + } + // Restart/reset advertising packets if advertising is in progress. + if (isAdvertising()) { + // Invalid advertising callback. + if (mAdvertisingCallback == null || mAdvertisingCallback.mLeHandle == -1) { + Log.e(TAG, "failed to restart advertising, invalid callback"); + return false; + } + iGatt.startAdvertising(mAdvertisingCallback.mLeHandle); + return true; + } + UUID uuid = UUID.randomUUID(); + GattCallbackWrapper wrapper = + new GattCallbackWrapper(this, null, null, GattCallbackWrapper.CALLBACK_TYPE_ADV); + iGatt.registerClient(new ParcelUuid(uuid), wrapper); + mAdvertisingCallback = wrapper; + return true; + } catch (RemoteException e) { + Log.e(TAG, "", e); + return false; + } + } + + /** + * Stop BLE advertising. + * An app should stop advertising by requesting + * {@link BluetoothAdapter#ACTION_STOP_ADVERTISING} instead of calling this method directly. + *
Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} + * @return true if BLE advertising stops, false otherwise. + * @hide + */ + public boolean stopAdvertisting() { + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported + return false; + } + if (mAdvertisingCallback == null) { + // no callback. + return false; + } + mAdvertisingCallback.stopAdvertising(); + mAdvertisingCallback = null; + return true; + } catch (RemoteException e) { + Log.e(TAG, "", e); + return false; + } + } + /** * Return true if Bluetooth is currently enabled and ready for use. *
Equivalent to: @@ -848,6 +977,23 @@ public final class BluetoothAdapter { return false; } + /** + * Returns whether BLE is currently advertising. + *
Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+ *
+ * @hide
+ */
+ public boolean isAdvertising() {
+ if (getState() != STATE_ON) return false;
+ try {
+ IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
+ return iGatt.isAdvertising();
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ return false;
+ }
+
/**
* Return the set of {@link BluetoothDevice} objects that are bonded
* (paired) to the local adapter.
@@ -1546,8 +1692,12 @@ public final class BluetoothAdapter {
private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub {
private static final int LE_CALLBACK_REG_TIMEOUT = 2000;
private static final int LE_CALLBACK_REG_WAIT_COUNT = 5;
+ private static final int CALLBACK_TYPE_SCAN = 0;
+ private static final int CALLBACK_TYPE_ADV = 1;
private final LeScanCallback mLeScanCb;
+ private int mCallbackType;
+
// mLeHandle 0: not registered
// -1: scan stopped
// >0: registered and scan started
@@ -1561,6 +1711,16 @@ public final class BluetoothAdapter {
mLeScanCb = leScanCb;
mScanFilter = uuid;
mLeHandle = 0;
+ mCallbackType = CALLBACK_TYPE_SCAN;
+ }
+
+ public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, LeScanCallback leScanCb,
+ UUID[] uuid, int type) {
+ mBluetoothAdapter = new WeakReference Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
- * @param start Start or stop advertising
- */
- /*package*/ void listen(boolean start) {
- if (mContext == null || !mContext.getResources().
- getBoolean(com.android.internal.R.bool.config_bluetooth_le_peripheral_mode_supported)) {
- throw new UnsupportedOperationException("BluetoothGatt#listen is blocked");
- }
- if (DBG) Log.d(TAG, "listen() - start: " + start);
- if (mService == null || mClientIf == 0) return;
-
- try {
- mService.clientListen(mClientIf, start);
- } catch (RemoteException e) {
- Log.e(TAG,"",e);
- }
- }
-
- /**
- * Sets the advertising data contained in the adv. response packet.
- *
- * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
- * @param advData true to set adv. data, false to set scan response
- * @param includeName Inlucde the name in the adv. response
- * @param includeTxPower Include TX power value
- * @param minInterval Minimum desired scan interval (optional)
- * @param maxInterval Maximum desired scan interval (optional)
- * @param appearance The appearance flags for the device (optional)
- * @param manufacturerData Manufacturer specific data including company ID (optional)
- */
- /*package*/ void setAdvData(boolean advData, boolean includeName, boolean includeTxPower,
- Integer minInterval, Integer maxInterval,
- Integer appearance, Byte[] manufacturerData) {
- if (mContext == null || !mContext.getResources().
- getBoolean(com.android.internal.R.bool.config_bluetooth_le_peripheral_mode_supported)) {
- throw new UnsupportedOperationException("BluetoothGatt#setAdvData is blocked");
- }
- if (DBG) Log.d(TAG, "setAdvData()");
- if (mService == null || mClientIf == 0) return;
-
- byte[] data = new byte[0];
- if (manufacturerData != null) {
- data = new byte[manufacturerData.length];
- for(int i = 0; i != manufacturerData.length; ++i) {
- data[i] = manufacturerData[i];
- }
- }
-
- try {
- mService.setAdvData(mClientIf, !advData,
- includeName, includeTxPower,
- minInterval != null ? minInterval : 0,
- maxInterval != null ? maxInterval : 0,
- appearance != null ? appearance : 0, data);
- } catch (RemoteException e) {
- Log.e(TAG,"",e);
- }
- }
-
/**
* Disconnects an established connection, or cancels a connection attempt
* currently in progress.
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 58ee54fdb1004..153215cb52569 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -537,7 +537,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
try {
mService.beginServiceDeclaration(mServerIf, service.getType(),
service.getInstanceId(), service.getHandles(),
- new ParcelUuid(service.getUuid()));
+ new ParcelUuid(service.getUuid()), service.isAdvertisePreferred());
List Requires {@link android.Manifest.permission#BLUETOOTH} permission.
@@ -263,4 +266,20 @@ public class BluetoothGattService {
}
return null;
}
+
+ /**
+ * Returns whether the uuid of the service should be advertised.
+ * @hide
+ */
+ public boolean isAdvertisePreferred() {
+ return mAdvertisePreferred;
+ }
+
+ /**
+ * Set whether the service uuid should be advertised.
+ * @hide
+ */
+ public void setAdvertisePreferred(boolean advertisePreferred) {
+ this.mAdvertisePreferred = advertisePreferred;
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index abdf949ebcfd0..4b28516e15a2e 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -73,6 +73,9 @@ public final class BluetoothUuid {
public static final ParcelUuid MAS =
ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
+ public static final ParcelUuid BASE_UUID =
+ ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
+
public static final ParcelUuid[] RESERVED_UUIDS = {
AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
@@ -211,4 +214,17 @@ public final class BluetoothUuid {
long value = (uuid.getMostSignificantBits() & 0x0000FFFF00000000L) >>> 32;
return (int)value;
}
+
+ /**
+ * Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid.
+ * @param parcelUuid
+ * @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise.
+ */
+ public static boolean isShortUuid(ParcelUuid parcelUuid) {
+ UUID uuid = parcelUuid.getUuid();
+ if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
+ return false;
+ }
+ return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
+ }
}
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index df393dbb2899b..784cdcc5318cc 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -37,10 +37,15 @@ interface IBluetoothGatt {
void unregisterClient(in int clientIf);
void clientConnect(in int clientIf, in String address, in boolean isDirect);
void clientDisconnect(in int clientIf, in String address);
- void clientListen(in int clientIf, in boolean start);
- void setAdvData(in int clientIf, in boolean setScanRsp, in boolean inclName,
- in boolean inclTxPower, in int minInterval, in int maxInterval,
- in int appearance, in byte[] manufacturerData);
+ void startAdvertising(in int appIf);
+ void stopAdvertising();
+ boolean setAdvServiceData(in byte[] serviceData);
+ byte[] getAdvServiceData();
+ boolean setAdvManufacturerCodeAndData(int manufactureCode, in byte[] manufacturerData);
+ byte[] getAdvManufacturerData();
+ List
+ * The exact format is defined in Bluetooth 4.0 specification, Volume 3, Part C, Section 11
+ * @hide
+ */
+public final class BluetoothAdvScanData {
+
+ /**
+ * Available data types of {@link BluetoothAdvScanData}.
+ */
+ public static final int AD = 0; // Advertising Data
+ public static final int SCAN_RESPONSE = 1; // Scan Response
+ public static final int EIR = 2; // Extended Inquiry Response
+
+ private static final String TAG = "BluetoothAdvScanData";
+
+ /**
+ * Data type of BluetoothAdvScanData.
+ */
+ private final int mDataType;
+ /**
+ * Bluetooth Gatt Service.
+ */
+ private IBluetoothGatt mBluetoothGatt;
+
+ /**
+ * @param mBluetoothGatt
+ * @param dataType
+ */
+ public BluetoothAdvScanData(IBluetoothGatt mBluetoothGatt, int dataType) {
+ this.mBluetoothGatt = mBluetoothGatt;
+ this.mDataType = dataType;
+ }
+
+ /**
+ * @return advertising data type.
+ */
+ public int getDataType() {
+ return mDataType;
+ }
+
+ /**
+ * Set manufactureCode and manufactureData.
+ * Returns true if manufacturer data is set, false if there is no enough room to set
+ * manufacturer data or the data is already set.
+ * @param manufacturerCode - unique identifier for the manufacturer
+ * @param manufacturerData - data associated with the specific manufacturer.
+ */
+ public boolean setManufacturerData(int manufacturerCode, byte[] manufacturerData) {
+ if (mDataType != AD) return false;
+ try {
+ return mBluetoothGatt.setAdvManufacturerCodeAndData(manufacturerCode, manufacturerData);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Set service data. Note the service data can only be set when the data type is {@code AD};
+ * @param serviceData
+ */
+ public boolean setServiceData(byte[] serviceData) {
+
+ if (mDataType != AD) return false;
+ if (serviceData == null) return false;
+ try {
+ return mBluetoothGatt.setAdvServiceData(serviceData);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns an immutable list of service uuids that will be advertised.
+ */
+ public List