diff options
| author | Matthew Xie <mattx@google.com> | 2013-04-11 16:36:26 -0700 |
|---|---|---|
| committer | Matthew Xie <mattx@google.com> | 2013-04-17 20:49:33 -0700 |
| commit | 01e8e2ac8e6994921b811f741b2d4dbe99b50b19 (patch) | |
| tree | f0f2141a687075d4fa19b5af0a7ea70e2b5feae4 /framework/java/android/bluetooth/BluetoothAdapter.java | |
| parent | 6b79decb475fdfc95e7ea193016d015bb0e94bd5 (diff) | |
Remove BluetoothAdapterCallback. Simplify leScan Api
App does not need to explicitly register/unregister callback
bug 8599881
Change-Id: I18cfef14d7ddb344722945e657dcb959823b412b
Diffstat (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java')
| -rw-r--r-- | framework/java/android/bluetooth/BluetoothAdapter.java | 422 |
1 files changed, 257 insertions, 165 deletions
diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 2e9c9e334d..3498bb8e47 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -20,7 +20,6 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; import android.os.Binder; -import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.ParcelUuid; @@ -30,11 +29,14 @@ 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.Map; import java.util.Random; import java.util.Set; import java.util.UUID; @@ -357,9 +359,7 @@ public final class BluetoothAdapter { private final IBluetoothManager mManagerService; private IBluetooth mService; - private Handler mServiceRecordHandler; - private BluetoothAdapterCallback mCallback; - private int mClientIf; + private final Map<LeScanCallback, GattCallbackWrapper> mLeScanClients; /** * Get a handle to the default local Bluetooth adapter. @@ -394,7 +394,7 @@ public final class BluetoothAdapter { mService = managerService.registerAdapter(mManagerCallback); } catch (RemoteException e) {Log.e(TAG, "", e);} mManagerService = managerService; - mServiceRecordHandler = null; + mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>(); } /** @@ -1409,72 +1409,38 @@ public final class BluetoothAdapter { } /** - * Register an callback to receive async results, such as LE scan result. + * Callback interface used to deliver LE scan results. * - * <p>This is an asynchronous call. The callback - * {@link BluetoothAdapterCallback#onCallbackRegistration} - * is used to notify success or failure if the function returns true. - * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. - * - * @param callback BluetootAdapter callback handler that will receive asynchronous callbacks. - * @return If true, the callback will be called to notify success or failure, - * false on immediate error - */ - public boolean registerCallback(BluetoothAdapterCallback callback) { - try { - IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); - mCallback = callback; - UUID uuid = UUID.randomUUID(); - if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid); - - iGatt.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback); - return true; - } catch (RemoteException e) { - Log.e(TAG,"",e); - return false; - } - } - - /** - * Unregister the registered callback. - */ - public boolean unRegisterCallback(BluetoothAdapterCallback callback) { - if (callback != mCallback) return false; - try { - IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); - - iGatt.unregisterClient(mClientIf); - return true; - } catch (RemoteException e) { - Log.e(TAG,"",e); - return false; - } + * @see #startLeScan(LeScanCallback) + * @see #startLeScan(UUID[], LeScanCallback) + */ + public interface LeScanCallback { + /** + * Callback reporting an LE device found during a device scan initiated + * by the {@link BluetoothAdapter#startLeScan} function. + * + * @param device Identifies the remote device + * @param rssi The RSSI value for the remote device as reported by the + * Bluetooth hardware. 0 if no RSSI value is available. + * @param scanRecord The content of the advertisement record offered by + * the remote device. + */ + public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord); } /** * Starts a scan for Bluetooth LE devices. * * <p>Results of the scan are reported using the - * {@link BluetoothAdapterCallback#onLeScan} callback. + * {@link LeScanCallback#onLeScan} callback. * * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * + * @param callback the callback LE scan results are delivered * @return true, if the scan was started successfully */ - public boolean startLeScan() { - if (DBG) Log.d(TAG, "startLeScan()"); - if (mClientIf == 0) return false; - - try { - IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); - iGatt.startScan(mClientIf, false); - } catch (RemoteException e) { - Log.e(TAG,"",e); - return false; - } - - return true; + public boolean startLeScan(LeScanCallback callback) { + return startLeScan(null, callback); } /** @@ -1482,155 +1448,281 @@ public final class BluetoothAdapter { * advertise given services. * * <p>Devices which advertise all specified services are reported using the - * {@link BluetoothAdapterCallback#onLeScan} callback. + * {@link LeScanCallback#onLeScan} callback. * * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * * @param serviceUuids Array of services to look for + * @param callback the callback LE scan results are delivered * @return true, if the scan was started successfully */ - public boolean startLeScan(UUID[] serviceUuids) { - if (DBG) Log.d(TAG, "startLeScan() - with UUIDs"); - if (mClientIf == 0) return false; + public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) { + if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids); - try { - IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); - ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length]; - for(int i = 0; i != uuids.length; ++i) { - uuids[i] = new ParcelUuid(serviceUuids[i]); - } - iGatt.startScanWithUuids(mClientIf, false, uuids); - } catch (RemoteException e) { - Log.e(TAG,"",e); + if (callback == null) { + if (DBG) Log.e(TAG, "startLeScan: null callback"); return false; } - return true; + synchronized(mLeScanClients) { + if (mLeScanClients.containsKey(callback)) { + if (DBG) Log.e(TAG, "LE Scan has already started"); + return false; + } + + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + UUID uuid = UUID.randomUUID(); + GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids); + + iGatt.registerClient(new ParcelUuid(uuid), wrapper); + if (wrapper.scanStarted()) { + mLeScanClients.put(callback, wrapper); + return true; + } + } catch (RemoteException e) { + Log.e(TAG,"",e); + } + } + return false; } /** * Stops an ongoing Bluetooth LE device scan. * * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. - */ - public void stopLeScan() { - if (DBG) Log.d(TAG, "stopScan()"); - if (mClientIf == 0) return; - - try { - IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); - iGatt.stopScan(mClientIf, false); - } catch (RemoteException e) { - Log.e(TAG,"",e); + * + * @param callback used to identify which scan to stop + * must be the same handle used to start the scan + */ + public void stopLeScan(LeScanCallback callback) { + if (DBG) Log.d(TAG, "stopLeScan()"); + GattCallbackWrapper wrapper; + synchronized(mLeScanClients) { + wrapper = mLeScanClients.remove(callback); + if (wrapper == null) return; } + wrapper.stopLeScan(); } /** * Bluetooth GATT interface callbacks */ - private final IBluetoothGattCallback mBluetoothGattCallback = - new IBluetoothGattCallback.Stub() { - /** - * Application interface registered - app is ready to go - */ - public void onClientRegistered(int status, int clientIf) { - if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status - + " clientIf=" + clientIf); - mClientIf = clientIf; - mCallback.onCallbackRegistration(status == BluetoothGatt.GATT_SUCCESS ? - BluetoothAdapterCallback.CALLBACK_REGISTERED : - BluetoothAdapterCallback.CALLBACK_REGISTRATION_FAILURE); - } + 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 final LeScanCallback mLeScanCb; + // mLeHandle 0: not registered + // -1: scan stopped + // >0: registered and scan started + private int mLeHandle; + private final UUID[] mScanFilter; + private WeakReference<BluetoothAdapter> mBluetoothAdapter; + + public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, + LeScanCallback leScanCb, UUID[] uuid) { + mBluetoothAdapter = new WeakReference<BluetoothAdapter>(bluetoothAdapter); + mLeScanCb = leScanCb; + mScanFilter = uuid; + mLeHandle = 0; + } - public void onClientConnectionState(int status, int clientIf, - boolean connected, String address) { - // no op + public boolean scanStarted() { + boolean started = false; + synchronized(this) { + if (mLeHandle == -1) return false; + + int count = 0; + // wait for callback registration and LE scan to start + while (mLeHandle == 0 && count < LE_CALLBACK_REG_WAIT_COUNT) { + try { + wait(LE_CALLBACK_REG_TIMEOUT); + } catch (InterruptedException e) { + Log.e(TAG, "Callback reg wait interrupted: " + e); + } + count++; + } + started = (mLeHandle > 0); } + return started; + } - /** - * Callback reporting an LE scan result. - * @hide - */ - public void onScanResult(String address, int rssi, byte[] advData) { - if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); - - try { - mCallback.onLeScan(getRemoteDevice(address), rssi, advData); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception: " + ex); + public void stopLeScan() { + 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.stopScan(mLeHandle, false); + iGatt.unregisterClient(mLeHandle); + } catch (RemoteException e) { + Log.e(TAG, "Failed to stop scan and unregister" + e); + } + } else { + Log.e(TAG, "stopLeScan, BluetoothAdapter is null"); } + mLeHandle = -1; + notifyAll(); } + } - public void onGetService(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid) { - // no op - } + /** + * Application interface registered - app is ready to go + */ + public void onClientRegistered(int status, int clientIf) { + if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status + + " clientIf=" + clientIf); + synchronized(this) { + if (mLeHandle == -1) { + if (DBG) Log.d(TAG, "onClientRegistered LE scan canceled"); + } - public void onGetIncludedService(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int inclSrvcType, int inclSrvcInstId, - ParcelUuid inclSrvcUuid) { - // no op + if (status == BluetoothGatt.GATT_SUCCESS) { + mLeHandle = clientIf; + IBluetoothGatt iGatt = null; + try { + BluetoothAdapter adapter = mBluetoothAdapter.get(); + if (adapter != null) { + iGatt = adapter.getBluetoothManager().getBluetoothGatt(); + if (mScanFilter == null) { + iGatt.startScan(mLeHandle, false); + } else { + ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; + for(int i = 0; i != uuids.length; ++i) { + uuids[i] = new ParcelUuid(mScanFilter[i]); + } + iGatt.startScanWithUuids(mLeHandle, false, uuids); + } + } else { + Log.e(TAG, "onClientRegistered, BluetoothAdapter null"); + mLeHandle = -1; + } + } catch (RemoteException e) { + Log.e(TAG, "fail to start le scan: " + e); + mLeHandle = -1; + } + if (mLeHandle == -1) { + // registration succeeded but start scan failed + if (iGatt != null) { + try { + iGatt.unregisterClient(mLeHandle); + } catch (RemoteException e) { + Log.e(TAG, "fail to unregister callback: " + mLeHandle + + " error: " + e); + } + } + } + } else { + // registration failed + mLeHandle = -1; + } + notifyAll(); } + } - public void onGetCharacteristic(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - int charProps) { - // no op - } + public void onClientConnectionState(int status, int clientIf, + boolean connected, String address) { + // no op + } - public void onGetDescriptor(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - ParcelUuid descUuid) { - // no op - } + /** + * Callback reporting an LE scan result. + * @hide + */ + public void onScanResult(String address, int rssi, byte[] advData) { + if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); - public void onSearchComplete(String address, int status) { - // no op + // Check null in case the scan has been stopped + synchronized(this) { + if (mLeHandle <= 0) return; } - - public void onCharacteristicRead(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, byte[] value) { - // no op + try { + BluetoothAdapter adapter = mBluetoothAdapter.get(); + if (adapter == null) { + Log.d(TAG, "onScanResult, BluetoothAdapter null"); + return; + } + mLeScanCb.onLeScan(adapter.getRemoteDevice(address), rssi, advData); + } catch (Exception ex) { + Log.w(TAG, "Unhandled exception: " + ex); } + } - public void onCharacteristicWrite(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid) { - // no op - } + public void onGetService(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid) { + // no op + } + + public void onGetIncludedService(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int inclSrvcType, int inclSrvcInstId, + ParcelUuid inclSrvcUuid) { + // no op + } - public void onNotify(String address, int srvcType, + public void onGetCharacteristic(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + int charProps) { + // no op + } + + public void onGetDescriptor(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + ParcelUuid descUuid) { + // no op + } + + public void onSearchComplete(String address, int status) { + // no op + } + + public void onCharacteristicRead(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, byte[] value) { + // no op + } + + public void onCharacteristicWrite(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid) { + // no op + } + + public void onNotify(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, byte[] value) { - // no op - } + // no op + } - public void onDescriptorRead(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - ParcelUuid descrUuid, byte[] value) { - // no op - } + public void onDescriptorRead(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + ParcelUuid descrUuid, byte[] value) { + // no op + } - public void onDescriptorWrite(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - ParcelUuid descrUuid) { - // no op - } + public void onDescriptorWrite(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + ParcelUuid descrUuid) { + // no op + } - public void onExecuteWrite(String address, int status) { - // no op - } + public void onExecuteWrite(String address, int status) { + // no op + } - public void onReadRemoteRssi(String address, int rssi, int status) { - // no op - } - }; + public void onReadRemoteRssi(String address, int rssi, int status) { + // no op + } + } } |
