Loading core/java/android/bluetooth/BluetoothAdapter.java +199 −11 Original line number Diff line number Diff line Loading @@ -27,14 +27,14 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.Pair; import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.HashMap; import java.util.LinkedList; import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Random; Loading Loading @@ -182,6 +182,43 @@ public final class BluetoothAdapter { public static final String EXTRA_DISCOVERABLE_DURATION = "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION"; /** * Activity Action: Show a system activity to request BLE advertising.<br> * If the device is not doing BLE advertising, this activity will start BLE advertising for the * device, otherwise it will continue BLE advertising using the current * {@link BluetoothAdvScanData}. <br> * Note this activity will also request the user to turn on Bluetooth if it's not currently * enabled. * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_START_ADVERTISING = "android.bluetooth.adapter.action.START_ADVERTISING"; /** * Activity Action: Stop the current BLE advertising. * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_STOP_ADVERTISING = "android.bluetooth.adapter.action.STOP_ADVERTISING"; /** * Broadcast Action: Indicate BLE Advertising is started. * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_BLUETOOTH_ADVERTISING_STARTED = "android.bluetooth.adapter.action.ADVERTISING_STARTED"; /** * Broadcast Action: Indicated BLE Advertising is stopped. * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_BLUETOOTH_ADVERTISING_STOPPED = "android.bluetooth.adapter.action.ADVERTISING_STOPPED"; /** * Activity Action: Show a system activity that allows the user to turn on * Bluetooth. Loading Loading @@ -251,7 +288,6 @@ public final class BluetoothAdapter { */ public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23; /** * Broadcast Action: The local Bluetooth adapter has started the remote * device discovery process. Loading Loading @@ -365,6 +401,8 @@ public final class BluetoothAdapter { private IBluetooth mService; private final Map<LeScanCallback, GattCallbackWrapper> mLeScanClients; private BluetoothAdvScanData mBluetoothAdvScanData = null; private GattCallbackWrapper mAdvertisingCallback; /** * Get a handle to the default local Bluetooth adapter. Loading Loading @@ -437,6 +475,97 @@ public final class BluetoothAdapter { address[0], address[1], address[2], address[3], address[4], address[5])); } /** * Returns a {@link BluetoothAdvScanData} object representing advertising data. * @hide */ public BluetoothAdvScanData getAdvScanData() { try { IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); if (iGatt == null) { // BLE is not supported Log.e(TAG, "failed to start, iGatt null"); return null; } if (mBluetoothAdvScanData == null) { mBluetoothAdvScanData = new BluetoothAdvScanData(iGatt, BluetoothAdvScanData.AD); } return mBluetoothAdvScanData; } catch (RemoteException e) { Log.e(TAG, "failed to get advScanData, error: " + e); return null; } } /** * Start BLE advertising using current {@link BluetoothAdvScanData}. * An app should start advertising by requesting * {@link BluetoothAdapter#ACTION_START_ADVERTISING} instead of calling this method directly. * <p>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. * <p>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. * <p>Equivalent to: Loading Loading @@ -848,6 +977,23 @@ public final class BluetoothAdapter { return false; } /** * Returns whether BLE is currently advertising. * <p>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. Loading Loading @@ -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 Loading @@ -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<BluetoothAdapter>(bluetoothAdapter); mLeScanCb = leScanCb; mScanFilter = uuid; mLeHandle = 0; mCallbackType = type; } public boolean scanStarted() { Loading @@ -1583,6 +1743,30 @@ public final class BluetoothAdapter { return started; } public void stopAdvertising() { synchronized (this) { if (mLeHandle <= 0) { Log.e(TAG, "Error state, mLeHandle: " + mLeHandle); return; } BluetoothAdapter adapter = mBluetoothAdapter.get(); if (adapter != null) { try { IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); iGatt.stopAdvertising(); Log.d(TAG, "unregeistering client " + mLeHandle); iGatt.unregisterClient(mLeHandle); } catch (RemoteException e) { Log.e(TAG, "Failed to stop advertising and unregister" + e); } } else { Log.e(TAG, "stopAdvertising, BluetoothAdapter is null"); } mLeHandle = -1; notifyAll(); } } public void stopLeScan() { synchronized(this) { if (mLeHandle <= 0) { Loading Loading @@ -1624,6 +1808,9 @@ public final class BluetoothAdapter { BluetoothAdapter adapter = mBluetoothAdapter.get(); if (adapter != null) { iGatt = adapter.getBluetoothManager().getBluetoothGatt(); if (mCallbackType == CALLBACK_TYPE_ADV) { iGatt.startAdvertising(mLeHandle); } else { if (mScanFilter == null) { iGatt.startScan(mLeHandle, false); } else { Loading @@ -1633,6 +1820,7 @@ public final class BluetoothAdapter { } iGatt.startScanWithUuids(mLeHandle, false, uuids); } } } else { Log.e(TAG, "onClientRegistered, BluetoothAdapter null"); mLeHandle = -1; Loading @@ -1642,7 +1830,7 @@ public final class BluetoothAdapter { mLeHandle = -1; } if (mLeHandle == -1) { // registration succeeded but start scan failed // registration succeeded but start scan or advertise failed if (iGatt != null) { try { iGatt.unregisterClient(mLeHandle); Loading core/java/android/bluetooth/BluetoothAdvScanData.java 0 → 100644 +147 −0 Original line number Diff line number Diff line /* * 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.os.ParcelUuid; import android.os.RemoteException; import android.util.Log; import java.util.Collections; import java.util.List; /** * This class provides the public APIs to set advertising and scan response data when BLE device * operates in peripheral mode. <br> * 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<ParcelUuid> getServiceUuids() { try { return Collections.unmodifiableList(mBluetoothGatt.getAdvServiceUuids()); } catch (RemoteException e) { return null; } } /** * Returns manufacturer data. */ public byte[] getManufacturerData() { if (mBluetoothGatt == null) return null; try { return mBluetoothGatt.getAdvManufacturerData(); } catch (RemoteException e) { return null; } } /** * Returns service data. */ public byte[] getServiceData() { if (mBluetoothGatt == null) return null; try { return mBluetoothGatt.getAdvServiceData(); } catch (RemoteException e) { return null; } } /** * Remove manufacturer data based on given manufacturer code. * @param manufacturerCode */ public void removeManufacturerCodeAndData(int manufacturerCode) { if (mBluetoothGatt != null) { try { mBluetoothGatt.removeAdvManufacturerCodeAndData(manufacturerCode); } catch (RemoteException e) { Log.e(TAG, e.toString()); } } } } core/java/android/bluetooth/BluetoothGatt.java +0 −73 Original line number Diff line number Diff line Loading @@ -553,14 +553,6 @@ public final class BluetoothGatt implements BluetoothProfile { Log.w(TAG, "Unhandled exception in callback", ex); } } /** * Listen command status callback * @hide */ public void onListen(int status) { if (DBG) Log.d(TAG, "onListen() - status=" + status); } }; /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device) { Loading Loading @@ -693,71 +685,6 @@ public final class BluetoothGatt implements BluetoothProfile { return true; } /** * Starts or stops sending of advertisement packages to listen for connection * requests from a central devices. * * <p>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. * * <p>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. Loading core/java/android/bluetooth/BluetoothGattServer.java +1 −1 Original line number Diff line number Diff line Loading @@ -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<BluetoothGattService> includedServices = service.getIncludedServices(); for (BluetoothGattService includedService : includedServices) { Loading core/java/android/bluetooth/BluetoothGattService.java +21 −2 Original line number Diff line number Diff line Loading @@ -15,8 +15,6 @@ */ package android.bluetooth; import android.bluetooth.BluetoothDevice; import java.util.ArrayList; import java.util.List; import java.util.UUID; Loading Loading @@ -81,6 +79,11 @@ public class BluetoothGattService { */ protected List<BluetoothGattService> mIncludedServices; /** * Whether the service uuid should be advertised. */ private boolean mAdvertisePreferred; /** * Create a new BluetoothGattService. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. Loading Loading @@ -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; } } Loading
core/java/android/bluetooth/BluetoothAdapter.java +199 −11 Original line number Diff line number Diff line Loading @@ -27,14 +27,14 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.Pair; import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.HashMap; import java.util.LinkedList; import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Random; Loading Loading @@ -182,6 +182,43 @@ public final class BluetoothAdapter { public static final String EXTRA_DISCOVERABLE_DURATION = "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION"; /** * Activity Action: Show a system activity to request BLE advertising.<br> * If the device is not doing BLE advertising, this activity will start BLE advertising for the * device, otherwise it will continue BLE advertising using the current * {@link BluetoothAdvScanData}. <br> * Note this activity will also request the user to turn on Bluetooth if it's not currently * enabled. * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_START_ADVERTISING = "android.bluetooth.adapter.action.START_ADVERTISING"; /** * Activity Action: Stop the current BLE advertising. * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_STOP_ADVERTISING = "android.bluetooth.adapter.action.STOP_ADVERTISING"; /** * Broadcast Action: Indicate BLE Advertising is started. * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_BLUETOOTH_ADVERTISING_STARTED = "android.bluetooth.adapter.action.ADVERTISING_STARTED"; /** * Broadcast Action: Indicated BLE Advertising is stopped. * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_BLUETOOTH_ADVERTISING_STOPPED = "android.bluetooth.adapter.action.ADVERTISING_STOPPED"; /** * Activity Action: Show a system activity that allows the user to turn on * Bluetooth. Loading Loading @@ -251,7 +288,6 @@ public final class BluetoothAdapter { */ public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23; /** * Broadcast Action: The local Bluetooth adapter has started the remote * device discovery process. Loading Loading @@ -365,6 +401,8 @@ public final class BluetoothAdapter { private IBluetooth mService; private final Map<LeScanCallback, GattCallbackWrapper> mLeScanClients; private BluetoothAdvScanData mBluetoothAdvScanData = null; private GattCallbackWrapper mAdvertisingCallback; /** * Get a handle to the default local Bluetooth adapter. Loading Loading @@ -437,6 +475,97 @@ public final class BluetoothAdapter { address[0], address[1], address[2], address[3], address[4], address[5])); } /** * Returns a {@link BluetoothAdvScanData} object representing advertising data. * @hide */ public BluetoothAdvScanData getAdvScanData() { try { IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); if (iGatt == null) { // BLE is not supported Log.e(TAG, "failed to start, iGatt null"); return null; } if (mBluetoothAdvScanData == null) { mBluetoothAdvScanData = new BluetoothAdvScanData(iGatt, BluetoothAdvScanData.AD); } return mBluetoothAdvScanData; } catch (RemoteException e) { Log.e(TAG, "failed to get advScanData, error: " + e); return null; } } /** * Start BLE advertising using current {@link BluetoothAdvScanData}. * An app should start advertising by requesting * {@link BluetoothAdapter#ACTION_START_ADVERTISING} instead of calling this method directly. * <p>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. * <p>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. * <p>Equivalent to: Loading Loading @@ -848,6 +977,23 @@ public final class BluetoothAdapter { return false; } /** * Returns whether BLE is currently advertising. * <p>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. Loading Loading @@ -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 Loading @@ -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<BluetoothAdapter>(bluetoothAdapter); mLeScanCb = leScanCb; mScanFilter = uuid; mLeHandle = 0; mCallbackType = type; } public boolean scanStarted() { Loading @@ -1583,6 +1743,30 @@ public final class BluetoothAdapter { return started; } public void stopAdvertising() { synchronized (this) { if (mLeHandle <= 0) { Log.e(TAG, "Error state, mLeHandle: " + mLeHandle); return; } BluetoothAdapter adapter = mBluetoothAdapter.get(); if (adapter != null) { try { IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); iGatt.stopAdvertising(); Log.d(TAG, "unregeistering client " + mLeHandle); iGatt.unregisterClient(mLeHandle); } catch (RemoteException e) { Log.e(TAG, "Failed to stop advertising and unregister" + e); } } else { Log.e(TAG, "stopAdvertising, BluetoothAdapter is null"); } mLeHandle = -1; notifyAll(); } } public void stopLeScan() { synchronized(this) { if (mLeHandle <= 0) { Loading Loading @@ -1624,6 +1808,9 @@ public final class BluetoothAdapter { BluetoothAdapter adapter = mBluetoothAdapter.get(); if (adapter != null) { iGatt = adapter.getBluetoothManager().getBluetoothGatt(); if (mCallbackType == CALLBACK_TYPE_ADV) { iGatt.startAdvertising(mLeHandle); } else { if (mScanFilter == null) { iGatt.startScan(mLeHandle, false); } else { Loading @@ -1633,6 +1820,7 @@ public final class BluetoothAdapter { } iGatt.startScanWithUuids(mLeHandle, false, uuids); } } } else { Log.e(TAG, "onClientRegistered, BluetoothAdapter null"); mLeHandle = -1; Loading @@ -1642,7 +1830,7 @@ public final class BluetoothAdapter { mLeHandle = -1; } if (mLeHandle == -1) { // registration succeeded but start scan failed // registration succeeded but start scan or advertise failed if (iGatt != null) { try { iGatt.unregisterClient(mLeHandle); Loading
core/java/android/bluetooth/BluetoothAdvScanData.java 0 → 100644 +147 −0 Original line number Diff line number Diff line /* * 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.os.ParcelUuid; import android.os.RemoteException; import android.util.Log; import java.util.Collections; import java.util.List; /** * This class provides the public APIs to set advertising and scan response data when BLE device * operates in peripheral mode. <br> * 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<ParcelUuid> getServiceUuids() { try { return Collections.unmodifiableList(mBluetoothGatt.getAdvServiceUuids()); } catch (RemoteException e) { return null; } } /** * Returns manufacturer data. */ public byte[] getManufacturerData() { if (mBluetoothGatt == null) return null; try { return mBluetoothGatt.getAdvManufacturerData(); } catch (RemoteException e) { return null; } } /** * Returns service data. */ public byte[] getServiceData() { if (mBluetoothGatt == null) return null; try { return mBluetoothGatt.getAdvServiceData(); } catch (RemoteException e) { return null; } } /** * Remove manufacturer data based on given manufacturer code. * @param manufacturerCode */ public void removeManufacturerCodeAndData(int manufacturerCode) { if (mBluetoothGatt != null) { try { mBluetoothGatt.removeAdvManufacturerCodeAndData(manufacturerCode); } catch (RemoteException e) { Log.e(TAG, e.toString()); } } } }
core/java/android/bluetooth/BluetoothGatt.java +0 −73 Original line number Diff line number Diff line Loading @@ -553,14 +553,6 @@ public final class BluetoothGatt implements BluetoothProfile { Log.w(TAG, "Unhandled exception in callback", ex); } } /** * Listen command status callback * @hide */ public void onListen(int status) { if (DBG) Log.d(TAG, "onListen() - status=" + status); } }; /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device) { Loading Loading @@ -693,71 +685,6 @@ public final class BluetoothGatt implements BluetoothProfile { return true; } /** * Starts or stops sending of advertisement packages to listen for connection * requests from a central devices. * * <p>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. * * <p>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. Loading
core/java/android/bluetooth/BluetoothGattServer.java +1 −1 Original line number Diff line number Diff line Loading @@ -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<BluetoothGattService> includedServices = service.getIncludedServices(); for (BluetoothGattService includedService : includedServices) { Loading
core/java/android/bluetooth/BluetoothGattService.java +21 −2 Original line number Diff line number Diff line Loading @@ -15,8 +15,6 @@ */ package android.bluetooth; import android.bluetooth.BluetoothDevice; import java.util.ArrayList; import java.util.List; import java.util.UUID; Loading Loading @@ -81,6 +79,11 @@ public class BluetoothGattService { */ protected List<BluetoothGattService> mIncludedServices; /** * Whether the service uuid should be advertised. */ private boolean mAdvertisePreferred; /** * Create a new BluetoothGattService. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. Loading Loading @@ -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; } }