diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/battery/BatteryManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/battery/BatteryManager.java index 72c5623f..526d9578 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/battery/BatteryManager.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/battery/BatteryManager.java @@ -27,6 +27,8 @@ public abstract class BatteryManager extends private final static UUID BATTERY_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb"); private BluetoothGattCharacteristic mBatteryLevelCharacteristic; + /** Last received Battery Level value. */ + private Integer mBatteryLevel; /** * The manager constructor. @@ -41,42 +43,62 @@ public abstract class BatteryManager extends protected abstract BatteryManagerGattCallback getGattCallback(); public void readBatteryLevelCharacteristic() { - readCharacteristic(mBatteryLevelCharacteristic) - .with(new BatteryLevelDataCallback() { - @Override - public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { - mCallbacks.onBatteryLevelChanged(device, batteryLevel); - } + if (isConnected()) { + readCharacteristic(mBatteryLevelCharacteristic) + .with(new BatteryLevelDataCallback() { + @Override + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { + mBatteryLevel = batteryLevel; + mCallbacks.onBatteryLevelChanged(device, batteryLevel); + } - @Override - public void onInvalidDataReceived(@NonNull final BluetoothDevice device, final @NonNull Data data) { - log(LogContract.Log.Level.WARNING, "Invalid Battery Level data received: " + data); - } - }) - .fail(status -> log(LogContract.Log.Level.WARNING, "Battery Level characteristic not found")); + @Override + public void onInvalidDataReceived(@NonNull final BluetoothDevice device, final @NonNull Data data) { + log(LogContract.Log.Level.WARNING, "Invalid Battery Level data received: " + data); + } + }) + .fail(status -> log(LogContract.Log.Level.WARNING, "Battery Level characteristic not found")); + } } public void enableBatteryLevelCharacteristicNotifications() { - // If the Battery Level characteristic is null, the request will be ignored - enableNotifications(mBatteryLevelCharacteristic) - .with(new BatteryLevelDataCallback() { - @Override - public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { - mCallbacks.onBatteryLevelChanged(device, batteryLevel); - } + if (isConnected()) { + // If the Battery Level characteristic is null, the request will be ignored + enableNotifications(mBatteryLevelCharacteristic) + .with(new BatteryLevelDataCallback() { + @Override + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { + mBatteryLevel = batteryLevel; + mCallbacks.onBatteryLevelChanged(device, batteryLevel); + } - @Override - public void onInvalidDataReceived(@NonNull final BluetoothDevice device, final @NonNull Data data) { - log(LogContract.Log.Level.WARNING, "Invalid Battery Level data received: " + data); - } - }) - .done(() -> log(LogContract.Log.Level.INFO, "Battery Level notifications enabled")) - .fail(status -> log(LogContract.Log.Level.WARNING, "Battery Level characteristic not found")); + @Override + public void onInvalidDataReceived(@NonNull final BluetoothDevice device, final @NonNull Data data) { + log(LogContract.Log.Level.WARNING, "Invalid Battery Level data received: " + data); + } + }) + .done(() -> log(LogContract.Log.Level.INFO, "Battery Level notifications enabled")) + .fail(status -> log(LogContract.Log.Level.WARNING, "Battery Level characteristic not found")); + } } + /** + * + */ public void disableBatteryLevelCharacteristicNotifications() { - disableNotifications(mBatteryLevelCharacteristic) - .done(() -> log(LogContract.Log.Level.INFO, "Battery Level notifications disabled")); + if (isConnected()) { + disableNotifications(mBatteryLevelCharacteristic) + .done(() -> log(LogContract.Log.Level.INFO, "Battery Level notifications disabled")); + } + } + + /** + * Returns the last received Battery Level value. + * The value is set to null when the device disconnects. + * @return Battery Level value, in percent. + */ + public Integer getBatteryLevel() { + return mBatteryLevel; } protected abstract class BatteryManagerGattCallback extends BleManagerGattCallback { @@ -99,6 +121,7 @@ public abstract class BatteryManager extends @Override protected void onDeviceDisconnected() { mBatteryLevelCharacteristic = null; + mBatteryLevel = null; } } } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSActivity.java index acc216b9..f11e0b99 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSActivity.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSActivity.java @@ -35,17 +35,20 @@ import android.view.MenuItem; import android.view.View; import android.widget.ListView; import android.widget.PopupMenu; +import android.widget.TextView; import java.util.UUID; import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity; +import no.nordicsemi.android.nrftoolbox.proximity.ProximityService; public class CGMSActivity extends BleProfileServiceReadyActivity implements PopupMenu.OnMenuItemClickListener { private View mControlPanelStd; private View mControlPanelAbort; private ListView mRecordsListView; + private TextView mBatteryLevelView; private CGMSRecordsAdapter mCgmsRecordsAdapter; private CGMService.CGMSBinder mBinder; @@ -65,6 +68,7 @@ public class CGMSActivity extends BleProfileServiceReadyActivity { clearRecords(); @@ -166,10 +170,15 @@ public class CGMSActivity extends BleProfileServiceReadyActivity manager : mBleManagers.values()) { - if (manager.isConnected()) - manager.readBatteryLevel(); - } } } @@ -286,12 +280,6 @@ public abstract class BleMulticonnectProfileService extends Service implements B if (!mActivityIsChangingConfiguration) { if (!mManagedDevices.isEmpty()) { onUnbind(); - // When we are connected, but the application is not open, we are not really interested in battery level notifications. - // But we will still be receiving other values, if enabled. - for (final BleManager manager : mBleManagers.values()) { - if (manager.isConnected()) - manager.disableBatteryLevelNotifications(); - } } else { // The last activity has disconnected from the service and there are no devices to manage. The service may be stopped. stopSelf(); diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/DeviceAdapter.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/DeviceAdapter.java index 66d5f080..877147e5 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/DeviceAdapter.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/DeviceAdapter.java @@ -136,8 +136,8 @@ public class DeviceAdapter extends RecyclerView.Adapter= 0) { + final Integer batteryValue = mService.getBatteryLevel(device); + if (batteryValue != null) { batteryView.getCompoundDrawables()[0 /*left*/].setLevel(batteryValue); batteryView.setVisibility(View.VISIBLE); batteryView.setText(batteryView.getResources().getString(R.string.battery, batteryValue)); diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityActivity.java index 9fbe2606..0f3dd963 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityActivity.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityActivity.java @@ -23,7 +23,12 @@ package no.nordicsemi.android.nrftoolbox.proximity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.os.Bundle; +import android.support.v4.content.LocalBroadcastManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -50,6 +55,17 @@ public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivit setGUI(); } + @Override + protected void onInitialize(final Bundle savedInstanceState) { + LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter()); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver); + } + private void setGUI() { final RecyclerView recyclerView = mDevicesView = findViewById(android.R.id.list); recyclerView.setLayoutManager(new LinearLayoutManager(this)); @@ -133,12 +149,12 @@ public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivit showLinklossDialog(device.getName()); } - @Override - public void onBatteryValueReceived(final BluetoothDevice device, final int value) { + private void onBatteryLevelChanged(final BluetoothDevice device, final int batteryLevel) { if (mAdapter != null) mAdapter.onBatteryValueReceived(device); // Value will be obtained from the service } + private void showLinklossDialog(final String name) { try { final LinklossFragment dialog = LinklossFragment.getInstance(name); @@ -147,4 +163,23 @@ public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivit // the activity must have been destroyed } } + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + final BluetoothDevice device = intent.getParcelableExtra(ProximityService.EXTRA_DEVICE); + + if (ProximityService.BROADCAST_BATTERY_LEVEL.equals(action)) { + final int batteryLevel = intent.getIntExtra(ProximityService.EXTRA_BATTERY_LEVEL, 0); + // Update GUI + onBatteryLevelChanged(device, batteryLevel); + } + } + }; + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ProximityService.BROADCAST_BATTERY_LEVEL); + return intentFilter; + } } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManager.java index 3ed5a23b..9a2d2509 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManager.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManager.java @@ -28,24 +28,19 @@ import android.bluetooth.BluetoothGattService; import android.content.Context; import android.support.annotation.NonNull; -import java.util.Deque; -import java.util.LinkedList; import java.util.UUID; -import no.nordicsemi.android.ble.BleManager; -import no.nordicsemi.android.ble.Request; import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.log.Logger; +import no.nordicsemi.android.nrftoolbox.battery.BatteryManager; import no.nordicsemi.android.nrftoolbox.parser.AlertLevelParser; -import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; -public class ProximityManager extends BleManager { +class ProximityManager extends BatteryManager { private final String TAG = "ProximityManager"; /** Immediate Alert service UUID */ - public final static UUID IMMEDIATE_ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb"); + private final static UUID IMMEDIATE_ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb"); /** Linkloss service UUID */ - public final static UUID LINKLOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb"); + final static UUID LINKLOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb"); /** Alert Level characteristic UUID */ private static final UUID ALERT_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A06-0000-1000-8000-00805f9b34fb"); @@ -55,9 +50,8 @@ public class ProximityManager extends BleManager { private BluetoothGattCharacteristic mAlertLevelCharacteristic, mLinklossCharacteristic; private boolean mAlertOn; - private int mBatteryLevel; - public ProximityManager(final Context context) { + ProximityManager(final Context context) { super(context); } @@ -67,17 +61,18 @@ public class ProximityManager extends BleManager { } @Override - protected BleManagerGattCallback getGattCallback() { + protected BatteryManagerGattCallback getGattCallback() { return mGattCallback; } /** * BluetoothGatt callbacks for connection/disconnection, service discovery, receiving indication, etc */ - private final BleManagerGattCallback mGattCallback = new BleManagerGattCallback() { + private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() { @Override protected void initialize(@NonNull final BluetoothDevice device) { + super.initialize(device); writeCharacteristic(mLinklossCharacteristic, HIGH_ALERT); } @@ -92,6 +87,7 @@ public class ProximityManager extends BleManager { @Override protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) { + super.isOptionalServiceSupported(gatt); final BluetoothGattService iaService = gatt.getService(IMMEDIATE_ALERT_SERVICE_UUID); if (iaService != null) { mAlertLevelCharacteristic = iaService.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID); @@ -101,6 +97,7 @@ public class ProximityManager extends BleManager { @Override protected void onDeviceDisconnected() { + super.onDeviceDisconnected(); mAlertLevelCharacteristic = null; mLinklossCharacteristic = null; // Reset the alert flag @@ -140,12 +137,4 @@ public class ProximityManager extends BleManager { boolean isAlertEnabled() { return mAlertOn; } - - /** - * Returns the last obtained Battery Level value in percent. - * @return battery level value - */ - int getBatteryLevel() { - return mBatteryLevel; - } } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManagerCallbacks.java index ce9d6e91..abafe450 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManagerCallbacks.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManagerCallbacks.java @@ -21,8 +21,8 @@ */ package no.nordicsemi.android.nrftoolbox.proximity; -import no.nordicsemi.android.ble.BleManagerCallbacks; +import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks; -public interface ProximityManagerCallbacks extends BleManagerCallbacks { +interface ProximityManagerCallbacks extends BatteryManagerCallbacks { // No additional methods } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManager.java index 09589b61..f8d80830 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManager.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManager.java @@ -42,13 +42,13 @@ import no.nordicsemi.android.nrftoolbox.parser.AlertLevelParser; import no.nordicsemi.android.nrftoolbox.profile.multiconnect.IDeviceLogger; import no.nordicsemi.android.nrftoolbox.utility.ParserUtils; -public class ProximityServerManager { +class ProximityServerManager { private final String TAG = "ProximityServerManager"; /** Immediate Alert service UUID */ - public final static UUID IMMEDIATE_ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb"); + final static UUID IMMEDIATE_ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb"); /** Linkloss service UUID */ - public final static UUID LINKLOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb"); + final static UUID LINKLOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb"); /** Alert Level characteristic UUID */ private static final UUID ALERT_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A06-0000-1000-8000-00805f9b34fb"); @@ -70,7 +70,7 @@ public class ProximityServerManager { void onGattServerFailed(final int error); } - public ProximityServerManager(final ProximityServerManagerCallbacks callbacks) { + ProximityServerManager(final ProximityServerManagerCallbacks callbacks) { mHandler = new Handler(); mCallbacks = callbacks; } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManagerCallbacks.java index e87085c5..f4a74b64 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManagerCallbacks.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManagerCallbacks.java @@ -23,9 +23,7 @@ package no.nordicsemi.android.nrftoolbox.proximity; import android.bluetooth.BluetoothDevice; -import no.nordicsemi.android.ble.BleManagerCallbacks; - -public interface ProximityServerManagerCallbacks extends BleManagerCallbacks { +public interface ProximityServerManagerCallbacks { void onAlarmTriggered(final BluetoothDevice device); void onAlarmStopped(final BluetoothDevice device); diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityService.java index 52a02c5c..e714a52c 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityService.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityService.java @@ -34,9 +34,11 @@ import android.media.AudioManager; import android.media.MediaPlayer; import android.media.RingtoneManager; import android.net.Uri; +import android.support.annotation.NonNull; import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationManagerCompat; import android.support.v4.content.ContextCompat; +import android.support.v4.content.LocalBroadcastManager; import android.text.TextUtils; import android.util.Log; @@ -45,7 +47,6 @@ import java.util.LinkedList; import java.util.List; import no.nordicsemi.android.ble.BleManager; -import no.nordicsemi.android.ble.BleManagerCallbacks; import no.nordicsemi.android.log.LogContract; import no.nordicsemi.android.nrftoolbox.FeaturesActivity; import no.nordicsemi.android.nrftoolbox.R; @@ -56,10 +57,12 @@ public class ProximityService extends BleMulticonnectProfileService implements P @SuppressWarnings("unused") private static final String TAG = "ProximityService"; + public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL"; + public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL"; + private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.proximity.ACTION_DISCONNECT"; private final static String ACTION_FIND = "no.nordicsemi.android.nrftoolbox.proximity.ACTION_FIND"; private final static String ACTION_SILENT = "no.nordicsemi.android.nrftoolbox.proximity.ACTION_SILENT"; - private final static String EXTRA_DEVICE = "no.nordicsemi.android.nrftoolbox.proximity.EXTRA_DEVICE"; private final static String PROXIMITY_GROUP_ID = "proximity_connected_tags"; private final static int NOTIFICATION_ID = 1000; @@ -109,9 +112,10 @@ public class ProximityService extends BleMulticonnectProfileService implements P /** * Returns the last received battery level value. * @param device the device of which battery level should be returned - * @return battery value or -1 if no value was received or Battery Level characteristic was not found + * @return battery value or null if no value was received or Battery Level characteristic was not found, + * or the device is disconnected */ - public int getBatteryLevel(final BluetoothDevice device) { + public Integer getBatteryLevel(final BluetoothDevice device) { final ProximityManager manager = (ProximityManager) getBleManager(device); return manager.getBatteryLevel(); } @@ -232,10 +236,24 @@ public class ProximityService extends BleMulticonnectProfileService implements P protected void onRebind() { // When the activity rebinds to the service, remove the notification cancelNotifications(); + + // This method will read the Battery Level value from each connected device, if possible and then try to enable battery notifications (if it has NOTIFY property). + // If the Battery Level characteristic has only the NOTIFY property, it will only try to enable notifications. + for (final BluetoothDevice device : getManagedDevices()) { + final ProximityManager manager = (ProximityManager) getBleManager(device); + manager.readBatteryLevelCharacteristic(); + manager.enableBatteryLevelCharacteristicNotifications(); + } } @Override public void onUnbind() { + // When we are connected, but the application is not open, we are not really interested in battery level notifications. + // But we will still be receiving other values, if enabled. + for (final BluetoothDevice device : getManagedDevices()) { + final ProximityManager manager = (ProximityManager) getBleManager(device); + manager.disableBatteryLevelCharacteristicNotifications(); + } createBackgroundNotification(); } @@ -292,6 +310,14 @@ public class ProximityService extends BleMulticonnectProfileService implements P stopAlarm(device); } + @Override + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { + final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL); + broadcast.putExtra(EXTRA_DEVICE, device); + broadcast.putExtra(EXTRA_BATTERY_LEVEL, batteryLevel); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + private void createBackgroundNotification() { final List connectedDevices = getConnectedDevices(); for (final BluetoothDevice device : connectedDevices) {