diff options
author | Wei Wang <weiwa@google.com> | 2014-03-20 16:37:53 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2014-03-20 16:37:53 +0000 |
commit | 9b12bd90a51aa0fe25d25f34791bc8e7db0b3141 (patch) | |
tree | 8f2b4f4098385322a74fd3918dc68b3565da6c46 /core/java | |
parent | c96693b5174835c7537c22b1eca8a2c15eb191d0 (diff) | |
parent | 15a18d07acc57d465e9d67bb28010912bb9ad15f (diff) | |
download | frameworks_base-9b12bd90a51aa0fe25d25f34791bc8e7db0b3141.zip frameworks_base-9b12bd90a51aa0fe25d25f34791bc8e7db0b3141.tar.gz frameworks_base-9b12bd90a51aa0fe25d25f34791bc8e7db0b3141.tar.bz2 |
am 15a18d07: am da084104: Merge "DO NOT MERGE: Add status callback for start/stop advertising." into klp-dev
* commit '15a18d07acc57d465e9d67bb28010912bb9ad15f':
DO NOT MERGE: Add status callback for start/stop advertising.
Diffstat (limited to 'core/java')
4 files changed, 131 insertions, 69 deletions
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index d1f1f2a..f973d84 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -20,7 +20,9 @@ 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.Looper; import android.os.Message; import android.os.ParcelUuid; import android.os.RemoteException; @@ -183,43 +185,6 @@ public final class BluetoothAdapter { "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. * <p>This system activity will return once Bluetooth has completed turning @@ -251,6 +216,22 @@ public final class BluetoothAdapter { "android.bluetooth.adapter.action.SCAN_MODE_CHANGED"; /** + * 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"; + + /** * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} * intents to request the current scan mode. Possible values are: * {@link #SCAN_MODE_NONE}, @@ -386,9 +367,27 @@ public final class BluetoothAdapter { /** The profile is in disconnecting state */ public static final int STATE_DISCONNECTING = 3; + /** States for Bluetooth LE advertising */ + /** @hide */ + public static final int STATE_ADVERTISE_STARTING = 0; + /** @hide */ + public static final int STATE_ADVERTISE_STARTED = 1; + /** @hide */ + public static final int STATE_ADVERTISE_STOPPING = 2; + /** @hide */ + public static final int STATE_ADVERTISE_STOPPED = 3; + /** + * Force stopping advertising without callback in case the advertising app dies. + * @hide + */ + public static final int STATE_ADVERTISE_FORCE_STOPPING = 4; + /** @hide */ public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager"; + /** @hide */ + public static final int ADVERTISE_CALLBACK_SUCCESS = 0; + private static final int ADDRESS_LENGTH = 17; /** @@ -402,7 +401,9 @@ public final class BluetoothAdapter { private final Map<LeScanCallback, GattCallbackWrapper> mLeScanClients; private BluetoothAdvScanData mBluetoothAdvScanData = null; - private GattCallbackWrapper mAdvertisingCallback; + private GattCallbackWrapper mAdvertisingGattCallback; + private final Handler mHandler; // Handler to post the advertise callback to run on main thread. + private final Object mLock = new Object(); /** * Get a handle to the default local Bluetooth adapter. @@ -438,6 +439,7 @@ public final class BluetoothAdapter { } catch (RemoteException e) {Log.e(TAG, "", e);} mManagerService = managerService; mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>(); + mHandler = new Handler(Looper.getMainLooper()); } /** @@ -477,6 +479,7 @@ public final class BluetoothAdapter { /** * Returns a {@link BluetoothAdvScanData} object representing advertising data. + * Data will be reset when bluetooth service is turned off. * @hide */ public BluetoothAdvScanData getAdvScanData() { @@ -497,19 +500,34 @@ public final class BluetoothAdapter { } } + /** + * Interface for BLE advertising callback. + * + * @hide + */ + public interface AdvertiseCallback { + /** + * Callback when advertise starts. + * @param status - {@link #ADVERTISE_CALLBACK_SUCCESS} for success, others for failure. + */ + void onAdvertiseStart(int status); + /** + * Callback when advertise stops. + * @param status - {@link #ADVERTISE_CALLBACK_SUCCESS} for success, others for failure. + */ + void onAdvertiseStop(int status); + } /** * 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. + * @param callback - {@link AdvertiseCallback} + * @return true if BLE advertising succeeds, false otherwise. * @hide */ - public boolean startAdvertising() { + public boolean startAdvertising(final AdvertiseCallback callback) { if (getState() != STATE_ON) return false; - try { IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); if (iGatt == null) { @@ -519,18 +537,31 @@ public final class BluetoothAdapter { // Restart/reset advertising packets if advertising is in progress. if (isAdvertising()) { // Invalid advertising callback. - if (mAdvertisingCallback == null || mAdvertisingCallback.mLeHandle == -1) { + if (mAdvertisingGattCallback == null || mAdvertisingGattCallback.mLeHandle == -1) { Log.e(TAG, "failed to restart advertising, invalid callback"); return false; } - iGatt.startAdvertising(mAdvertisingCallback.mLeHandle); + iGatt.startAdvertising(mAdvertisingGattCallback.mLeHandle); + // Run the callback from main thread. + mHandler.post(new Runnable() { + @Override + public void run() { + // callback with status success. + callback.onAdvertiseStart(ADVERTISE_CALLBACK_SUCCESS); + } + }); return true; } UUID uuid = UUID.randomUUID(); GattCallbackWrapper wrapper = - new GattCallbackWrapper(this, null, null, GattCallbackWrapper.CALLBACK_TYPE_ADV); + new GattCallbackWrapper(this, null, null, callback); iGatt.registerClient(new ParcelUuid(uuid), wrapper); - mAdvertisingCallback = wrapper; + if (!wrapper.advertiseStarted()) { + return false; + } + synchronized (mLock) { + mAdvertisingGattCallback = wrapper; + } return true; } catch (RemoteException e) { Log.e(TAG, "", e); @@ -540,25 +571,29 @@ public final class BluetoothAdapter { /** * 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} + * + * @param callback - {@link AdvertiseCallback} * @return true if BLE advertising stops, false otherwise. * @hide */ - public boolean stopAdvertisting() { + public boolean stopAdvertising(AdvertiseCallback callback) { try { IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); if (iGatt == null) { // BLE is not supported return false; } - if (mAdvertisingCallback == null) { + if (mAdvertisingGattCallback == null) { // no callback. return false; } - mAdvertisingCallback.stopAdvertising(); - mAdvertisingCallback = null; + // Make sure same callback is used for start and stop advertising. + if (callback != mAdvertisingGattCallback.mAdvertiseCallback) { + Log.e(TAG, "must use the same callback for star/stop advertising"); + return false; + } + mAdvertisingGattCallback.stopAdvertising(); + mAdvertisingGattCallback = null; return true; } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1418,6 +1453,8 @@ public final class BluetoothAdapter { if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); synchronized (mManagerCallback) { mService = null; + // Reset bluetooth adv scan data when Gatt service is down. + mBluetoothAdvScanData = null; for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ try { if (cb != null) { @@ -1692,11 +1729,9 @@ 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 AdvertiseCallback mAdvertiseCallback; private final LeScanCallback mLeScanCb; - private int mCallbackType; // mLeHandle 0: not registered // -1: scan stopped @@ -1711,26 +1746,34 @@ public final class BluetoothAdapter { mLeScanCb = leScanCb; mScanFilter = uuid; mLeHandle = 0; - mCallbackType = CALLBACK_TYPE_SCAN; + mAdvertiseCallback = null; } public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, LeScanCallback leScanCb, - UUID[] uuid, int type) { + UUID[] uuid, AdvertiseCallback callback) { mBluetoothAdapter = new WeakReference<BluetoothAdapter>(bluetoothAdapter); mLeScanCb = leScanCb; mScanFilter = uuid; mLeHandle = 0; - mCallbackType = type; + mAdvertiseCallback = callback; } public boolean scanStarted() { + return waitForRegisteration(LE_CALLBACK_REG_WAIT_COUNT); + } + + public boolean advertiseStarted() { + // Wait for registeration callback. + return waitForRegisteration(1); + } + + private boolean waitForRegisteration(int maxWaitCount) { 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) { + while (mLeHandle == 0 && count < maxWaitCount) { try { wait(LE_CALLBACK_REG_TIMEOUT); } catch (InterruptedException e) { @@ -1754,7 +1797,7 @@ public final class BluetoothAdapter { try { IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); iGatt.stopAdvertising(); - Log.d(TAG, "unregeistering client " + mLeHandle); + Log.d(TAG, "unregistering client " + mLeHandle); iGatt.unregisterClient(mLeHandle); } catch (RemoteException e) { Log.e(TAG, "Failed to stop advertising and unregister" + e); @@ -1808,7 +1851,7 @@ public final class BluetoothAdapter { BluetoothAdapter adapter = mBluetoothAdapter.get(); if (adapter != null) { iGatt = adapter.getBluetoothManager().getBluetoothGatt(); - if (mCallbackType == CALLBACK_TYPE_ADV) { + if (mAdvertiseCallback != null) { iGatt.startAdvertising(mLeHandle); } else { if (mScanFilter == null) { @@ -1858,7 +1901,7 @@ public final class BluetoothAdapter { * @hide */ public void onScanResult(String address, int rssi, byte[] advData) { - if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); + if (VDBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); // Check null in case the scan has been stopped synchronized(this) { @@ -1947,9 +1990,13 @@ public final class BluetoothAdapter { // no op } - public void onListen(int status) { - // no op + public void onAdvertiseStateChange(int advertiseState, int status) { + Log.d(TAG, "on advertise call back, state: " + advertiseState + " status: " + status); + if (advertiseState == STATE_ADVERTISE_STARTED) { + mAdvertiseCallback.onAdvertiseStart(status); + } else { + mAdvertiseCallback.onAdvertiseStop(status); + } } } - } diff --git a/core/java/android/bluetooth/BluetoothAdvScanData.java b/core/java/android/bluetooth/BluetoothAdvScanData.java index a97b0a8..df2c256 100644 --- a/core/java/android/bluetooth/BluetoothAdvScanData.java +++ b/core/java/android/bluetooth/BluetoothAdvScanData.java @@ -77,6 +77,7 @@ public final class BluetoothAdvScanData { try { return mBluetoothGatt.setAdvManufacturerCodeAndData(manufacturerCode, manufacturerData); } catch (RemoteException e) { + Log.e(TAG, "Unable to set manufacturer id and data.", e); return false; } } @@ -92,6 +93,7 @@ public final class BluetoothAdvScanData { try { return mBluetoothGatt.setAdvServiceData(serviceData); } catch (RemoteException e) { + Log.e(TAG, "Unable to set service data.", e); return false; } } @@ -103,6 +105,7 @@ public final class BluetoothAdvScanData { try { return Collections.unmodifiableList(mBluetoothGatt.getAdvServiceUuids()); } catch (RemoteException e) { + Log.e(TAG, "Unable to get service uuids.", e); return null; } } @@ -115,6 +118,7 @@ public final class BluetoothAdvScanData { try { return mBluetoothGatt.getAdvManufacturerData(); } catch (RemoteException e) { + Log.e(TAG, "Unable to get manufacturer data.", e); return null; } } @@ -127,6 +131,7 @@ public final class BluetoothAdvScanData { try { return mBluetoothGatt.getAdvServiceData(); } catch (RemoteException e) { + Log.e(TAG, "Unable to get service data.", e); return null; } } @@ -140,7 +145,7 @@ public final class BluetoothAdvScanData { try { mBluetoothGatt.removeAdvManufacturerCodeAndData(manufacturerCode); } catch (RemoteException e) { - Log.e(TAG, e.toString()); + Log.e(TAG, "Unable to remove manufacturer : " + manufacturerCode, e); } } } diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index cd093c5..ae6ad3b 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -553,6 +553,15 @@ public final class BluetoothGatt implements BluetoothProfile { Log.w(TAG, "Unhandled exception in callback", ex); } } + + /** + * Advertise state change callback + * @hide + */ + public void onAdvertiseStateChange(int state, int status) { + if (DBG) Log.d(TAG, "onAdvertiseStateChange() - state = " + + state + " status=" + status); + } }; /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device) { diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl index e3563fc..7c69a06 100644 --- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl +++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl @@ -63,4 +63,5 @@ interface IBluetoothGattCallback { in int charInstId, in ParcelUuid charUuid, in byte[] value); void onReadRemoteRssi(in String address, in int rssi, in int status); + oneway void onAdvertiseStateChange(in int advertiseState, in int status); } |