From 3c8c13ff7ee3f112c3f376a4735eaaa5e0eb4628 Mon Sep 17 00:00:00 2001 From: Aleksander Nowakowski Date: Wed, 19 Oct 2016 12:04:59 +0200 Subject: [PATCH] Bluetooth state receiver moved to BleManager Manager is responsible for receiving Bluetooth OFF state, Receivers registered in connect to make the manager reusable (close() unregister them) --- .../nrftoolbox/profile/BleManager.java | 82 ++++++++++++++----- .../BleMulticonnectProfileService.java | 24 +----- .../android/nrftoolbox/ble/BleManager.java | 61 ++++++++++---- 3 files changed, 108 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManager.java index 61205a2a..79f15e71 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManager.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManager.java @@ -21,6 +21,7 @@ */ package no.nordicsemi.android.nrftoolbox.profile; +import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; @@ -81,12 +82,12 @@ public abstract class BleManager implements ILogg * The log session or null if nRF Logger is not installed. */ protected ILogSession mLogSession; + private final Context mContext; + private final Handler mHandler; protected BluetoothDevice mBluetoothDevice; protected E mCallbacks; - private Handler mHandler; private BluetoothGatt mBluetoothGatt; private BleManagerGattCallback mGattCallback; - private Context mContext; /** * This flag is set to false only when the {@link #shouldAutoConnect()} method returns true and the device got disconnected without calling {@link #disconnect()} method. * If {@link #shouldAutoConnect()} returns false (default) this is always set to true. @@ -98,6 +99,43 @@ public abstract class BleManager implements ILogg /** Last received battery value or -1 if value wasn't received. */ private int mBatteryValue = -1; + private final BroadcastReceiver mBluetoothStateBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF); + final int previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, BluetoothAdapter.STATE_OFF); + + final String stateString = "[Broadcast] Action received: " + BluetoothAdapter.ACTION_STATE_CHANGED + ", state changed to " + state2String(state); + Logger.d(mLogSession, stateString); + + switch (state) { + case BluetoothAdapter.STATE_TURNING_OFF: + case BluetoothAdapter.STATE_OFF: + if (mConnected && previousState != BluetoothAdapter.STATE_TURNING_OFF && previousState != BluetoothAdapter.STATE_OFF) { + // The connection is killed by the system, no need to gently disconnect + mGattCallback.notifyDeviceDisconnected(mBluetoothDevice); + close(); + } + break; + } + } + + private String state2String(final int state) { + switch (state) { + case BluetoothAdapter.STATE_TURNING_ON: + return "TURNING ON"; + case BluetoothAdapter.STATE_ON: + return "ON"; + case BluetoothAdapter.STATE_TURNING_OFF: + return "TURNING OFF"; + case BluetoothAdapter.STATE_OFF: + return "OFF"; + default: + return "UNKNOWN (" + state + ")"; + } + } + }; + private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { @@ -155,10 +193,6 @@ public abstract class BleManager implements ILogg public BleManager(final Context context) { mContext = context; mHandler = new Handler(); - - // Register bonding broadcast receiver - context.registerReceiver(mBondingBroadcastReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED)); - context.registerReceiver(mPairingRequestBroadcastReceiver, new IntentFilter("android.bluetooth.device.action.PAIRING_REQUEST"/*BluetoothDevice.ACTION_PAIRING_REQUEST*/)); } /** @@ -210,6 +244,11 @@ public abstract class BleManager implements ILogg Logger.d(mLogSession, "gatt.close()"); mBluetoothGatt.close(); mBluetoothGatt = null; + } else { + // Register bonding broadcast receiver + mContext.registerReceiver(mBluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); + mContext.registerReceiver(mBondingBroadcastReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED)); + mContext.registerReceiver(mPairingRequestBroadcastReceiver, new IntentFilter("android.bluetooth.device.action.PAIRING_REQUEST"/*BluetoothDevice.ACTION_PAIRING_REQUEST*/)); } } @@ -273,6 +312,7 @@ public abstract class BleManager implements ILogg */ public void close() { try { + mContext.unregisterReceiver(mBluetoothStateBroadcastReceiver); mContext.unregisterReceiver(mBondingBroadcastReceiver); mContext.unregisterReceiver(mPairingRequestBroadcastReceiver); } catch (Exception e) { @@ -897,6 +937,22 @@ public abstract class BleManager implements ILogg */ protected abstract void onDeviceDisconnected(); + private void notifyDeviceDisconnected(final BluetoothDevice device) { + mConnected = false; + mConnectionState = BluetoothGatt.STATE_DISCONNECTED; + if (mUserDisconnected) { + Logger.i(mLogSession, "Disconnected"); + mCallbacks.onDeviceDisconnected(device); + close(); + } else { + Logger.w(mLogSession, "Connection lost"); + mCallbacks.onLinklossOccur(device); + // We are not closing the connection here as the device should try to reconnect automatically. + // This may be only called when the shouldAutoConnect() method returned true. + } + onDeviceDisconnected(); + } + /** * Callback reporting the result of a characteristic read operation. * @@ -1023,20 +1079,8 @@ public abstract class BleManager implements ILogg if (status != BluetoothGatt.GATT_SUCCESS) Logger.w(mLogSession, "Error: (0x" + Integer.toHexString(status) + "): " + GattError.parseConnectionError(status)); - mConnected = false; - mConnectionState = BluetoothGatt.STATE_DISCONNECTED; mOperationInProgress = true; // no more calls are possible - if (mUserDisconnected) { - Logger.i(mLogSession, "Disconnected"); - mCallbacks.onDeviceDisconnected(gatt.getDevice()); - close(); - } else { - Logger.w(mLogSession, "Connection lost"); - mCallbacks.onLinklossOccur(gatt.getDevice()); - // We are not closing the connection here as the device should try to reconnect automatically. - // This may be only called when the shouldAutoConnect() method returned true. - } - onDeviceDisconnected(); + notifyDeviceDisconnected(gatt.getDevice()); return; } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/BleMulticonnectProfileService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/BleMulticonnectProfileService.java index 42b10a83..f1d7aef0 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/BleMulticonnectProfileService.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/BleMulticonnectProfileService.java @@ -85,10 +85,6 @@ public abstract class BleMulticonnectProfileService extends Service implements B public void onReceive(final Context context, final Intent intent) { final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF); final int previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, BluetoothAdapter.STATE_OFF); - final ILogger logger = getBinder(); - - final String stateString = "[Broadcast] Action received: " + BluetoothAdapter.ACTION_STATE_CHANGED + ", state changed to " + state2String(state); - logger.log(LogContract.Log.Level.DEBUG, stateString); switch (state) { case BluetoothAdapter.STATE_ON: @@ -101,21 +97,6 @@ public abstract class BleMulticonnectProfileService extends Service implements B break; } } - - private String state2String(final int state) { - switch (state) { - case BluetoothAdapter.STATE_TURNING_ON: - return "TURNING ON"; - case BluetoothAdapter.STATE_ON: - return "ON"; - case BluetoothAdapter.STATE_TURNING_OFF: - return "TURNING OFF"; - case BluetoothAdapter.STATE_OFF: - return "OFF"; - default: - return "UNKNOWN (" + state + ")"; - } - } }; public class LocalBinder extends Binder implements ILogger, IDeviceLogger { @@ -404,10 +385,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B * Method called when Bluetooth Adapter has been disabled. */ protected void onBluetoothDisabled() { - for (final BleManager manager : mBleManagers.values()) { - // Devices were disconnected, no need to disconnect manually. - manager.close(); - } + // do nothing, BleManagers have their own Bluetooth State broadcast received and will close themselves } /** diff --git a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleManager.java b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleManager.java index 92469db9..bc9dcebe 100644 --- a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleManager.java +++ b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleManager.java @@ -21,6 +21,7 @@ */ package no.nordicsemi.android.nrftoolbox.ble; +import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; @@ -74,9 +75,9 @@ public class BleManager implements BleProfileApi { protected final BleManagerCallbacks mCallbacks; private final Context mContext; + private final Handler mHandler; protected BluetoothDevice mBluetoothDevice; protected BleProfile mProfile; - private Handler mHandler; private BluetoothGatt mBluetoothGatt; private BleManagerGattCallback mGattCallback; /** @@ -84,14 +85,31 @@ public class BleManager implements BleProfileApi { * If {@link #shouldAutoConnect()} returns false (default) this is always set to true. */ private boolean mUserDisconnected; - /** - * Flag set to true when the device is connected. - */ + /** Flag set to true when the device is connected. */ private boolean mConnected; private int mConnectionState = BluetoothGatt.STATE_DISCONNECTED; /** Last received battery value or -1 if value wasn't received. */ private int mBatteryValue = -1; + private final BroadcastReceiver mBluetoothStateBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF); + final int previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, BluetoothAdapter.STATE_OFF); + + switch (state) { + case BluetoothAdapter.STATE_TURNING_OFF: + case BluetoothAdapter.STATE_OFF: + if (mConnected && previousState != BluetoothAdapter.STATE_TURNING_OFF && previousState != BluetoothAdapter.STATE_OFF) { + // The connection is killed by the system, no need to gently disconnect + mGattCallback.notifyDeviceDisconnected(mBluetoothDevice); + close(); + } + break; + } + } + }; + private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { @@ -165,7 +183,7 @@ public class BleManager implements BleProfileApi { } /** - * Connects to the Bluetooth Smart device + * Connects to the Bluetooth Smart device. * * @param device a device to connect to */ @@ -177,6 +195,10 @@ public class BleManager implements BleProfileApi { if (mBluetoothGatt != null) { mBluetoothGatt.close(); mBluetoothGatt = null; + } else { + // Register bonding broadcast receiver + mContext.registerReceiver(mBluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); + mContext.registerReceiver(mBondingBroadcastReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED)); } } @@ -236,6 +258,7 @@ public class BleManager implements BleProfileApi { */ public void close() { try { + mContext.unregisterReceiver(mBluetoothStateBroadcastReceiver); mContext.unregisterReceiver(mBondingBroadcastReceiver); } catch (Exception e) { // the receiver must have been not registered or unregistered before @@ -488,6 +511,21 @@ public class BleManager implements BleProfileApi { private boolean mInitInProgress; private boolean mOperationInProgress; + private void notifyDeviceDisconnected(final BluetoothDevice device) { + mConnected = false; + mConnectionState = BluetoothGatt.STATE_DISCONNECTED; + if (mUserDisconnected) { + mCallbacks.onDeviceDisconnected(device); + close(); + } else { + mCallbacks.onLinklossOccur(device); + // We are not closing the connection here as the device should try to reconnect automatically. + // This may be only called when the shouldAutoConnect() method returned true. + } + if (mProfile != null) + mProfile.release(); + } + private void onError(final BluetoothDevice device, final String message, final int errorCode) { mCallbacks.onError(device, message, errorCode); if (mProfile != null) @@ -529,19 +567,8 @@ public class BleManager implements BleProfileApi { }, 600); } else { if (newState == BluetoothProfile.STATE_DISCONNECTED) { - mConnected = false; - mConnectionState = BluetoothGatt.STATE_DISCONNECTED; mOperationInProgress = true; // no more calls are possible - if (mUserDisconnected) { - mCallbacks.onDeviceDisconnected(gatt.getDevice()); - close(); - } else { - mCallbacks.onLinklossOccur(gatt.getDevice()); - // We are not closing the connection here as the device should try to reconnect automatically. - // This may be only called when the shouldAutoConnect() method returned true. - } - if (mProfile != null) - mProfile.release(); + notifyDeviceDisconnected(gatt.getDevice()); return; }