From f25a90230595b65dc6a636d3e0784afaffa86cef Mon Sep 17 00:00:00 2001 From: Aleksander Nowakowski Date: Mon, 18 Dec 2017 13:05:01 +0100 Subject: [PATCH] BleManager extracted to a standalone module --- app/build.gradle | 3 + .../PermissionRationaleFragment.java | 1 - .../android/nrftoolbox/bpm/BPMActivity.java | 2 +- .../android/nrftoolbox/bpm/BPMManager.java | 2 +- .../nrftoolbox/bpm/BPMManagerCallbacks.java | 2 +- .../android/nrftoolbox/cgms/CGMSManager.java | 2 +- .../nrftoolbox/cgms/CGMSManagerCallbacks.java | 2 +- .../android/nrftoolbox/cgms/CGMService.java | 2 +- .../android/nrftoolbox/csc/CSCActivity.java | 2 +- .../android/nrftoolbox/csc/CSCManager.java | 2 +- .../nrftoolbox/csc/CSCManagerCallbacks.java | 2 +- .../android/nrftoolbox/csc/CSCService.java | 6 +- .../android/nrftoolbox/dfu/DfuActivity.java | 1 - .../nrftoolbox/gls/GlucoseActivity.java | 2 +- .../nrftoolbox/gls/GlucoseManager.java | 2 +- .../gls/GlucoseManagerCallbacks.java | 2 +- .../android/nrftoolbox/hrs/HRSActivity.java | 2 +- .../android/nrftoolbox/hrs/HRSManager.java | 2 +- .../nrftoolbox/hrs/HRSManagerCallbacks.java | 2 +- .../android/nrftoolbox/hts/HTSActivity.java | 2 +- .../android/nrftoolbox/hts/HTSManager.java | 2 +- .../nrftoolbox/hts/HTSManagerCallbacks.java | 2 +- .../android/nrftoolbox/hts/HTSService.java | 2 +- .../nrftoolbox/profile/BleManager.java | 1643 ----------------- .../profile/BleManagerCallbacks.java | 146 -- .../profile/BleProfileActivity.java | 2 + .../BleProfileExpandableListActivity.java | 2 + .../nrftoolbox/profile/BleProfileService.java | 3 + .../BleProfileServiceReadyActivity.java | 1 + .../android/nrftoolbox/profile/ILogger.java | 43 - .../BleMulticonnectProfileService.java | 6 +- ...lticonnectProfileServiceReadyActivity.java | 2 +- .../proximity/ProximityManager.java | 2 +- .../proximity/ProximityManagerCallbacks.java | 2 +- .../ProximityServerManagerCallbacks.java | 2 +- .../proximity/ProximityService.java | 4 +- .../android/nrftoolbox/rsc/RSCManager.java | 2 +- .../nrftoolbox/rsc/RSCManagerCallbacks.java | 2 +- .../android/nrftoolbox/rsc/RSCService.java | 4 +- .../nrftoolbox/scanner/DeviceListAdapter.java | 2 +- .../nrftoolbox/scanner/ScannerFragment.java | 1 - .../nrftoolbox/template/TemplateManager.java | 2 +- .../template/TemplateManagerCallbacks.java | 2 +- .../nrftoolbox/template/TemplateService.java | 4 +- .../android/nrftoolbox/uart/UARTActivity.java | 3 +- .../nrftoolbox/uart/UARTEditDialog.java | 1 - .../nrftoolbox/uart/UARTLogFragment.java | 2 - .../android/nrftoolbox/uart/UARTManager.java | 2 +- .../nrftoolbox/uart/UARTManagerCallbacks.java | 2 +- .../android/nrftoolbox/uart/UARTService.java | 4 +- .../UARTConfigurationSynchronizer.java | 2 +- .../nrftoolbox/utility/ParserUtils.java | 30 +- .../wearable/MainWearableListenerService.java | 2 +- .../nrftoolbox/widget/ClosableSpinner.java | 1 - .../widget/TrebuchetBoldTextView.java | 1 - .../nrftoolbox/widget/TrebuchetTextView.java | 1 - common/src/main/AndroidManifest.xml | 4 - .../android/nrftoolbox/error/GattError.java | 150 -- .../android/nrftoolbox/ble/BleManager.java | 107 +- .../android/nrftoolbox/ble/BleProfile.java | 26 + .../android/nrftoolbox/ble/BleProfileApi.java | 136 +- 61 files changed, 294 insertions(+), 2106 deletions(-) delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManager.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManagerCallbacks.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/ILogger.java delete mode 100644 common/src/main/java/no/nordicsemi/android/nrftoolbox/error/GattError.java diff --git a/app/build.gradle b/app/build.gradle index 06f63ffb..1de1f496 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -54,6 +54,9 @@ dependencies { // add it as a module into the project structure and uncomment the following line (and also the according lines in the settings.gradle): // implementation project(':dfu') + // Import the BLE Library + implementation project(':ble') + implementation('org.simpleframework:simple-xml:2.7.1') { exclude group: 'stax', module: 'stax-api' exclude group: 'xpp3', module: 'xpp3' diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/PermissionRationaleFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/PermissionRationaleFragment.java index b1418c5e..cd8c5409 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/PermissionRationaleFragment.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/PermissionRationaleFragment.java @@ -23,7 +23,6 @@ package no.nordicsemi.android.nrftoolbox; import android.app.Dialog; import android.content.Context; -import android.content.DialogInterface; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMActivity.java index 74976617..7d4f9f3e 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMActivity.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMActivity.java @@ -28,8 +28,8 @@ import android.widget.TextView; import java.util.Calendar; import java.util.UUID; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; import no.nordicsemi.android.nrftoolbox.profile.BleProfileActivity; // TODO The BPMActivity should be rewritten to use the service approach, like other do. diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManager.java index 88586ffe..a93aad9b 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManager.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManager.java @@ -31,10 +31,10 @@ import java.util.Deque; import java.util.LinkedList; import java.util.UUID; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.parser.BloodPressureMeasurementParser; import no.nordicsemi.android.nrftoolbox.parser.IntermediateCuffPressureParser; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; public class BPMManager extends BleManager { /** Blood Pressure service UUID */ diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManagerCallbacks.java index 76550bd6..707192f6 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManagerCallbacks.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManagerCallbacks.java @@ -25,7 +25,7 @@ import android.bluetooth.BluetoothDevice; import java.util.Calendar; -import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; +import no.nordicsemi.android.ble.BleManagerCallbacks; public interface BPMManagerCallbacks extends BleManagerCallbacks { int UNIT_mmHG = 0; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManager.java index cba3f55b..9981921a 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManager.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManager.java @@ -32,11 +32,11 @@ import java.util.Deque; import java.util.LinkedList; import java.util.UUID; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.parser.CGMMeasurementParser; import no.nordicsemi.android.nrftoolbox.parser.CGMSpecificOpsControlPointParser; import no.nordicsemi.android.nrftoolbox.parser.RecordAccessControlPointParser; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; public class CGMSManager extends BleManager { diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManagerCallbacks.java index ecd32d60..61ad7883 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManagerCallbacks.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManagerCallbacks.java @@ -24,7 +24,7 @@ package no.nordicsemi.android.nrftoolbox.cgms; import android.bluetooth.BluetoothDevice; -import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; +import no.nordicsemi.android.ble.BleManagerCallbacks; public interface CGMSManagerCallbacks extends BleManagerCallbacks { /** diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMService.java index c902df0d..fb1d2ae9 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMService.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMService.java @@ -12,11 +12,11 @@ import android.support.v4.app.NotificationCompat; import android.support.v4.content.LocalBroadcastManager; import android.util.SparseArray; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.FeaturesActivity; import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; public class CGMService extends BleProfileService implements CGMSManagerCallbacks { diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCActivity.java index 3fe2649b..03132f83 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCActivity.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCActivity.java @@ -38,9 +38,9 @@ import java.util.Locale; import java.util.UUID; import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; import no.nordicsemi.android.nrftoolbox.csc.settings.SettingsActivity; import no.nordicsemi.android.nrftoolbox.csc.settings.SettingsFragment; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity; public class CSCActivity extends BleProfileServiceReadyActivity { diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManager.java index fb7919fa..b1d03987 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManager.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManager.java @@ -31,9 +31,9 @@ import java.util.Deque; import java.util.LinkedList; import java.util.UUID; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.parser.CSCMeasurementParser; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; public class CSCManager extends BleManager { /** Cycling Speed and Cadence service UUID */ diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManagerCallbacks.java index 23826095..6555bcf3 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManagerCallbacks.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManagerCallbacks.java @@ -23,7 +23,7 @@ package no.nordicsemi.android.nrftoolbox.csc; import android.bluetooth.BluetoothDevice; -import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; +import no.nordicsemi.android.ble.BleManagerCallbacks; public interface CSCManagerCallbacks extends BleManagerCallbacks { int NOT_AVAILABLE = -1; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCService.java index 03f1d153..64ba264f 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCService.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCService.java @@ -32,16 +32,16 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.preference.PreferenceManager; -import android.support.v4.content.LocalBroadcastManager; import android.support.v4.app.NotificationCompat; +import android.support.v4.content.LocalBroadcastManager; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.FeaturesActivity; import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; import no.nordicsemi.android.nrftoolbox.csc.settings.SettingsFragment; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; public class CSCService extends BleProfileService implements CSCManagerCallbacks { private static final String TAG = "CSCService"; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuActivity.java index 00179f8a..e76465d0 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuActivity.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuActivity.java @@ -31,7 +31,6 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothManager; import android.content.Context; import android.content.CursorLoader; -import android.content.DialogInterface; import android.content.Intent; import android.content.Loader; import android.content.SharedPreferences; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseActivity.java index bf30e1a2..bd94c4f5 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseActivity.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseActivity.java @@ -33,8 +33,8 @@ import android.widget.TextView; import java.util.UUID; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; import no.nordicsemi.android.nrftoolbox.profile.BleProfileExpandableListActivity; // TODO The GlucoseActivity should be rewritten to use the service approach, like other do. diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManager.java index acd9e62c..460449e6 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManager.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManager.java @@ -33,11 +33,11 @@ import java.util.Deque; import java.util.LinkedList; import java.util.UUID; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.parser.GlucoseMeasurementContextParser; import no.nordicsemi.android.nrftoolbox.parser.GlucoseMeasurementParser; import no.nordicsemi.android.nrftoolbox.parser.RecordAccessControlPointParser; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; @SuppressWarnings("unused") diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManagerCallbacks.java index 87c69d76..6bc8ff3d 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManagerCallbacks.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManagerCallbacks.java @@ -23,7 +23,7 @@ package no.nordicsemi.android.nrftoolbox.gls; import android.bluetooth.BluetoothDevice; -import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; +import no.nordicsemi.android.ble.BleManagerCallbacks; public interface GlucoseManagerCallbacks extends BleManagerCallbacks { void onOperationStarted(final BluetoothDevice device); diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSActivity.java index 9acc4f84..65a34d48 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSActivity.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSActivity.java @@ -35,9 +35,9 @@ import org.achartengine.GraphicalView; import java.util.UUID; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.nrftoolbox.FeaturesActivity; import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; import no.nordicsemi.android.nrftoolbox.profile.BleProfileActivity; /** diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManager.java index aa5ac708..45c56397 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManager.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManager.java @@ -30,11 +30,11 @@ import java.util.Deque; import java.util.LinkedList; import java.util.UUID; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.nrftoolbox.parser.BodySensorLocationParser; import no.nordicsemi.android.nrftoolbox.parser.HeartRateMeasurementParser; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; /** * HRSManager class performs BluetoothGatt operations for connection, service discovery, enabling notification and reading characteristics. All operations required to connect to device with BLE HR diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManagerCallbacks.java index 13127cc4..aa55d822 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManagerCallbacks.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManagerCallbacks.java @@ -23,7 +23,7 @@ package no.nordicsemi.android.nrftoolbox.hrs; import android.bluetooth.BluetoothDevice; -import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; +import no.nordicsemi.android.ble.BleManagerCallbacks; public interface HRSManagerCallbacks extends BleManagerCallbacks { diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSActivity.java index 858e2d33..4e2009a2 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSActivity.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSActivity.java @@ -37,9 +37,9 @@ import java.text.DecimalFormat; import java.util.UUID; import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; import no.nordicsemi.android.nrftoolbox.hts.settings.SettingsActivity; import no.nordicsemi.android.nrftoolbox.hts.settings.SettingsFragment; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity; /** diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManager.java index 8ab3e9f7..83a7807f 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManager.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManager.java @@ -30,9 +30,9 @@ import java.util.Deque; import java.util.LinkedList; import java.util.UUID; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.parser.TemperatureMeasurementParser; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; /** diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManagerCallbacks.java index e7eb5baa..6fdb6eb0 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManagerCallbacks.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManagerCallbacks.java @@ -23,7 +23,7 @@ package no.nordicsemi.android.nrftoolbox.hts; import android.bluetooth.BluetoothDevice; -import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; +import no.nordicsemi.android.ble.BleManagerCallbacks; /** * Interface {@link HTSManagerCallbacks} must be implemented by {@link HTSActivity} in order to receive callbacks from {@link HTSManager} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSService.java index bb8da22e..0bf641b0 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSService.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSService.java @@ -33,11 +33,11 @@ import android.content.IntentFilter; import android.support.v4.app.NotificationCompat; import android.support.v4.content.LocalBroadcastManager; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.FeaturesActivity; import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; public class HTSService extends BleProfileService implements HTSManagerCallbacks { 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 deleted file mode 100644 index 7a9736d9..00000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManager.java +++ /dev/null @@ -1,1643 +0,0 @@ -/* - * Copyright (c) 2015, Nordic Semiconductor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package no.nordicsemi.android.nrftoolbox.profile; - -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothGatt; -import android.bluetooth.BluetoothGattCallback; -import android.bluetooth.BluetoothGattCharacteristic; -import android.bluetooth.BluetoothGattDescriptor; -import android.bluetooth.BluetoothGattService; -import android.bluetooth.BluetoothProfile; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Build; -import android.os.Handler; -import android.support.annotation.StringRes; -import android.util.Log; - -import java.lang.reflect.Method; -import java.util.Deque; -import java.util.LinkedList; -import java.util.Queue; -import java.util.UUID; - -import no.nordicsemi.android.log.ILogSession; -import no.nordicsemi.android.log.Logger; -import no.nordicsemi.android.nrftoolbox.error.GattError; -import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; -import no.nordicsemi.android.nrftoolbox.utility.ParserUtils; - -/** - * DO NOT EDIT THIS FILE UNLESS NECESSARY! - * The BleManager should be overridden in your app and all the 'high level' callbacks should be called from there. - * Keeping this file as is (and {@link BleManagerCallbacks} as well) will allow to quickly update it when an update is posted here. - * - *

The BleManager is responsible for managing the low level communication with a Bluetooth Smart device. Please see profiles implementation for an example of use. - * This base manager has been tested against number of devices and samples from Nordic SDK.

- *

The manager handles connection events and initializes the device after establishing the connection. - *

    - *
  1. For bonded devices it ensures that the Service Changed indications, if this characteristic is present, are enabled. Android does not enable them by default, - * leaving this to the developers.
  2. - *
  3. The manager tries to read the Battery Level characteristic. No matter the result of this operation (for example the Battery Level characteristic may not have the READ property) - * it tries to enable Battery Level notifications, to get battery updates from the device.
  4. - *
  5. Afterwards, the manager initializes the device using given queue of commands. See {@link BleManagerGattCallback#initGatt(BluetoothGatt)} method for more details.
  6. - *
  7. When initialization complete, the {@link BleManagerCallbacks#onDeviceReady(BluetoothDevice)} callback is called.
  8. - *
The manager also is responsible for parsing the Battery Level values and calling {@link BleManagerCallbacks#onBatteryValueReceived(BluetoothDevice, int)} method.

- *

Events from all profiles are being logged into the nRF Logger application, - * which may be downloaded from Google Play: https://play.google.com/store/apps/details?id=no.nordicsemi.android.log

- *

The nRF Logger application allows you to see application logs without need to connect it to the computer.

- * - * @param The profile callbacks type - */ -public abstract class BleManager implements ILogger { - private final static String TAG = "BleManager"; - - private final static UUID CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); - - private final static UUID BATTERY_SERVICE = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb"); - private final static UUID BATTERY_LEVEL_CHARACTERISTIC = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb"); - - private final static UUID GENERIC_ATTRIBUTE_SERVICE = UUID.fromString("00001801-0000-1000-8000-00805f9b34fb"); - private final static UUID SERVICE_CHANGED_CHARACTERISTIC = UUID.fromString("00002A05-0000-1000-8000-00805f9b34fb"); - - private final Object mLock = new Object(); - /** - * 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 BluetoothGatt mBluetoothGatt; - private BleManagerGattCallback mGattCallback; - /** - * 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. - */ - private boolean mUserDisconnected; - /** - * Flag set to true when {@link #shouldAutoConnect()} method returned true. The first connection attempt is done with autoConnect - * flag set to false (to make the first connection quick) but on connection lost the manager will call {@link #connect(BluetoothDevice)} again. - * This time this method will call {@link BluetoothGatt#connect()} which always uses autoConnect equal true. - */ - private boolean mInitialConnection; - /** 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); - - 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); - } - // Calling close() will prevent the STATE_OFF event from being logged (this receiver will be unregistered). But it doesn't matter. - 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) { - final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1); - final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1); - - // Skip other devices - if (mBluetoothGatt == null || !device.getAddress().equals(mBluetoothGatt.getDevice().getAddress())) - return; - - Logger.d(mLogSession, "[Broadcast] Action received: " + BluetoothDevice.ACTION_BOND_STATE_CHANGED + ", bond state changed to: " + bondStateToString(bondState) + " (" + bondState + ")"); - DebugLogger.i(TAG, "Bond state changed for: " + device.getName() + " new state: " + bondState + " previous: " + previousBondState); - - switch (bondState) { - case BluetoothDevice.BOND_BONDING: - mCallbacks.onBondingRequired(device); - break; - case BluetoothDevice.BOND_BONDED: - Logger.i(mLogSession, "Device bonded"); - mCallbacks.onBonded(device); - - // Start initializing again. - // In fact, bonding forces additional, internal service discovery (at least on Nexus devices), so this method may safely be used to start this process again. - Logger.v(mLogSession, "Discovering Services..."); - Logger.d(mLogSession, "gatt.discoverServices()"); - mBluetoothGatt.discoverServices(); - break; - } - } - }; - - private final BroadcastReceiver mPairingRequestBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(final Context context, final Intent intent) { - final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - - // Skip other devices - if (mBluetoothGatt == null || !device.getAddress().equals(mBluetoothGatt.getDevice().getAddress())) - return; - - // String values are used as the constants are not available for Android 4.3. - final int variant = intent.getIntExtra("android.bluetooth.device.extra.PAIRING_VARIANT"/*BluetoothDevice.EXTRA_PAIRING_VARIANT*/, 0); - Logger.d(mLogSession, "[Broadcast] Action received: android.bluetooth.device.action.PAIRING_REQUEST"/*BluetoothDevice.ACTION_PAIRING_REQUEST*/ + - ", pairing variant: " + pairingVariantToString(variant) + " (" + variant + ")"); - - // The API below is available for Android 4.4 or newer. - - // An app may set the PIN here or set pairing confirmation (depending on the variant) using: - // device.setPin(new byte[] { '1', '2', '3', '4', '5', '6' }); - // device.setPairingConfirmation(true); - } - }; - - public BleManager(final Context context) { - mContext = context; - mHandler = new Handler(); - } - - /** - * Returns the context that the manager was created with. - * - * @return the context - */ - protected Context getContext() { - return mContext; - } - - /** - * This method must return the gatt callback used by the manager. - * This method must not create a new gatt callback each time it is being invoked, but rather return a single object. - * - * @return the gatt callback object - */ - protected abstract BleManagerGattCallback getGattCallback(); - - /** - * Returns whether to connect to the remote device just once (false) or to add the address to white list of devices - * that will be automatically connect as soon as they become available (true). In the latter case, if - * Bluetooth adapter is enabled, Android scans periodically for devices from the white list and if a advertising packet - * is received from such, it tries to connect to it. When the connection is lost, the system will keep trying to reconnect - * to it in. If true is returned, and the connection to the device is lost the {@link BleManagerCallbacks#onLinklossOccur(BluetoothDevice)} - * callback is called instead of {@link BleManagerCallbacks#onDeviceDisconnected(BluetoothDevice)}. - *

This feature works much better on newer Android phone models and many not work on older phones.

- *

This method should only be used with bonded devices, as otherwise the device may change it's address. - * It will however work also with non-bonded devices with private static address. A connection attempt to - * a device with private resolvable address will fail.

- *

The first connection to a device will always be created with autoConnect flag to false - * (see {@link BluetoothDevice#connectGatt(Context, boolean, BluetoothGattCallback)}). This is to make it quick as the - * user most probably waits for a quick response. However, if this method returned true during first connection and the link was lost, - * the manager will try to reconnect to it using {@link BluetoothGatt#connect()} which forces autoConnect to true .

- * - * @return autoConnect flag value - */ - protected boolean shouldAutoConnect() { - return false; - } - - /** - * Connects to the Bluetooth Smart device. - * - * @param device a device to connect to - */ - public void connect(final BluetoothDevice device) { - if (mConnected) - return; - - synchronized (mLock) { - if (mBluetoothGatt != null) { - // There are 2 ways of reconnecting to the same device: - // 1. Reusing the same BluetoothGatt object and calling connect() - this will force the autoConnect flag to true - // 2. Closing it and reopening a new instance of BluetoothGatt object. - // The gatt.close() is an asynchronous method. It requires some time before it's finished and - // device.connectGatt(...) can't be called immediately or service discovery - // may never finish on some older devices (Nexus 4, Android 5.0.1). - // If shouldAutoConnect() method returned false we can't call gatt.connect() and have to close gatt and open it again. - if (!mInitialConnection) { - Logger.d(mLogSession, "gatt.close()"); - mBluetoothGatt.close(); - mBluetoothGatt = null; - try { - Logger.d(mLogSession, "wait(200)"); - Thread.sleep(200); // Is 200 ms enough? - } catch (final InterruptedException e) { - // Ignore - } - } else { - // Instead, the gatt.connect() method will be used to reconnect to the same device. - // This method forces autoConnect = true even if the gatt was created with this flag set to false. - mInitialConnection = false; - Logger.v(mLogSession, "Connecting..."); - mConnectionState = BluetoothGatt.STATE_CONNECTING; - mCallbacks.onDeviceConnecting(device); - Logger.d(mLogSession, "gatt.connect()"); - mBluetoothGatt.connect(); - return; - } - } 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*/)); - } - } - - final boolean shouldAutoConnect = shouldAutoConnect(); - mUserDisconnected = !shouldAutoConnect; // We will receive Linkloss events only when the device is connected with autoConnect=true - // The first connection will always be done with autoConnect = false to make the connection quick. - // If the shouldAutoConnect() method returned true, the manager will automatically try to reconnect to this device on link loss. - if (shouldAutoConnect) - mInitialConnection = true; - mBluetoothDevice = device; - Logger.v(mLogSession, "Connecting..."); - mConnectionState = BluetoothGatt.STATE_CONNECTING; - mCallbacks.onDeviceConnecting(device); - Logger.d(mLogSession, "gatt = device.connectGatt(autoConnect = false)"); - mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback = getGattCallback()); - } - - /** - * Disconnects from the device or cancels the pending connection attempt. Does nothing if device was not connected. - * @return true if device is to be disconnected. False if it was already disconnected. - */ - public boolean disconnect() { - mUserDisconnected = true; - mInitialConnection = false; - - if (mBluetoothGatt != null) { - mConnectionState = BluetoothGatt.STATE_DISCONNECTING; - Logger.v(mLogSession, mConnected ? "Disconnecting..." : "Cancelling connection..."); - mCallbacks.onDeviceDisconnecting(mBluetoothGatt.getDevice()); - final boolean wasConnected = mConnected; - Logger.d(mLogSession, "gatt.disconnect()"); - mBluetoothGatt.disconnect(); - - if (!wasConnected) { - // There will be no callback, the connection attempt will be stopped - mConnectionState = BluetoothGatt.STATE_DISCONNECTED; - Logger.i(mLogSession, "Disconnected"); - mCallbacks.onDeviceDisconnected(mBluetoothGatt.getDevice()); - } - return true; - } - return false; - } - - /** - * This method returns true if the device is connected. Services could have not been discovered yet. - */ - public boolean isConnected() { - return mConnected; - } - - /** - * Method returns the connection state: - * {@link BluetoothGatt#STATE_CONNECTING STATE_CONNECTING}, - * {@link BluetoothGatt#STATE_CONNECTED STATE_CONNECTED}, - * {@link BluetoothGatt#STATE_DISCONNECTING STATE_DISCONNECTING}, - * {@link BluetoothGatt#STATE_DISCONNECTED STATE_DISCONNECTED} - * @return the connection state - */ - public int getConnectionState() { - return mConnectionState; - } - - /** - * Returns the last received value of Battery Level characteristic, or -1 if such does not exist, hasn't been read or notification wasn't received yet. - * @return the last battery level value in percent - */ - public int getBatteryValue() { - return mBatteryValue; - } - - /** - * Closes and releases resources. May be also used to unregister broadcast listeners. - */ - public void close() { - try { - mContext.unregisterReceiver(mBluetoothStateBroadcastReceiver); - mContext.unregisterReceiver(mBondingBroadcastReceiver); - mContext.unregisterReceiver(mPairingRequestBroadcastReceiver); - } catch (Exception e) { - // the receiver must have been not registered or unregistered before - } - synchronized (mLock) { - if (mBluetoothGatt != null) { - Logger.d(mLogSession, "gatt.close()"); - mBluetoothGatt.close(); - mBluetoothGatt = null; - } - mConnected = false; - mInitialConnection = false; - mConnectionState = BluetoothGatt.STATE_DISCONNECTED; - mGattCallback = null; - mBluetoothDevice = null; - } - } - - /** - * Sets the optional log session. This session will be used to log Bluetooth events. - * The logs may be viewed using the nRF Logger application: https://play.google.com/store/apps/details?id=no.nordicsemi.android.log - * Since nRF Logger Library v2.0 an app may define it's own log provider. Use {@link BleProfileServiceReadyActivity#getLocalAuthorityLogger()} to define local log URI. - * NOTE: nRF Logger must be installed prior to nRF Toolbox as it defines the required permission which is used by nRF Toolbox. - * - * @param session the session, or null if nRF Logger is not installed. - */ - public void setLogger(final ILogSession session) { - mLogSession = session; - } - - @Override - public void log(final int level, final String message) { - Logger.log(mLogSession, level, message); - } - - @Override - public void log(final int level, @StringRes final int messageRes, final Object... params) { - Logger.log(mLogSession, level, messageRes, params); - } - - /** - * Sets the manager callback listener - * - * @param callbacks the callback listener - */ - public void setGattCallbacks(E callbacks) { - mCallbacks = callbacks; - } - - /** - * Enqueues creating bond request to the queue. - * @return true if request has been enqueued, false if the device has not been connected - */ - protected final boolean createBond() { - return enqueue(Request.createBond()); - } - - /** - * Creates a bond with the device. The device must be first set using {@link #connect(BluetoothDevice)} which will - * try to connect to the device. If you need to pair with a device before connecting to it you may do it without - * the use of BleManager object and connect after bond is established. - * @return true if pairing has started, false if it was already paired or an immediate error occur. - */ - private boolean internalCreateBond() { - final BluetoothDevice device = mBluetoothDevice; - if (device == null) - return false; - - if (device.getBondState() == BluetoothDevice.BOND_BONDED) { - Logger.v(mLogSession, "Create bond request on already bonded device..."); - Logger.i(mLogSession, "Device bonded"); - return false; - } - - Logger.v(mLogSession, "Starting pairing..."); - - boolean result = false; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - Logger.d(mLogSession, "device.createBond()"); - result = device.createBond(); - } else { - /* - * There is a createBond() method in BluetoothDevice class but for now it's hidden. We will call it using reflections. It has been revealed in KitKat (Api19) - */ - try { - final Method createBond = device.getClass().getMethod("createBond"); - if (createBond != null) { - Logger.d(mLogSession, "device.createBond() (hidden)"); - result = (Boolean) createBond.invoke(device); - } - } catch (final Exception e) { - Log.w(TAG, "An exception occurred while creating bond", e); - } - } - - if (!result) - Log.w(TAG, "Creating bond failed"); - return result; - } - - /** - * When the device is bonded and has the Generic Attribute service and the Service Changed characteristic this method enables indications on this characteristic. - * In case one of the requirements is not fulfilled this method returns false. - * - * @return true when the request has been sent, false when the device is not bonded, does not have the Generic Attribute service, the GA service does not have - * the Service Changed characteristic or this characteristic does not have the CCCD. - */ - private boolean ensureServiceChangedEnabled() { - final BluetoothGatt gatt = mBluetoothGatt; - if (gatt == null) - return false; - - // The Service Changed indications have sense only on bonded devices - final BluetoothDevice device = gatt.getDevice(); - if (device.getBondState() != BluetoothDevice.BOND_BONDED) - return false; - - final BluetoothGattService gaService = gatt.getService(GENERIC_ATTRIBUTE_SERVICE); - if (gaService == null) - return false; - - final BluetoothGattCharacteristic scCharacteristic = gaService.getCharacteristic(SERVICE_CHANGED_CHARACTERISTIC); - if (scCharacteristic == null) - return false; - - Logger.i(mLogSession, "Service Changed characteristic found on a bonded device"); - return internalEnableIndications(scCharacteristic); - } - - /** - * Enables notifications on given characteristic. - * - * @return true is the request has been enqueued - */ - protected final boolean enableNotifications(final BluetoothGattCharacteristic characteristic) { - return enqueue(Request.newEnableNotificationsRequest(characteristic)); - } - - private boolean internalEnableNotifications(final BluetoothGattCharacteristic characteristic) { - final BluetoothGatt gatt = mBluetoothGatt; - if (gatt == null || characteristic == null) - return false; - - // Check characteristic property - final int properties = characteristic.getProperties(); - if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) == 0) - return false; - - Logger.d(mLogSession, "gatt.setCharacteristicNotification(" + characteristic.getUuid() + ", true)"); - gatt.setCharacteristicNotification(characteristic, true); - final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); - if (descriptor != null) { - descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); - Logger.v(mLogSession, "Enabling notifications for " + characteristic.getUuid()); - Logger.d(mLogSession, "gatt.writeDescriptor(" + CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID + ", value=0x01-00)"); - return internalWriteDescriptorWorkaround(descriptor); - } - return false; - } - - /** - * Enables indications on given characteristic. - * - * @return true is the request has been enqueued - */ - protected final boolean enableIndications(final BluetoothGattCharacteristic characteristic) { - return enqueue(Request.newEnableIndicationsRequest(characteristic)); - } - - private boolean internalEnableIndications(final BluetoothGattCharacteristic characteristic) { - final BluetoothGatt gatt = mBluetoothGatt; - if (gatt == null || characteristic == null) - return false; - - // Check characteristic property - final int properties = characteristic.getProperties(); - if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) == 0) - return false; - - Logger.d(mLogSession, "gatt.setCharacteristicNotification(" + characteristic.getUuid() + ", true)"); - gatt.setCharacteristicNotification(characteristic, true); - final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); - if (descriptor != null) { - descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); - Logger.v(mLogSession, "Enabling indications for " + characteristic.getUuid()); - Logger.d(mLogSession, "gatt.writeDescriptor(" + CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID + ", value=0x02-00)"); - return internalWriteDescriptorWorkaround(descriptor); - } - return false; - } - - /** - * Sends the read request to the given characteristic. - * - * @param characteristic the characteristic to read - * @return true if request has been enqueued - */ - protected final boolean readCharacteristic(final BluetoothGattCharacteristic characteristic) { - return enqueue(Request.newReadRequest(characteristic)); - } - - private boolean internalReadCharacteristic(final BluetoothGattCharacteristic characteristic) { - final BluetoothGatt gatt = mBluetoothGatt; - if (gatt == null || characteristic == null) - return false; - - // Check characteristic property - final int properties = characteristic.getProperties(); - if ((properties & BluetoothGattCharacteristic.PROPERTY_READ) == 0) - return false; - - Logger.v(mLogSession, "Reading characteristic " + characteristic.getUuid()); - Logger.d(mLogSession, "gatt.readCharacteristic(" + characteristic.getUuid() + ")"); - return gatt.readCharacteristic(characteristic); - } - - /** - * Writes the characteristic value to the given characteristic. - * - * @param characteristic the characteristic to write to - * @return true if request has been enqueued - */ - protected final boolean writeCharacteristic(final BluetoothGattCharacteristic characteristic) { - return enqueue(Request.newWriteRequest(characteristic, characteristic.getValue())); - } - - private boolean internalWriteCharacteristic(final BluetoothGattCharacteristic characteristic) { - final BluetoothGatt gatt = mBluetoothGatt; - if (gatt == null || characteristic == null) - return false; - - // Check characteristic property - final int properties = characteristic.getProperties(); - if ((properties & (BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE)) == 0) - return false; - - Logger.v(mLogSession, "Writing characteristic " + characteristic.getUuid() + " (" + getWriteType(characteristic.getWriteType()) + ")"); - Logger.d(mLogSession, "gatt.writeCharacteristic(" + characteristic.getUuid() + ")"); - return gatt.writeCharacteristic(characteristic); - } - - /** - * Sends the read request to the given descriptor. - * - * @param descriptor the descriptor to read - * @return true if request has been enqueued - */ - protected final boolean readDescriptor(final BluetoothGattDescriptor descriptor) { - return enqueue(Request.newReadRequest(descriptor)); - } - - private boolean internalReadDescriptor(final BluetoothGattDescriptor descriptor) { - final BluetoothGatt gatt = mBluetoothGatt; - if (gatt == null || descriptor == null) - return false; - - Logger.v(mLogSession, "Reading descriptor " + descriptor.getUuid()); - Logger.d(mLogSession, "gatt.readDescriptor(" + descriptor.getUuid() + ")"); - return gatt.readDescriptor(descriptor); - } - - /** - * Writes the descriptor value to the given descriptor. - * - * @param descriptor the descriptor to write to - * @return true if request has been enqueued - */ - protected final boolean writeDescriptor(final BluetoothGattDescriptor descriptor) { - return enqueue(Request.newWriteRequest(descriptor, descriptor.getValue())); - } - - private boolean internalWriteDescriptor(final BluetoothGattDescriptor descriptor) { - final BluetoothGatt gatt = mBluetoothGatt; - if (gatt == null || descriptor == null) - return false; - - Logger.v(mLogSession, "Writing descriptor " + descriptor.getUuid()); - Logger.d(mLogSession, "gatt.writeDescriptor(" + descriptor.getUuid() + ")"); - return internalWriteDescriptorWorkaround(descriptor); - } - - /** - * Reads the battery level from the device. - * - * @return true if request has been enqueued - */ - public final boolean readBatteryLevel() { - return enqueue(Request.newReadBatteryLevelRequest()); - } - - private boolean internalReadBatteryLevel() { - final BluetoothGatt gatt = mBluetoothGatt; - if (gatt == null) - return false; - - final BluetoothGattService batteryService = gatt.getService(BATTERY_SERVICE); - if (batteryService == null) - return false; - - final BluetoothGattCharacteristic batteryLevelCharacteristic = batteryService.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC); - if (batteryLevelCharacteristic == null) - return false; - - // Check characteristic property - final int properties = batteryLevelCharacteristic.getProperties(); - if ((properties & BluetoothGattCharacteristic.PROPERTY_READ) == 0) - return false; - - Logger.a(mLogSession, "Reading battery level..."); - return internalReadCharacteristic(batteryLevelCharacteristic); - } - - /** - * This method tries to enable notifications on the Battery Level characteristic. - * - * @param enable true to enable battery notifications, false to disable - * @return true if request has been enqueued - */ - public final boolean setBatteryNotifications(final boolean enable) { - if (enable) - return enqueue(Request.newEnableBatteryLevelNotificationsRequest()); - else - return enqueue(Request.newDisableBatteryLevelNotificationsRequest()); - } - - private boolean internalSetBatteryNotifications(final boolean enable) { - final BluetoothGatt gatt = mBluetoothGatt; - if (gatt == null) { - return false; - } - - final BluetoothGattService batteryService = gatt.getService(BATTERY_SERVICE); - if (batteryService == null) - return false; - - final BluetoothGattCharacteristic batteryLevelCharacteristic = batteryService.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC); - if (batteryLevelCharacteristic == null) - return false; - - // Check characteristic property - final int properties = batteryLevelCharacteristic.getProperties(); - if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) == 0) - return false; - - gatt.setCharacteristicNotification(batteryLevelCharacteristic, enable); - final BluetoothGattDescriptor descriptor = batteryLevelCharacteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); - if (descriptor != null) { - if (enable) { - descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); - Logger.a(mLogSession, "Enabling battery level notifications..."); - Logger.v(mLogSession, "Enabling notifications for " + BATTERY_LEVEL_CHARACTERISTIC); - Logger.d(mLogSession, "gatt.writeDescriptor(" + CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID + ", value=0x0100)"); - } else { - descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); - Logger.a(mLogSession, "Disabling battery level notifications..."); - Logger.v(mLogSession, "Disabling notifications for " + BATTERY_LEVEL_CHARACTERISTIC); - Logger.d(mLogSession, "gatt.writeDescriptor(" + CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID + ", value=0x0000)"); - } - return internalWriteDescriptorWorkaround(descriptor); - } - return false; - } - - /** - * There was a bug in Android up to 6.0 where the descriptor was written using parent - * characteristic's write type, instead of always Write With Response, as the spec says. - *

- * See: - * https://android.googlesource.com/platform/frameworks/base/+/942aebc95924ab1e7ea1e92aaf4e7fc45f695a6c%5E%21/#F0 - *

- * @param descriptor the descriptor to be written - * @return the result of {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor)} - */ - private boolean internalWriteDescriptorWorkaround(final BluetoothGattDescriptor descriptor) { - final BluetoothGatt gatt = mBluetoothGatt; - if (gatt == null || descriptor == null) - return false; - - final BluetoothGattCharacteristic parentCharacteristic = descriptor.getCharacteristic(); - final int originalWriteType = parentCharacteristic.getWriteType(); - parentCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT); - final boolean result = gatt.writeDescriptor(descriptor); - parentCharacteristic.setWriteType(originalWriteType); - return result; - } - - /** - * Enqueues a new request. The request will be handled immediately if there is no operation in progress, - * or automatically after the last enqueued one will finish. - *

This method should be used to read and write data from the target device as it ensures that the last operation has finished - * before a new one will be called.

- * @param request new request to be added to the queue. - * @return true if request has been enqueued, false if the {@link #connect(BluetoothDevice)} method was not called before, - * or the manager was closed using {@link #close()}. - */ - public boolean enqueue(final Request request) { - if (mGattCallback != null) { - // Add the new task to the end of the queue - mGattCallback.mTaskQueue.add(request); - mGattCallback.nextRequest(); - return true; - } - return false; - } - - /** - * On Android, when multiple BLE operations needs to be done, it is required to wait for a proper - * {@link android.bluetooth.BluetoothGattCallback BluetoothGattCallback} callback before calling - * another operation. In order to make BLE operations easier the BleManager allows to enqueue a request - * containing all data necessary for a given operation. Requests are performed one after another until the - * queue is empty. Use static methods from below to instantiate a request and then enqueue them using {@link #enqueue(Request)}. - */ - protected static final class Request { - private enum Type { - CREATE_BOND, - WRITE, - READ, - WRITE_DESCRIPTOR, - READ_DESCRIPTOR, - ENABLE_NOTIFICATIONS, - ENABLE_INDICATIONS, - READ_BATTERY_LEVEL, - ENABLE_BATTERY_LEVEL_NOTIFICATIONS, - DISABLE_BATTERY_LEVEL_NOTIFICATIONS, - ENABLE_SERVICE_CHANGED_INDICATIONS, - } - - private final Type type; - private final BluetoothGattCharacteristic characteristic; - private final BluetoothGattDescriptor descriptor; - private final byte[] value; - private final int writeType; - - private Request(final Type type) { - this.type = type; - this.characteristic = null; - this.descriptor = null; - this.value = null; - this.writeType = 0; - } - - private Request(final Type type, final BluetoothGattCharacteristic characteristic) { - this.type = type; - this.characteristic = characteristic; - this.descriptor = null; - this.value = null; - this.writeType = 0; - } - - private Request(final Type type, final BluetoothGattCharacteristic characteristic, final int writeType, final byte[] value, final int offset, final int length) { - this.type = type; - this.characteristic = characteristic; - this.descriptor = null; - this.value = copy(value, offset, length); - this.writeType = writeType; - } - - private Request(final Type type, final BluetoothGattDescriptor descriptor) { - this.type = type; - this.characteristic = null; - this.descriptor = descriptor; - this.value = null; - this.writeType = 0; - } - - private Request(final Type type, final BluetoothGattDescriptor descriptor, final byte[] value, final int offset, final int length) { - this.type = type; - this.characteristic = null; - this.descriptor = descriptor; - this.value = copy(value, offset, length); - this.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT; - } - - private static byte[] copy(final byte[] value, final int offset, final int length) { - if (value == null || offset > value.length) - return null; - final int maxLength = Math.min(value.length - offset, length); - final byte[] copy = new byte[maxLength]; - System.arraycopy(value, offset, copy, 0, maxLength); - return copy; - } - - /** - * Creates a new request that will start pairing with the device. - * @return the new request that can be enqueued using {@link #enqueue(Request)} method. - */ - public static Request createBond() { - return new Request(Type.CREATE_BOND); - } - - /** - * Creates new Read Characteristic request. The request will not be executed if given characteristic - * is null or does not have READ property. After the operation is complete a proper callback will be invoked. - * @param characteristic characteristic to be read - * @return the new request that can be enqueued using {@link #enqueue(Request)} method. - */ - public static Request newReadRequest(final BluetoothGattCharacteristic characteristic) { - return new Request(Type.READ, characteristic); - } - - /** - * Creates new Write Characteristic request. The request will not be executed if given characteristic - * is null or does not have WRITE property. After the operation is complete a proper callback will be invoked. - * @param characteristic characteristic to be written - * @param value value to be written. The array is copied into another buffer so it's safe to reuse the array again. - * @return the new request that can be enqueued using {@link #enqueue(Request)} method. - */ - public static Request newWriteRequest(final BluetoothGattCharacteristic characteristic, final byte[] value) { - return new Request(Type.WRITE, characteristic, characteristic.getWriteType(), value, 0, value != null ? value.length : 0); - } - - /** - * Creates new Write Characteristic request. The request will not be executed if given characteristic - * is null or does not have WRITE property. After the operation is complete a proper callback will be invoked. - * @param characteristic characteristic to be written - * @param value value to be written. The array is copied into another buffer so it's safe to reuse the array again. - * @param writeType write type to be used, one of {@link BluetoothGattCharacteristic#WRITE_TYPE_DEFAULT}, {@link BluetoothGattCharacteristic#WRITE_TYPE_NO_RESPONSE}. - * @return the new request that can be enqueued using {@link #enqueue(Request)} method. - */ - public static Request newWriteRequest(final BluetoothGattCharacteristic characteristic, final byte[] value, final int writeType) { - return new Request(Type.WRITE, characteristic, writeType, value, 0, value != null ? value.length : 0); - } - - /** - * Creates new Write Characteristic request. The request will not be executed if given characteristic - * is null or does not have WRITE property. After the operation is complete a proper callback will be invoked. - * @param characteristic characteristic to be written - * @param value value to be written. The array is copied into another buffer so it's safe to reuse the array again. - * @param offset the offset from which value has to be copied - * @param length number of bytes to be copied from the value buffer - * @return the new request that can be enqueued using {@link #enqueue(Request)} method. - */ - public static Request newWriteRequest(final BluetoothGattCharacteristic characteristic, final byte[] value, final int offset, final int length) { - return new Request(Type.WRITE, characteristic, characteristic.getWriteType(), value, offset, length); - } - - /** - * Creates new Write Characteristic request. The request will not be executed if given characteristic - * is null or does not have WRITE property. After the operation is complete a proper callback will be invoked. - * @param characteristic characteristic to be written - * @param value value to be written. The array is copied into another buffer so it's safe to reuse the array again. - * @param offset the offset from which value has to be copied - * @param length number of bytes to be copied from the value buffer - * @param writeType write type to be used, one of {@link BluetoothGattCharacteristic#WRITE_TYPE_DEFAULT}, {@link BluetoothGattCharacteristic#WRITE_TYPE_NO_RESPONSE}. - * @return the new request that can be enqueued using {@link #enqueue(Request)} method. - */ - public static Request newWriteRequest(final BluetoothGattCharacteristic characteristic, final byte[] value, final int offset, final int length, final int writeType) { - return new Request(Type.WRITE, characteristic, writeType, value, offset, length); - } - - /** - * Creates new Read Descriptor request. The request will not be executed if given descriptor - * is null. After the operation is complete a proper callback will be invoked. - * @param descriptor descriptor to be read - * @return the new request that can be enqueued using {@link #enqueue(Request)} method. - */ - public static Request newReadRequest(final BluetoothGattDescriptor descriptor) { - return new Request(Type.READ_DESCRIPTOR, descriptor); - } - - /** - * Creates new Write Descriptor request. The request will not be executed if given descriptor - * is null. After the operation is complete a proper callback will be invoked. - * @param descriptor descriptor to be written - * @param value value to be written. The array is copied into another buffer so it's safe to reuse the array again. - * @return the new request that can be enqueued using {@link #enqueue(Request)} method. - */ - public static Request newWriteRequest(final BluetoothGattDescriptor descriptor, final byte[] value) { - return new Request(Type.WRITE_DESCRIPTOR, descriptor, value, 0, value != null ? value.length : 0); - } - - /** - * Creates new Write Descriptor request. The request will not be executed if given descriptor - * is null. After the operation is complete a proper callback will be invoked. - * @param descriptor descriptor to be written - * @param value value to be written. The array is copied into another buffer so it's safe to reuse the array again. - * @param offset the offset from which value has to be copied - * @param length number of bytes to be copied from the value buffer - * @return the new request that can be enqueued using {@link #enqueue(Request)} method. - */ - public static Request newWriteRequest(final BluetoothGattDescriptor descriptor, final byte[] value, final int offset, final int length) { - return new Request(Type.WRITE_DESCRIPTOR, descriptor, value, offset, length); - } - - /** - * Creates new Enable Notification request. The request will not be executed if given characteristic - * is null, does not have NOTIFY property or the CCCD. After the operation is complete a proper callback will be invoked. - * @param characteristic characteristic to have notifications enabled - * @return the new request that can be enqueued using {@link #enqueue(Request)} method. - */ - public static Request newEnableNotificationsRequest(final BluetoothGattCharacteristic characteristic) { - return new Request(Type.ENABLE_NOTIFICATIONS, characteristic); - } - - /** - * Creates new Enable Indications request. The request will not be executed if given characteristic - * is null, does not have INDICATE property or the CCCD. After the operation is complete a proper callback will be invoked. - * @param characteristic characteristic to have indications enabled - * @return the new request that can be enqueued using {@link #enqueue(Request)} method. - */ - public static Request newEnableIndicationsRequest(final BluetoothGattCharacteristic characteristic) { - return new Request(Type.ENABLE_INDICATIONS, characteristic); - } - - /** - * Reads the first found Battery Level characteristic value from the first found Battery Service. - * If any of them is not found, or the characteristic does not have the READ property this operation will not execute. - * @return the new request that can be enqueued using {@link #enqueue(Request)} method. - */ - public static Request newReadBatteryLevelRequest() { - return new Request(Type.READ_BATTERY_LEVEL); // the first Battery Level char from the first Battery Service is used - } - - /** - * Enables notifications on the first found Battery Level characteristic from the first found Battery Service. - * If any of them is not found, or the characteristic does not have the NOTIFY property this operation will not execute. - * @return the new request that can be enqueued using {@link #enqueue(Request)} method. - */ - public static Request newEnableBatteryLevelNotificationsRequest() { - return new Request(Type.ENABLE_BATTERY_LEVEL_NOTIFICATIONS); // the first Battery Level char from the first Battery Service is used - } - - /** - * Disables notifications on the first found Battery Level characteristic from the first found Battery Service. - * If any of them is not found, or the characteristic does not have the NOTIFY property this operation will not execute. - * @return the new request that can be enqueued using {@link #enqueue(Request)} method. - */ - public static Request newDisableBatteryLevelNotificationsRequest() { - return new Request(Type.DISABLE_BATTERY_LEVEL_NOTIFICATIONS); // the first Battery Level char from the first Battery Service is used - } - - /** - * Enables indications on Service Changed characteristic if such exists in the Generic Attribute service. - * It is required to enable those notifications on bonded devices on older Android versions to be - * informed about attributes changes. Android 7+ (or 6+) handles this automatically and no action is required. - * @return the new request that can be enqueued using {@link #enqueue(Request)} method. - */ - private static Request newEnableServiceChangedIndicationsRequest() { - return new Request(Type.ENABLE_SERVICE_CHANGED_INDICATIONS); // the only Service Changed char is used (if such exists) - } - } - - protected abstract class BleManagerGattCallback extends BluetoothGattCallback { - private final static String ERROR_CONNECTION_STATE_CHANGE = "Error on connection state change"; - private final static String ERROR_DISCOVERY_SERVICE = "Error on discovering services"; - private final static String ERROR_AUTH_ERROR_WHILE_BONDED = "Phone has lost bonding information"; - private final static String ERROR_READ_CHARACTERISTIC = "Error on reading characteristic"; - private final static String ERROR_WRITE_CHARACTERISTIC = "Error on writing characteristic"; - private final static String ERROR_READ_DESCRIPTOR = "Error on reading descriptor"; - private final static String ERROR_WRITE_DESCRIPTOR = "Error on writing descriptor"; - - private final Queue mTaskQueue = new LinkedList<>(); - private Deque mInitQueue; - private boolean mInitInProgress; - private boolean mOperationInProgress = true; // Initially true to block operations before services are discovered. - - /** - * This method should return true when the gatt device supports the required services. - * - * @param gatt the gatt device with services discovered - * @return true when the device has teh required service - */ - protected abstract boolean isRequiredServiceSupported(final BluetoothGatt gatt); - - /** - * This method should return true when the gatt device supports the optional services. - * The default implementation returns false. - * - * @param gatt the gatt device with services discovered - * @return true when the device has teh optional service - */ - protected boolean isOptionalServiceSupported(final BluetoothGatt gatt) { - return false; - } - - /** - * This method should return a list of requests needed to initialize the profile. - * Enabling Service Change indications for bonded devices and reading the Battery Level value and enabling Battery Level notifications - * is handled before executing this queue. The queue should not have requests that are not available, e.g. should not - * read an optional service when it is not supported by the connected device. - *

This method is called when the services has been discovered and the device is supported (has required service).

- * - * @param gatt the gatt device with services discovered - * @return the queue of requests - */ - protected abstract Deque initGatt(final BluetoothGatt gatt); - - /** - * Called then the initialization queue is complete. - */ - protected void onDeviceReady() { - mCallbacks.onDeviceReady(mBluetoothGatt.getDevice()); - } - - /** - * This method should nullify all services and characteristics of the device. - * It's called when the device is no longer connected, either due to user action - * or a link loss. - */ - 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. - * - * @param gatt GATT client - * @param characteristic Characteristic that was read from the associated remote device. - */ - protected void onCharacteristicRead(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { - // do nothing - } - - /** - * Callback indicating the result of a characteristic write operation. - *

If this callback is invoked while a reliable write transaction is - * in progress, the value of the characteristic represents the value - * reported by the remote device. An application should compare this - * value to the desired value to be written. If the values don't match, - * the application must abort the reliable write transaction. - * - * @param gatt GATT client - * @param characteristic Characteristic that was written to the associated remote device. - */ - protected void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { - // do nothing - } - - /** - * Callback reporting the result of a descriptor read operation. - * - * @param gatt GATT client - * @param descriptor Descriptor that was read from the associated remote device. - */ - protected void onDescriptorRead(final BluetoothGatt gatt, final BluetoothGattDescriptor descriptor) { - // do nothing - } - - /** - * Callback indicating the result of a descriptor write operation. - *

If this callback is invoked while a reliable write transaction is in progress, - * the value of the characteristic represents the value reported by the remote device. - * An application should compare this value to the desired value to be written. - * If the values don't match, the application must abort the reliable write transaction. - * - * @param gatt GATT client - * @param descriptor Descriptor that was written to the associated remote device. - */ - protected void onDescriptorWrite(final BluetoothGatt gatt, final BluetoothGattDescriptor descriptor) { - // do nothing - } - - /** - * Callback reporting the value of Battery Level characteristic which could have - * been received by Read or Notify operations. - * - * @param gatt GATT client - * @param value the battery value in percent - */ - protected void onBatteryValueReceived(final BluetoothGatt gatt, final int value) { - // do nothing - } - - /** - * Callback indicating a notification has been received. - * @param gatt GATT client - * @param characteristic Characteristic from which the notification came. - */ - protected void onCharacteristicNotified(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { - // do nothing - } - - /** - * Callback indicating an indication has been received. - * @param gatt GATT client - * @param characteristic Characteristic from which the indication came. - */ - protected void onCharacteristicIndicated(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { - // do nothing - } - - private void onError(final BluetoothDevice device, final String message, final int errorCode) { - Logger.e(mLogSession, "Error (0x" + Integer.toHexString(errorCode) + "): " + GattError.parse(errorCode)); - mCallbacks.onError(device, message, errorCode); - } - - @Override - public final void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) { - Logger.d(mLogSession, "[Callback] Connection state changed with status: " + status + " and new state: " + newState + " (" + stateToString(newState) + ")"); - - if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) { - // Notify the parent activity/service - Logger.i(mLogSession, "Connected to " + gatt.getDevice().getAddress()); - mConnected = true; - mConnectionState = BluetoothGatt.STATE_CONNECTED; - mCallbacks.onDeviceConnected(gatt.getDevice()); - - /* - * The onConnectionStateChange event is triggered just after the Android connects to a device. - * In case of bonded devices, the encryption is reestablished AFTER this callback is called. - * Moreover, when the device has Service Changed indication enabled, and the list of services has changed (e.g. using the DFU), - * the indication is received few hundred milliseconds later, depending on the connection interval. - * When received, Android will start performing a service discovery operation on its own, internally, - * and will NOT notify the app that services has changed. - * - * If the gatt.discoverServices() method would be invoked here with no delay, if would return cached services, - * as the SC indication wouldn't be received yet. - * Therefore we have to postpone the service discovery operation until we are (almost, as there is no such callback) sure, - * that it has been handled. - * TODO: Please calculate the proper delay that will work in your solution. - * It should be greater than the time from LLCP Feature Exchange to ATT Write for Service Change indication. - * If your device does not use Service Change indication (for example does not have DFU) the delay may be 0. - */ - final boolean bonded = gatt.getDevice().getBondState() == BluetoothDevice.BOND_BONDED; - final int delay = bonded ? 1600 : 0; // around 1600 ms is required when connection interval is ~45ms. - if (delay > 0) - Logger.d(mLogSession, "wait(" + delay + ")"); - mHandler.postDelayed(() -> { - // Some proximity tags (e.g. nRF PROXIMITY) initialize bonding automatically when connected. - if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_BONDING) { - Logger.v(mLogSession, "Discovering Services..."); - Logger.d(mLogSession, "gatt.discoverServices()"); - gatt.discoverServices(); - } - }, delay); - } else { - if (newState == BluetoothProfile.STATE_DISCONNECTED) { - if (status != BluetoothGatt.GATT_SUCCESS) - Logger.w(mLogSession, "Error: (0x" + Integer.toHexString(status) + "): " + GattError.parseConnectionError(status)); - - mOperationInProgress = true; // no more calls are possible - mInitQueue = null; - mTaskQueue.clear(); - final boolean wasConnected = mConnected; - // if (mConnected) { // Checking mConnected prevents from calling onDeviceDisconnected if connection attempt failed. This check is not necessary - notifyDeviceDisconnected(gatt.getDevice()); // This sets the mConnected flag to false - // } - // Try to reconnect if the initial connection was lost because of a link loss or timeout, and shouldAutoConnect() returned true during connection attempt. - // This time it will set the autoConnect flag to true (gatt.connect() forces autoConnect true) - if (mInitialConnection) { - connect(gatt.getDevice()); - } - - if (wasConnected || status == BluetoothGatt.GATT_SUCCESS) - return; - } else { - if (status != BluetoothGatt.GATT_SUCCESS) - Logger.e(mLogSession, "Error (0x" + Integer.toHexString(status) + "): " + GattError.parseConnectionError(status)); - } - mCallbacks.onError(gatt.getDevice(), ERROR_CONNECTION_STATE_CHANGE, status); - } - } - - @Override - public final void onServicesDiscovered(final BluetoothGatt gatt, final int status) { - if (status == BluetoothGatt.GATT_SUCCESS) { - Logger.i(mLogSession, "Services Discovered"); - if (isRequiredServiceSupported(gatt)) { - Logger.v(mLogSession, "Primary service found"); - final boolean optionalServicesFound = isOptionalServiceSupported(gatt); - if (optionalServicesFound) - Logger.v(mLogSession, "Secondary service found"); - - // Notify the parent activity - mCallbacks.onServicesDiscovered(gatt.getDevice(), optionalServicesFound); - - // Obtain the queue of initialization requests - mInitInProgress = true; - mInitQueue = initGatt(gatt); - - // Before we start executing the initialization queue some other tasks need to be done. - if (mInitQueue == null) - mInitQueue = new LinkedList<>(); - - // Note, that operations are added in reverse order to the front of the queue. - - // 3. Enable Battery Level notifications if required (if this char. does not exist, this operation will be skipped) - if (mCallbacks.shouldEnableBatteryLevelNotifications(gatt.getDevice())) - mInitQueue.addFirst(Request.newEnableBatteryLevelNotificationsRequest()); - // 2. Read Battery Level characteristic (if such does not exist, this will be skipped) - mInitQueue.addFirst(Request.newReadBatteryLevelRequest()); - // 1. On devices running Android 4.3-6.0 the Service Changed characteristic needs to be enabled by the app (for bonded devices) - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) - mInitQueue.addFirst(Request.newEnableServiceChangedIndicationsRequest()); - - mOperationInProgress = false; - nextRequest(); - } else { - Logger.w(mLogSession, "Device is not supported"); - mCallbacks.onDeviceNotSupported(gatt.getDevice()); - disconnect(); - } - } else { - DebugLogger.e(TAG, "onServicesDiscovered error " + status); - onError(gatt.getDevice(), ERROR_DISCOVERY_SERVICE, status); - } - } - - @Override - public final void onCharacteristicRead(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) { - if (status == BluetoothGatt.GATT_SUCCESS) { - Logger.i(mLogSession, "Read Response received from " + characteristic.getUuid() + ", value: " + ParserUtils.parse(characteristic)); - - if (isBatteryLevelCharacteristic(characteristic)) { - final int batteryValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0); - Logger.a(mLogSession, "Battery level received: " + batteryValue + "%"); - mBatteryValue = batteryValue; - onBatteryValueReceived(gatt, batteryValue); - mCallbacks.onBatteryValueReceived(gatt.getDevice(), batteryValue); - } else { - // The value has been read. Notify the manager and proceed with the initialization queue. - onCharacteristicRead(gatt, characteristic); - } - } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { - if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) { - // This should never happen but it used to: http://stackoverflow.com/a/20093695/2115352 - DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED); - mCallbacks.onError(gatt.getDevice(), ERROR_AUTH_ERROR_WHILE_BONDED, status); - } - } else { - DebugLogger.e(TAG, "onCharacteristicRead error " + status); - onError(gatt.getDevice(), ERROR_READ_CHARACTERISTIC, status); - } - mOperationInProgress = false; - nextRequest(); - } - - @Override - public final void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) { - if (status == BluetoothGatt.GATT_SUCCESS) { - Logger.i(mLogSession, "Data written to " + characteristic.getUuid() + ", value: " + ParserUtils.parse(characteristic)); - // The value has been written. Notify the manager and proceed with the initialization queue. - onCharacteristicWrite(gatt, characteristic); - } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { - if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) { - // This should never happen but it used to: http://stackoverflow.com/a/20093695/2115352 - DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED); - mCallbacks.onError(gatt.getDevice(), ERROR_AUTH_ERROR_WHILE_BONDED, status); - } - } else { - DebugLogger.e(TAG, "onCharacteristicWrite error " + status); - onError(gatt.getDevice(), ERROR_WRITE_CHARACTERISTIC, status); - } - mOperationInProgress = false; - nextRequest(); - } - - @Override - public void onDescriptorRead(final BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) { - if (status == BluetoothGatt.GATT_SUCCESS) { - Logger.i(mLogSession, "Read Response received from descr. " + descriptor.getUuid() + ", value: " + ParserUtils.parse(descriptor)); - - // The value has been read. Notify the manager and proceed with the initialization queue. - onDescriptorRead(gatt, descriptor); - } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { - if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) { - // This should never happen but it used to: http://stackoverflow.com/a/20093695/2115352 - DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED); - mCallbacks.onError(gatt.getDevice(), ERROR_AUTH_ERROR_WHILE_BONDED, status); - } - } else { - DebugLogger.e(TAG, "onDescriptorRead error " + status); - onError(gatt.getDevice(), ERROR_READ_DESCRIPTOR, status); - } - mOperationInProgress = false; - nextRequest(); - } - - @Override - public final void onDescriptorWrite(final BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) { - if (status == BluetoothGatt.GATT_SUCCESS) { - Logger.i(mLogSession, "Data written to descr. " + descriptor.getUuid() + ", value: " + ParserUtils.parse(descriptor)); - - if (isServiceChangedCCCD(descriptor)) { - Logger.a(mLogSession, "Service Changed notifications enabled"); - } else if (isBatteryLevelCCCD(descriptor)) { - final byte[] value = descriptor.getValue(); - if (value != null && value.length == 2 && value[1] == 0x00) { - if (value[0] == 0x01) { - Logger.a(mLogSession, "Battery Level notifications enabled"); - } else { - Logger.a(mLogSession, "Battery Level notifications disabled"); - } - } else { - onDescriptorWrite(gatt, descriptor); - } - } else if (isCCCD(descriptor)) { - final byte[] value = descriptor.getValue(); - if (value != null && value.length == 2 && value[1] == 0x00) { - switch (value[0]) { - case 0x00: - Logger.a(mLogSession, "Notifications and indications disabled"); - break; - case 0x01: - Logger.a(mLogSession, "Notifications enabled"); - break; - case 0x02: - Logger.a(mLogSession, "Indications enabled"); - break; - } - } else { - onDescriptorWrite(gatt, descriptor); - } - } else { - onDescriptorWrite(gatt, descriptor); - } - } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { - if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) { - // This should never happen but it used to: http://stackoverflow.com/a/20093695/2115352 - DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED); - mCallbacks.onError(gatt.getDevice(), ERROR_AUTH_ERROR_WHILE_BONDED, status); - } - } else { - DebugLogger.e(TAG, "onDescriptorWrite error " + status); - onError(gatt.getDevice(), ERROR_WRITE_DESCRIPTOR, status); - } - mOperationInProgress = false; - nextRequest(); - } - - @Override - public final void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { - final String data = ParserUtils.parse(characteristic); - - if (isBatteryLevelCharacteristic(characteristic)) { - Logger.i(mLogSession, "Notification received from " + characteristic.getUuid() + ", value: " + data); - final int batteryValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0); - Logger.a(mLogSession, "Battery level received: " + batteryValue + "%"); - mBatteryValue = batteryValue; - onBatteryValueReceived(gatt, batteryValue); - mCallbacks.onBatteryValueReceived(gatt.getDevice(), batteryValue); - } else { - final BluetoothGattDescriptor cccd = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); - final boolean notifications = cccd == null || cccd.getValue() == null || cccd.getValue().length != 2 || cccd.getValue()[0] == 0x01; - - if (notifications) { - Logger.i(mLogSession, "Notification received from " + characteristic.getUuid() + ", value: " + data); - onCharacteristicNotified(gatt, characteristic); - } else { // indications - Logger.i(mLogSession, "Indication received from " + characteristic.getUuid() + ", value: " + data); - onCharacteristicIndicated(gatt, characteristic); - } - } - } - - /** - * Executes the next request. If the last element from the initialization queue has been executed - * the {@link #onDeviceReady()} callback is called. - */ - private void nextRequest() { - if (mOperationInProgress) - return; - - // Get the first request from the init queue - Request request = mInitQueue != null ? mInitQueue.poll() : null; - - // Are we done with initializing? - if (request == null) { - if (mInitInProgress) { - mInitQueue = null; // release the queue - mInitInProgress = false; - onDeviceReady(); - } - // If so, we can continue with the task queue - request = mTaskQueue.poll(); - if (request == null) { - // Nothing to be done for now - return; - } - } - - mOperationInProgress = true; - boolean result = false; - switch (request.type) { - case CREATE_BOND: { - result = internalCreateBond(); - break; - } - case READ: { - result = internalReadCharacteristic(request.characteristic); - break; - } - case WRITE: { - final BluetoothGattCharacteristic characteristic = request.characteristic; - characteristic.setValue(request.value); - characteristic.setWriteType(request.writeType); - result = internalWriteCharacteristic(characteristic); - break; - } - case READ_DESCRIPTOR: { - result = internalReadDescriptor(request.descriptor); - break; - } - case WRITE_DESCRIPTOR: { - final BluetoothGattDescriptor descriptor = request.descriptor; - descriptor.setValue(request.value); - result = internalWriteDescriptor(descriptor); - break; - } - case ENABLE_NOTIFICATIONS: { - result = internalEnableNotifications(request.characteristic); - break; - } - case ENABLE_INDICATIONS: { - result = internalEnableIndications(request.characteristic); - break; - } - case READ_BATTERY_LEVEL: { - result = internalReadBatteryLevel(); - break; - } - case ENABLE_BATTERY_LEVEL_NOTIFICATIONS: { - result = internalSetBatteryNotifications(true); - break; - } - case DISABLE_BATTERY_LEVEL_NOTIFICATIONS: { - result = internalSetBatteryNotifications(false); - break; - } - case ENABLE_SERVICE_CHANGED_INDICATIONS: { - result = ensureServiceChangedEnabled(); - break; - } - } - // The result may be false if given characteristic or descriptor were not found on the device. - // In that case, proceed with next operation and ignore the one that failed. - if (!result) { - mOperationInProgress = false; - nextRequest(); - } - } - - /** - * Returns true if this descriptor is from the Service Changed characteristic. - * - * @param descriptor the descriptor to be checked - * @return true if the descriptor belongs to the Service Changed characteristic - */ - private boolean isServiceChangedCCCD(final BluetoothGattDescriptor descriptor) { - if (descriptor == null) - return false; - - return SERVICE_CHANGED_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid()); - } - - /** - * Returns true if the characteristic is the Battery Level characteristic. - * - * @param characteristic the characteristic to be checked - * @return true if the characteristic is the Battery Level characteristic. - */ - private boolean isBatteryLevelCharacteristic(final BluetoothGattCharacteristic characteristic) { - if (characteristic == null) - return false; - - return BATTERY_LEVEL_CHARACTERISTIC.equals(characteristic.getUuid()); - } - - /** - * Returns true if this descriptor is from the Battery Level characteristic. - * - * @param descriptor the descriptor to be checked - * @return true if the descriptor belongs to the Battery Level characteristic - */ - private boolean isBatteryLevelCCCD(final BluetoothGattDescriptor descriptor) { - if (descriptor == null) - return false; - - return BATTERY_LEVEL_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid()); - } - - /** - * Returns true if this descriptor is a Client Characteristic Configuration descriptor (CCCD). - * - * @param descriptor the descriptor to be checked - * @return true if the descriptor is a CCCD - */ - private boolean isCCCD(final BluetoothGattDescriptor descriptor) { - if (descriptor == null) - return false; - - return CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID.equals(descriptor.getUuid()); - } - } - - private static final int PAIRING_VARIANT_PIN = 0; - private static final int PAIRING_VARIANT_PASSKEY = 1; - private static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2; - private static final int PAIRING_VARIANT_CONSENT = 3; - private static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4; - private static final int PAIRING_VARIANT_DISPLAY_PIN = 5; - private static final int PAIRING_VARIANT_OOB_CONSENT = 6; - - protected String pairingVariantToString(final int variant) { - switch (variant) { - case PAIRING_VARIANT_PIN: - return "PAIRING_VARIANT_PIN"; - case PAIRING_VARIANT_PASSKEY: - return "PAIRING_VARIANT_PASSKEY"; - case PAIRING_VARIANT_PASSKEY_CONFIRMATION: - return "PAIRING_VARIANT_PASSKEY_CONFIRMATION"; - case PAIRING_VARIANT_CONSENT: - return "PAIRING_VARIANT_CONSENT"; - case PAIRING_VARIANT_DISPLAY_PASSKEY: - return "PAIRING_VARIANT_DISPLAY_PASSKEY"; - case PAIRING_VARIANT_DISPLAY_PIN: - return "PAIRING_VARIANT_DISPLAY_PIN"; - case PAIRING_VARIANT_OOB_CONSENT: - return "PAIRING_VARIANT_OOB_CONSENT"; - default: - return "UNKNOWN"; - } - } - - protected String bondStateToString(final int state) { - switch (state) { - case BluetoothDevice.BOND_NONE: - return "BOND_NONE"; - case BluetoothDevice.BOND_BONDING: - return "BOND_BONDING"; - case BluetoothDevice.BOND_BONDED: - return "BOND_BONDED"; - default: - return "UNKNOWN"; - } - } - - protected String getWriteType(final int type) { - switch (type) { - case BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT: - return "WRITE REQUEST"; - case BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE: - return "WRITE COMMAND"; - case BluetoothGattCharacteristic.WRITE_TYPE_SIGNED: - return "WRITE SIGNED"; - default: - return "UNKNOWN: " + type; - } - } - - /** - * Converts the connection state to String value - * @param state the connection state - * @return state as String - */ - protected String stateToString(final int state) { - switch (state) { - case BluetoothProfile.STATE_CONNECTED: - return "CONNECTED"; - case BluetoothProfile.STATE_CONNECTING: - return "CONNECTING"; - case BluetoothProfile.STATE_DISCONNECTING: - return "DISCONNECTING"; - default: - return "DISCONNECTED"; - } - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManagerCallbacks.java deleted file mode 100644 index ea67f998..00000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManagerCallbacks.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2015, Nordic Semiconductor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package no.nordicsemi.android.nrftoolbox.profile; - -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothGatt; -import android.bluetooth.BluetoothGattCallback; - -/** - * DO NOT EDIT THIS FILE UNLESS NECESSARY! - * The BleManagerCallbacks should be overridden in your app and all the 'high level' callbacks should be added there. - * Keeping this file as is (and {@link BleManager} as well) will allow to quickly update it when an update is posted here. - * @see no.nordicsemi.android.nrftoolbox.rsc.RSCManagerCallbacks - */ -public interface BleManagerCallbacks { - - /** - * Called when the Android device started connecting to given device. - * The {@link #onDeviceConnected(BluetoothDevice)} will be called when the device is connected, - * or {@link #onError(BluetoothDevice, String, int)} in case of error. - * @param device the device that got connected - */ - void onDeviceConnecting(final BluetoothDevice device); - - /** - * Called when the device has been connected. This does not mean that the application may start communication. - * A service discovery will be handled automatically after this call. Service discovery - * may ends up with calling {@link #onServicesDiscovered(BluetoothDevice, boolean)} or - * {@link #onDeviceNotSupported(BluetoothDevice)} if required services have not been found. - * @param device the device that got connected - */ - void onDeviceConnected(final BluetoothDevice device); - - /** - * Called when user initialized disconnection. - * @param device the device that gets disconnecting - */ - void onDeviceDisconnecting(final BluetoothDevice device); - - /** - * Called when the device has disconnected (when the callback returned - * {@link BluetoothGattCallback#onConnectionStateChange(BluetoothGatt, int, int)} with state DISCONNECTED), - * but ONLY if the {@link BleManager#shouldAutoConnect()} method returned false for this device when it was connecting. - * Otherwise the {@link #onLinklossOccur(BluetoothDevice)} method will be called instead. - * @param device the device that got disconnected - */ - void onDeviceDisconnected(final BluetoothDevice device); - - /** - * This callback is invoked when the Ble Manager lost connection to a device that has been connected - * with autoConnect option (see {@link BleManager#shouldAutoConnect()}. - * Otherwise a {@link #onDeviceDisconnected(BluetoothDevice)} method will be called on such event. - * @param device the device that got disconnected due to a link loss - */ - void onLinklossOccur(final BluetoothDevice device); - - /** - * Called when service discovery has finished and primary services has been found. - * This method is not called if the primary, mandatory services were not found during service discovery. - * For example in the Blood Pressure Monitor, a Blood Pressure service is a primary service and - * Intermediate Cuff Pressure service is a optional secondary service. - * Existence of battery service is not notified by this call. - *

After successful service discovery the service will initialize all services. - * The {@link #onDeviceReady(BluetoothDevice)} method will be called when the initialization is complete.

- * - * @param device the device which services got disconnected - * @param optionalServicesFound - * if true the secondary services were also found on the device. - */ - void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound); - - /** - * Method called when all initialization requests has been completed. - * @param device the device that get ready - */ - void onDeviceReady(final BluetoothDevice device); - - /** - * This method should return true if Battery Level notifications should be enabled on the target device. - * If there is no Battery Service, or the Battery Level characteristic does not have NOTIFY property, - * this method will not be called for this device. - *

This method may return true only if an activity is bound to the service (to display the information - * to the user), always (e.g. if critical battery level is reported using notifications) or never, if - * such information is not important or the manager wants to control Battery Level notifications on its own.

- * @param device target device - * @return true to enabled battery level notifications after connecting to the device, false otherwise - */ - boolean shouldEnableBatteryLevelNotifications(final BluetoothDevice device); - - /** - * Called when battery value has been received from the device. - * - * @param value - * the battery value in percent - * @param device the device frm which the battery value has changed - */ - void onBatteryValueReceived(final BluetoothDevice device, final int value); - - /** - * Called when an {@link BluetoothGatt#GATT_INSUFFICIENT_AUTHENTICATION} error occurred and the device bond state is NOT_BONDED - * @param device the device that requires bonding - */ - void onBondingRequired(final BluetoothDevice device); - - /** - * Called when the device has been successfully bonded. - * @param device the device that got bonded - */ - void onBonded(final BluetoothDevice device); - - /** - * Called when a BLE error has occurred - * - * @param message - * the error message - * @param errorCode - * the error code - * @param device the device that caused an error - */ - void onError(final BluetoothDevice device, final String message, final int errorCode); - - /** - * Called when service discovery has finished but the main services were not found on the device. - * @param device the device that failed to connect due to lack of required services - */ - void onDeviceNotSupported(final BluetoothDevice device); -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileActivity.java index b1256c1f..01775706 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileActivity.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileActivity.java @@ -41,6 +41,8 @@ import android.widget.Toast; import java.util.UUID; +import no.nordicsemi.android.ble.BleManager; +import no.nordicsemi.android.ble.BleManagerCallbacks; import no.nordicsemi.android.log.ILogSession; import no.nordicsemi.android.log.LocalLogSession; import no.nordicsemi.android.log.Logger; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileExpandableListActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileExpandableListActivity.java index 01880610..f1bb65c2 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileExpandableListActivity.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileExpandableListActivity.java @@ -40,6 +40,8 @@ import android.widget.Toast; import java.util.UUID; +import no.nordicsemi.android.ble.BleManager; +import no.nordicsemi.android.ble.BleManagerCallbacks; import no.nordicsemi.android.log.ILogSession; import no.nordicsemi.android.log.LocalLogSession; import no.nordicsemi.android.log.Logger; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileService.java index a1aa5cd1..9cf3b1df 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileService.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileService.java @@ -38,6 +38,9 @@ import android.support.annotation.StringRes; import android.support.v4.content.LocalBroadcastManager; import android.widget.Toast; +import no.nordicsemi.android.ble.BleManager; +import no.nordicsemi.android.ble.BleManagerCallbacks; +import no.nordicsemi.android.ble.utils.ILogger; import no.nordicsemi.android.log.ILogSession; import no.nordicsemi.android.log.LogContract; import no.nordicsemi.android.log.Logger; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileServiceReadyActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileServiceReadyActivity.java index a8a4b136..83f9430b 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileServiceReadyActivity.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileServiceReadyActivity.java @@ -48,6 +48,7 @@ import android.widget.Toast; import java.util.UUID; +import no.nordicsemi.android.ble.BleManagerCallbacks; import no.nordicsemi.android.log.ILogSession; import no.nordicsemi.android.log.LocalLogSession; import no.nordicsemi.android.log.Logger; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/ILogger.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/ILogger.java deleted file mode 100644 index 1afce151..00000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/ILogger.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2016, Nordic Semiconductor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package no.nordicsemi.android.nrftoolbox.profile; - -import android.support.annotation.StringRes; - -public interface ILogger { - - /** - * Logs the given message with given log level into the all managed devices' log session. - * @param level the log level - * @param message the message to be logged - */ - void log(final int level, final String message); - - /** - * Logs the given message with given log level into the all managed devices' log session. - * @param level the log level - * @param messageRes string resource id - * @param params additional (optional) parameters used to fill the message - */ - void log(final int level, @StringRes final int messageRes, final Object... params); -} 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 bea13065..2578f825 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 @@ -41,11 +41,11 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; +import no.nordicsemi.android.ble.BleManager; +import no.nordicsemi.android.ble.BleManagerCallbacks; +import no.nordicsemi.android.ble.utils.ILogger; import no.nordicsemi.android.log.ILogSession; import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; -import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; -import no.nordicsemi.android.nrftoolbox.profile.ILogger; public abstract class BleMulticonnectProfileService extends Service implements BleManagerCallbacks { @SuppressWarnings("unused") diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/BleMulticonnectProfileServiceReadyActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/BleMulticonnectProfileServiceReadyActivity.java index 5a867a9f..7536104b 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/BleMulticonnectProfileServiceReadyActivity.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/BleMulticonnectProfileServiceReadyActivity.java @@ -48,13 +48,13 @@ import java.util.Collections; import java.util.List; import java.util.UUID; +import no.nordicsemi.android.ble.BleManagerCallbacks; import no.nordicsemi.android.log.ILogSession; import no.nordicsemi.android.log.LocalLogSession; import no.nordicsemi.android.log.LogContract; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.AppHelpFragment; import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; import no.nordicsemi.android.nrftoolbox.scanner.ScannerFragment; import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; 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 f5b983d2..67a16500 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 @@ -30,9 +30,9 @@ import java.util.Deque; import java.util.LinkedList; import java.util.UUID; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.parser.AlertLevelParser; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; public class ProximityManager extends BleManager { 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 4e310bd4..ce9d6e91 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,7 +21,7 @@ */ package no.nordicsemi.android.nrftoolbox.proximity; -import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; +import no.nordicsemi.android.ble.BleManagerCallbacks; public interface ProximityManagerCallbacks extends BleManagerCallbacks { // No additional methods 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 e629173a..e87085c5 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,7 +23,7 @@ package no.nordicsemi.android.nrftoolbox.proximity; import android.bluetooth.BluetoothDevice; -import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; +import no.nordicsemi.android.ble.BleManagerCallbacks; public interface ProximityServerManagerCallbacks extends BleManagerCallbacks { void onAlarmTriggered(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 b58c752f..bb20c4e0 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,9 @@ import android.media.AudioManager; import android.media.MediaPlayer; import android.media.RingtoneManager; import android.net.Uri; +import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationManagerCompat; import android.support.v4.content.ContextCompat; -import android.support.v4.app.NotificationCompat; import android.text.TextUtils; import android.util.Log; @@ -44,11 +44,11 @@ import java.io.IOException; import java.util.LinkedList; import java.util.List; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.LogContract; import no.nordicsemi.android.nrftoolbox.FeaturesActivity; import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; import no.nordicsemi.android.nrftoolbox.profile.multiconnect.BleMulticonnectProfileService; public class ProximityService extends BleMulticonnectProfileService implements ProximityManagerCallbacks, ProximityServerManagerCallbacks { diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManager.java index 3d1324d7..1e0ad854 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManager.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManager.java @@ -31,9 +31,9 @@ import java.util.Deque; import java.util.LinkedList; import java.util.UUID; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.parser.RSCMeasurementParser; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; public class RSCManager extends BleManager { private static final byte INSTANTANEOUS_STRIDE_LENGTH_PRESENT = 0x01; // 1 bit diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManagerCallbacks.java index 0e3c4b83..bafaba0e 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManagerCallbacks.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManagerCallbacks.java @@ -23,7 +23,7 @@ package no.nordicsemi.android.nrftoolbox.rsc; import android.bluetooth.BluetoothDevice; -import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; +import no.nordicsemi.android.ble.BleManagerCallbacks; public interface RSCManagerCallbacks extends BleManagerCallbacks { int NOT_AVAILABLE = -1; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCService.java index 6a06f445..9c65139d 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCService.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCService.java @@ -31,14 +31,14 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; -import android.support.v4.content.LocalBroadcastManager; import android.support.v4.app.NotificationCompat; +import android.support.v4.content.LocalBroadcastManager; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.FeaturesActivity; import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; public class RSCService extends BleProfileService implements RSCManagerCallbacks { diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/DeviceListAdapter.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/DeviceListAdapter.java index 2bd450f4..cae85725 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/DeviceListAdapter.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/DeviceListAdapter.java @@ -49,7 +49,7 @@ public class DeviceListAdapter extends BaseAdapter { private final ArrayList mListValues = new ArrayList<>(); private final Context mContext; - public DeviceListAdapter(Context context) { + public DeviceListAdapter(final Context context) { mContext = context; } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ScannerFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ScannerFragment.java index 8526ef4a..e8176857 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ScannerFragment.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ScannerFragment.java @@ -39,7 +39,6 @@ import android.support.v4.content.ContextCompat; import android.support.v7.app.AlertDialog; import android.view.LayoutInflater; import android.view.View; -import android.widget.AdapterView; import android.widget.Button; import android.widget.ListView; import android.widget.Toast; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManager.java index 44be2b94..050d0ef3 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManager.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManager.java @@ -30,9 +30,9 @@ import java.util.Deque; import java.util.LinkedList; import java.util.UUID; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.parser.TemplateParser; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; /** * Modify to template manager to match your requirements. diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManagerCallbacks.java index 11394464..fcbd285d 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManagerCallbacks.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManagerCallbacks.java @@ -23,7 +23,7 @@ package no.nordicsemi.android.nrftoolbox.template; import android.bluetooth.BluetoothDevice; -import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; +import no.nordicsemi.android.ble.BleManagerCallbacks; /** * Interface {@link TemplateManagerCallbacks} must be implemented by {@link TemplateActivity} in order to receive callbacks from {@link TemplateManager} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateService.java index 0fc3cb0a..a1781701 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateService.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateService.java @@ -30,14 +30,14 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.support.v4.content.LocalBroadcastManager; import android.support.v4.app.NotificationCompat; +import android.support.v4.content.LocalBroadcastManager; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.FeaturesActivity; import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; public class TemplateService extends BleProfileService implements TemplateManagerCallbacks { diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTActivity.java index f693c584..8223c2e4 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTActivity.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTActivity.java @@ -33,7 +33,6 @@ import android.app.PendingIntent; import android.bluetooth.BluetoothDevice; import android.content.ActivityNotFoundException; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; @@ -89,8 +88,8 @@ import java.util.UUID; import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; import no.nordicsemi.android.nrftoolbox.dfu.adapter.FileBrowserAppsAdapter; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity; import no.nordicsemi.android.nrftoolbox.uart.database.DatabaseHelper; import no.nordicsemi.android.nrftoolbox.uart.domain.Command; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTEditDialog.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTEditDialog.java index 709d985c..eafdf62e 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTEditDialog.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTEditDialog.java @@ -34,7 +34,6 @@ import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.CheckBox; -import android.widget.CompoundButton; import android.widget.EditText; import android.widget.GridView; import android.widget.ImageView; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogFragment.java index 3da184f6..a674634a 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogFragment.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogFragment.java @@ -36,7 +36,6 @@ import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.content.LocalBroadcastManager; -import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -46,7 +45,6 @@ import android.widget.Button; import android.widget.CursorAdapter; import android.widget.EditText; import android.widget.ListView; -import android.widget.TextView; import no.nordicsemi.android.log.ILogSession; import no.nordicsemi.android.log.LogContract; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManager.java index b5f60d95..26ac6be3 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManager.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManager.java @@ -33,8 +33,8 @@ import java.util.Deque; import java.util.LinkedList; import java.util.UUID; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; public class UARTManager extends BleManager { /** Nordic UART Service UUID */ diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManagerCallbacks.java index 6520d627..4a5bf249 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManagerCallbacks.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManagerCallbacks.java @@ -24,7 +24,7 @@ package no.nordicsemi.android.nrftoolbox.uart; import android.bluetooth.BluetoothDevice; -import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; +import no.nordicsemi.android.ble.BleManagerCallbacks; public interface UARTManagerCallbacks extends BleManagerCallbacks { diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTService.java index 07884bba..2d07af37 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTService.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTService.java @@ -31,8 +31,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.support.annotation.NonNull; -import android.support.v4.content.LocalBroadcastManager; import android.support.v4.app.NotificationCompat; +import android.support.v4.content.LocalBroadcastManager; import android.text.TextUtils; import android.util.Log; @@ -42,11 +42,11 @@ import com.google.android.gms.wearable.Node; import com.google.android.gms.wearable.NodeApi; import com.google.android.gms.wearable.Wearable; +import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.log.Logger; import no.nordicsemi.android.nrftoolbox.FeaturesActivity; import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.profile.BleManager; import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; import no.nordicsemi.android.nrftoolbox.wearable.common.Constants; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/wearable/UARTConfigurationSynchronizer.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/wearable/UARTConfigurationSynchronizer.java index 1bc5fe0a..696a0785 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/wearable/UARTConfigurationSynchronizer.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/wearable/UARTConfigurationSynchronizer.java @@ -35,9 +35,9 @@ import com.google.android.gms.wearable.Wearable; import java.util.ArrayList; -import no.nordicsemi.android.nrftoolbox.wearable.common.Constants; import no.nordicsemi.android.nrftoolbox.uart.domain.Command; import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration; +import no.nordicsemi.android.nrftoolbox.wearable.common.Constants; public class UARTConfigurationSynchronizer { private static final String WEAR_URI_PREFIX = "wear:"; // no / at the end as the path already has it diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/ParserUtils.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/ParserUtils.java index 461d9d1d..5e11b143 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/ParserUtils.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/ParserUtils.java @@ -22,35 +22,7 @@ package no.nordicsemi.android.nrftoolbox.utility; -import android.bluetooth.BluetoothGattCharacteristic; -import android.bluetooth.BluetoothGattDescriptor; - -public class ParserUtils { - final private static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); - - - public static String parse(final BluetoothGattCharacteristic characteristic) { - return parse(characteristic.getValue()); - } - - public static String parse(final BluetoothGattDescriptor descriptor) { - return parse(descriptor.getValue()); - } - - public static String parse(final byte[] data) { - if (data == null || data.length == 0) - return ""; - - final char[] out = new char[data.length * 3 - 1]; - for (int j = 0; j < data.length; j++) { - int v = data[j] & 0xFF; - out[j * 3] = HEX_ARRAY[v >>> 4]; - out[j * 3 + 1] = HEX_ARRAY[v & 0x0F]; - if (j != data.length - 1) - out[j * 3 + 2] = '-'; - } - return "(0x) " + new String(out); - } +public class ParserUtils extends no.nordicsemi.android.ble.utils.ParserUtils { public static String parseDebug(final byte[] data) { if (data == null || data.length == 0) diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/wearable/MainWearableListenerService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/wearable/MainWearableListenerService.java index a9d43335..30661f5f 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/wearable/MainWearableListenerService.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/wearable/MainWearableListenerService.java @@ -27,8 +27,8 @@ import android.content.Intent; import com.google.android.gms.wearable.MessageEvent; import com.google.android.gms.wearable.WearableListenerService; -import no.nordicsemi.android.nrftoolbox.wearable.common.Constants; import no.nordicsemi.android.nrftoolbox.uart.UARTService; +import no.nordicsemi.android.nrftoolbox.wearable.common.Constants; /** * The main listener for messages from Wearable devices. There may be only one such service per application so it has to handle messages from all profiles. diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/ClosableSpinner.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/ClosableSpinner.java index c03b4dd5..8f3967f4 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/ClosableSpinner.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/ClosableSpinner.java @@ -24,7 +24,6 @@ package no.nordicsemi.android.nrftoolbox.widget; import android.content.Context; import android.util.AttributeSet; -import android.widget.Spinner; public class ClosableSpinner extends android.support.v7.widget.AppCompatSpinner { public ClosableSpinner(Context context, AttributeSet attrs) { diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetBoldTextView.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetBoldTextView.java index 16f51465..22b40ba4 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetBoldTextView.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetBoldTextView.java @@ -24,7 +24,6 @@ package no.nordicsemi.android.nrftoolbox.widget; import android.content.Context; import android.graphics.Typeface; import android.util.AttributeSet; -import android.widget.TextView; import no.nordicsemi.android.nrftoolbox.R; diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetTextView.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetTextView.java index 94e39de4..db9363d0 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetTextView.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetTextView.java @@ -24,7 +24,6 @@ package no.nordicsemi.android.nrftoolbox.widget; import android.content.Context; import android.graphics.Typeface; import android.util.AttributeSet; -import android.widget.TextView; import no.nordicsemi.android.nrftoolbox.R; diff --git a/common/src/main/AndroidManifest.xml b/common/src/main/AndroidManifest.xml index 70ad70e0..8b31bd93 100644 --- a/common/src/main/AndroidManifest.xml +++ b/common/src/main/AndroidManifest.xml @@ -21,10 +21,6 @@ --> - - - diff --git a/common/src/main/java/no/nordicsemi/android/nrftoolbox/error/GattError.java b/common/src/main/java/no/nordicsemi/android/nrftoolbox/error/GattError.java deleted file mode 100644 index 61abd81e..00000000 --- a/common/src/main/java/no/nordicsemi/android/nrftoolbox/error/GattError.java +++ /dev/null @@ -1,150 +0,0 @@ -/************************************************************************************************************************************************* - * Copyright (c) 2015, Nordic Semiconductor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ************************************************************************************************************************************************/ - -package no.nordicsemi.android.nrftoolbox.error; - -import android.bluetooth.BluetoothGatt; - -/** - * Parses the error numbers according to the gatt_api.h file from bluedroid stack. - * See: https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.1.0_r1/stack/include/gatt_api.h (and other versions) for details. - */ -public class GattError { - - // Starts at line 106 of gatt_api.h file - /** - * Converts the connection status given by the {@link android.bluetooth.BluetoothGattCallback#onConnectionStateChange(BluetoothGatt, int, int)} to error name. - * @param error the status number - * @return the error name as stated in the gatt_api.h file - */ - public static String parseConnectionError(final int error) { - switch (error) { - case BluetoothGatt.GATT_SUCCESS: - return "SUCCESS"; - case 0x01: - return "GATT CONN L2C FAILURE"; - case 0x08: - return "GATT CONN TIMEOUT"; - case 0x13: - return "GATT CONN TERMINATE PEER USER"; - case 0x16: - return "GATT CONN TERMINATE LOCAL HOST"; - case 0x3E: - return "GATT CONN FAIL ESTABLISH"; - case 0x22: - return "GATT CONN LMP TIMEOUT"; - case 0x0100: - return "GATT CONN CANCEL "; - case 0x0085: - return "GATT ERROR"; // Device not reachable - default: - return "UNKNOWN (" + error + ")"; - } - } - - // Starts at line 29 of the gatt_api.h file - /** - * Converts the bluetooth communication status given by other BluetoothGattCallbacks to error name. It also parses the DFU errors. - * @param error the status number - * @return the error name as stated in the gatt_api.h file - */ - public static String parse(final int error) { - switch (error) { - case 0x0001: - return "GATT INVALID HANDLE"; - case 0x0002: - return "GATT READ NOT PERMIT"; - case 0x0003: - return "GATT WRITE NOT PERMIT"; - case 0x0004: - return "GATT INVALID PDU"; - case 0x0005: - return "GATT INSUF AUTHENTICATION"; - case 0x0006: - return "GATT REQ NOT SUPPORTED"; - case 0x0007: - return "GATT INVALID OFFSET"; - case 0x0008: - return "GATT INSUF AUTHORIZATION"; - case 0x0009: - return "GATT PREPARE Q FULL"; - case 0x000a: - return "GATT NOT FOUND"; - case 0x000b: - return "GATT NOT LONG"; - case 0x000c: - return "GATT INSUF KEY SIZE"; - case 0x000d: - return "GATT INVALID ATTR LEN"; - case 0x000e: - return "GATT ERR UNLIKELY"; - case 0x000f: - return "GATT INSUF ENCRYPTION"; - case 0x0010: - return "GATT UNSUPPORT GRP TYPE"; - case 0x0011: - return "GATT INSUF RESOURCE"; - case 0x0087: - return "GATT ILLEGAL PARAMETER"; - case 0x0080: - return "GATT NO RESOURCES"; - case 0x0081: - return "GATT INTERNAL ERROR"; - case 0x0082: - return "GATT WRONG STATE"; - case 0x0083: - return "GATT DB FULL"; - case 0x0084: - return "GATT BUSY"; - case 0x0085: - return "GATT ERROR"; - case 0x0086: - return "GATT CMD STARTED"; - case 0x0088: - return "GATT PENDING"; - case 0x0089: - return "GATT AUTH FAIL"; - case 0x008a: - return "GATT MORE"; - case 0x008b: - return "GATT INVALID CFG"; - case 0x008c: - return "GATT SERVICE STARTED"; - case 0x008d: - return "GATT ENCRYPTED NO MITM"; - case 0x008e: - return "GATT NOT ENCRYPTED"; - case 0x008f: - return "GATT CONGESTED"; - case 0x00FD: - return "GATT CCCD CFG ERROR"; - case 0x00FE: - return "GATT PROCEDURE IN PROGRESS"; - case 0x00FF: - return "GATT VALUE OUT OF RANGE"; - case 0x0101: - return "TOO MANY OPEN CONNECTIONS"; - default: - return "UNKNOWN (" + error + ")"; - } - } -} 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 61a329ba..696d35d6 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 @@ -35,6 +35,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Build; import android.os.Handler; +import android.support.annotation.RequiresApi; import java.util.Deque; import java.util.LinkedList; @@ -573,6 +574,34 @@ public class BleManager implements BleProfileApi { return result; } + @Override + public final boolean requestMtu(final int mtu) { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && enqueue(Request.newMtuRequest(mtu)); + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private boolean internalRequestMtu(final int mtu) { + final BluetoothGatt gatt = mBluetoothGatt; + if (gatt == null) + return false; + + return gatt.requestMtu(mtu); + } + + @Override + public final boolean requestConnectionPriority(final int priority) { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && enqueue(Request.newConnectionPriorityRequest(priority)); + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private boolean internalRequestConnectionPriority(final int priority) { + final BluetoothGatt gatt = mBluetoothGatt; + if (gatt == null) + return false; + + return gatt.requestConnectionPriority(priority); + } + @Override public boolean enqueue(final Request request) { if (mGattCallback != null) { @@ -592,11 +621,21 @@ public class BleManager implements BleProfileApi { private final static String ERROR_WRITE_CHARACTERISTIC = "Error on writing characteristic"; private final static String ERROR_READ_DESCRIPTOR = "Error on reading descriptor"; private final static String ERROR_WRITE_DESCRIPTOR = "Error on writing descriptor"; + private final static String ERROR_MTU_REQUEST = "Error on mtu request"; + private final static String ERROR_CONNECTION_PRIORITY_REQUEST = "Error on connection priority request"; private final Queue mTaskQueue = new LinkedList<>(); private Deque mInitQueue; private boolean mInitInProgress; private boolean mOperationInProgress = true; + /** + * This flag is required to resume operations after the connection priority request was made. + * It is used only on Android Oreo and newer, as only there there is onConnectionUpdated callback. + * However, as this callback is triggered every time the connection parameters change, even + * when such request wasn't made, this flag ensures the nextRequest() method won't be called + * during another operation. + */ + private boolean mConnectionPriorityOperationInProgress = false; private void notifyDeviceDisconnected(final BluetoothDevice device) { mConnected = false; @@ -814,6 +853,48 @@ public class BleManager implements BleProfileApi { } } + @Override + public void onMtuChanged(final BluetoothGatt gatt, final int mtu, final int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + mProfile.onMtuChanged(mtu); + } else { + DebugLogger.e(TAG, "onMtuChanged error: " + status + ", mtu: " + mtu); + onError(gatt.getDevice(), ERROR_MTU_REQUEST, status); + } + mOperationInProgress = false; + nextRequest(); + } + + // @Override + /** + * Callback indicating the connection parameters were updated. Works on Android 8+. + * + * @param gatt GATT client involved + * @param interval Connection interval used on this connection, 1.25ms unit. Valid range is from + * 6 (7.5ms) to 3200 (4000ms). + * @param latency Slave latency for the connection in number of connection events. Valid range + * is from 0 to 499 + * @param timeout Supervision timeout for this connection, in 10ms unit. Valid range is from 10 + * (0.1s) to 3200 (32s) + * @param status {@link BluetoothGatt#GATT_SUCCESS} if the connection has been updated + * successfully + */ + public void onConnectionUpdated(final BluetoothGatt gatt, final int interval, final int latency, final int timeout, final int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + mProfile.onConnectionUpdated(interval, latency, timeout); + } else if (status == 0x3b) { // HCI_ERR_UNACCEPT_CONN_INTERVAL + DebugLogger.e(TAG, "onConnectionUpdated received status: Unacceptable connection interval, interval: " + interval + ", latency: " + latency + ", timeout: " + timeout); + } else { + DebugLogger.e(TAG, "onConnectionUpdated received status: " + status + ", interval: " + interval + ", latency: " + latency + ", timeout: " + timeout); + mCallbacks.onError(gatt.getDevice(), ERROR_CONNECTION_PRIORITY_REQUEST, status); + } + if (mConnectionPriorityOperationInProgress) { + mConnectionPriorityOperationInProgress = false; + mOperationInProgress = false; + nextRequest(); + } + } + /** * Executes the next request. If the last element from the initialization queue has been executed * the {@link BleManagerCallbacks#onDeviceReady(BluetoothDevice)} callback is called. @@ -853,7 +934,7 @@ public class BleManager implements BleProfileApi { } case WRITE: { final BluetoothGattCharacteristic characteristic = request.characteristic; - characteristic.setValue(request.value); + characteristic.setValue(request.data); characteristic.setWriteType(request.writeType); result = internalWriteCharacteristic(characteristic); break; @@ -864,7 +945,7 @@ public class BleManager implements BleProfileApi { } case WRITE_DESCRIPTOR: { final BluetoothGattDescriptor descriptor = request.descriptor; - descriptor.setValue(request.value); + descriptor.setValue(request.data); result = internalWriteDescriptor(descriptor); break; } @@ -892,10 +973,32 @@ public class BleManager implements BleProfileApi { result = ensureServiceChangedEnabled(); break; } + case REQUEST_MTU: { + result = internalRequestMtu(request.value); + break; + } + case REQUEST_CONNECTION_PRIORITY: { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + mConnectionPriorityOperationInProgress = true; + result = internalRequestConnectionPriority(request.value); + } else { + result = internalRequestConnectionPriority(request.value); + // There is no callback for requestConnectionPriority(...) before Android Oreo.\ + // Let's give it some time to finish as the request is an asynchronous operation. + if (result) { + mHandler.postDelayed(() -> { + mOperationInProgress = false; + nextRequest(); + }, 100); + } + } + break; + } } // The result may be false if given characteristic or descriptor were not found on the device. // In that case, proceed with next operation and ignore the one that failed. if (!result) { + mConnectionPriorityOperationInProgress = false; mOperationInProgress = false; nextRequest(); } diff --git a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfile.java b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfile.java index 379e7aab..5938c535 100644 --- a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfile.java +++ b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfile.java @@ -22,10 +22,12 @@ package no.nordicsemi.android.nrftoolbox.ble; +import android.annotation.TargetApi; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.content.Context; +import android.os.Build; import java.util.Deque; @@ -147,6 +149,30 @@ public abstract class BleProfile { // do nothing } + /** + * Method called when the MTU request has finished with success. The MTU value may + * be different than requested one. + * @param mtu the new MTU (Maximum Transfer Unit) + */ + protected void onMtuChanged(final int mtu) { + // do nothing + } + + /** + * Callback indicating the connection parameters were updated. Works on Android 8+. + * + * @param interval Connection interval used on this connection, 1.25ms unit. Valid range is from + * 6 (7.5ms) to 3200 (4000ms). + * @param latency Slave latency for the connection in number of connection events. Valid range + * is from 0 to 499 + * @param timeout Supervision timeout for this connection, in 10ms unit. Valid range is from 10 + * (0.1s) to 3200 (32s) + */ + @TargetApi(Build.VERSION_CODES.O) + protected void onConnectionUpdated(final int interval, final int latency, final int timeout) { + // do nothing + } + /** * Called when a BLE error has occurred * @param message the error message diff --git a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfileApi.java b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfileApi.java index 96492e22..3a87c8f6 100644 --- a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfileApi.java +++ b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfileApi.java @@ -22,6 +22,7 @@ package no.nordicsemi.android.nrftoolbox.ble; +import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.content.Context; @@ -48,52 +49,69 @@ public interface BleProfileApi { ENABLE_BATTERY_LEVEL_NOTIFICATIONS, DISABLE_BATTERY_LEVEL_NOTIFICATIONS, ENABLE_SERVICE_CHANGED_INDICATIONS, + REQUEST_MTU, + REQUEST_CONNECTION_PRIORITY, } final Type type; final BluetoothGattCharacteristic characteristic; final BluetoothGattDescriptor descriptor; - final byte[] value; + final byte[] data; final int writeType; + final int value; private Request(final Type type) { this.type = type; this.characteristic = null; this.descriptor = null; - this.value = null; + this.data = null; this.writeType = 0; + this.value = 0; + } + + private Request(final Type type, final int value) { + this.type = type; + this.characteristic = null; + this.descriptor = null; + this.data = null; + this.writeType = 0; + this.value = value; } private Request(final Type type, final BluetoothGattCharacteristic characteristic) { this.type = type; this.characteristic = characteristic; this.descriptor = null; - this.value = null; + this.data = null; this.writeType = 0; + this.value = 0; } - private Request(final Type type, final BluetoothGattCharacteristic characteristic, final int writeType, final byte[] value, final int offset, final int length) { + private Request(final Type type, final BluetoothGattCharacteristic characteristic, final int writeType, final byte[] data, final int offset, final int length) { this.type = type; this.characteristic = characteristic; this.descriptor = null; - this.value = copy(value, offset, length); + this.data = copy(data, offset, length); this.writeType = writeType; + this.value = 0; } private Request(final Type type, final BluetoothGattDescriptor descriptor) { this.type = type; this.characteristic = null; this.descriptor = descriptor; - this.value = null; + this.data = null; this.writeType = 0; + this.value = 0; } - private Request(final Type type, final BluetoothGattDescriptor descriptor, final byte[] value, final int offset, final int length) { + private Request(final Type type, final BluetoothGattDescriptor descriptor, final byte[] data, final int offset, final int length) { this.type = type; this.characteristic = null; this.descriptor = descriptor; - this.value = copy(value, offset, length); + this.data = copy(data, offset, length); this.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT; + this.value = 0; } private static byte[] copy(final byte[] value, final int offset, final int length) { @@ -127,50 +145,50 @@ public interface BleProfileApi { * Creates new Write Characteristic request. The request will not be executed if given characteristic * is null or does not have WRITE property. After the operation is complete a proper callback will be invoked. * @param characteristic characteristic to be written - * @param value value to be written. The array is copied into another buffer so it's safe to reuse the array again. + * @param data data to be written. The array is copied into another buffer so it's safe to reuse the array again. * @return the new request that can be enqueued using {@link #enqueue(Request)} method. */ - public static Request newWriteRequest(final BluetoothGattCharacteristic characteristic, final byte[] value) { - return new Request(Type.WRITE, characteristic, characteristic.getWriteType(), value, 0, value != null ? value.length : 0); + public static Request newWriteRequest(final BluetoothGattCharacteristic characteristic, final byte[] data) { + return new Request(Type.WRITE, characteristic, characteristic.getWriteType(), data, 0, data != null ? data.length : 0); } /** * Creates new Write Characteristic request. The request will not be executed if given characteristic * is null or does not have WRITE property. After the operation is complete a proper callback will be invoked. * @param characteristic characteristic to be written - * @param value value to be written. The array is copied into another buffer so it's safe to reuse the array again. + * @param data data to be written. The array is copied into another buffer so it's safe to reuse the array again. * @param writeType write type to be used, one of {@link BluetoothGattCharacteristic#WRITE_TYPE_DEFAULT}, {@link BluetoothGattCharacteristic#WRITE_TYPE_NO_RESPONSE}. * @return the new request that can be enqueued using {@link #enqueue(Request)} method. */ - public static Request newWriteRequest(final BluetoothGattCharacteristic characteristic, final byte[] value, final int writeType) { - return new Request(Type.WRITE, characteristic, writeType, value, 0, value != null ? value.length : 0); + public static Request newWriteRequest(final BluetoothGattCharacteristic characteristic, final byte[] data, final int writeType) { + return new Request(Type.WRITE, characteristic, writeType, data, 0, data != null ? data.length : 0); } /** * Creates new Write Characteristic request. The request will not be executed if given characteristic * is null or does not have WRITE property. After the operation is complete a proper callback will be invoked. * @param characteristic characteristic to be written - * @param value value to be written. The array is copied into another buffer so it's safe to reuse the array again. - * @param offset the offset from which value has to be copied - * @param length number of bytes to be copied from the value buffer + * @param data data to be written. The array is copied into another buffer so it's safe to reuse the array again. + * @param offset the offset from which data has to be copied + * @param length number of bytes to be copied from the data buffer * @return the new request that can be enqueued using {@link #enqueue(Request)} method. */ - public static Request newWriteRequest(final BluetoothGattCharacteristic characteristic, final byte[] value, final int offset, final int length) { - return new Request(Type.WRITE, characteristic, characteristic.getWriteType(), value, offset, length); + public static Request newWriteRequest(final BluetoothGattCharacteristic characteristic, final byte[] data, final int offset, final int length) { + return new Request(Type.WRITE, characteristic, characteristic.getWriteType(), data, offset, length); } /** * Creates new Write Characteristic request. The request will not be executed if given characteristic * is null or does not have WRITE property. After the operation is complete a proper callback will be invoked. * @param characteristic characteristic to be written - * @param value value to be written. The array is copied into another buffer so it's safe to reuse the array again. - * @param offset the offset from which value has to be copied - * @param length number of bytes to be copied from the value buffer + * @param data data to be written. The array is copied into another buffer so it's safe to reuse the array again. + * @param offset the offset from which data has to be copied + * @param length number of bytes to be copied from the data buffer * @param writeType write type to be used, one of {@link BluetoothGattCharacteristic#WRITE_TYPE_DEFAULT}, {@link BluetoothGattCharacteristic#WRITE_TYPE_NO_RESPONSE}. * @return the new request that can be enqueued using {@link #enqueue(Request)} method. */ - public static Request newWriteRequest(final BluetoothGattCharacteristic characteristic, final byte[] value, final int offset, final int length, final int writeType) { - return new Request(Type.WRITE, characteristic, writeType, value, offset, length); + public static Request newWriteRequest(final BluetoothGattCharacteristic characteristic, final byte[] data, final int offset, final int length, final int writeType) { + return new Request(Type.WRITE, characteristic, writeType, data, offset, length); } /** @@ -187,24 +205,24 @@ public interface BleProfileApi { * Creates new Write Descriptor request. The request will not be executed if given descriptor * is null. After the operation is complete a proper callback will be invoked. * @param descriptor descriptor to be written - * @param value value to be written. The array is copied into another buffer so it's safe to reuse the array again. + * @param data data to be written. The array is copied into another buffer so it's safe to reuse the array again. * @return the new request that can be enqueued using {@link #enqueue(Request)} method. */ - public static Request newWriteRequest(final BluetoothGattDescriptor descriptor, final byte[] value) { - return new Request(Type.WRITE_DESCRIPTOR, descriptor, value, 0, value != null ? value.length : 0); + public static Request newWriteRequest(final BluetoothGattDescriptor descriptor, final byte[] data) { + return new Request(Type.WRITE_DESCRIPTOR, descriptor, data, 0, data != null ? data.length : 0); } /** * Creates new Write Descriptor request. The request will not be executed if given descriptor * is null. After the operation is complete a proper callback will be invoked. * @param descriptor descriptor to be written - * @param value value to be written. The array is copied into another buffer so it's safe to reuse the array again. - * @param offset the offset from which value has to be copied - * @param length number of bytes to be copied from the value buffer + * @param data data to be written. The array is copied into another buffer so it's safe to reuse the array again. + * @param offset the offset from which data has to be copied + * @param length number of bytes to be copied from the data buffer * @return the new request that can be enqueued using {@link #enqueue(Request)} method. */ - public static Request newWriteRequest(final BluetoothGattDescriptor descriptor, final byte[] value, final int offset, final int length) { - return new Request(Type.WRITE_DESCRIPTOR, descriptor, value, offset, length); + public static Request newWriteRequest(final BluetoothGattDescriptor descriptor, final byte[] data, final int offset, final int length) { + return new Request(Type.WRITE_DESCRIPTOR, descriptor, data, offset, length); } /** @@ -263,6 +281,38 @@ public interface BleProfileApi { static Request newEnableServiceChangedIndicationsRequest() { return new Request(Type.ENABLE_SERVICE_CHANGED_INDICATIONS); // the only Service Changed char is used (if such exists) } + + /** + * Requests new MTU (Maximum Transfer Unit). This is only supported on Android Lollipop or newer. + * The target device may reject requested data and set smalled MTU. + * @param mtu the new MTU. Acceptable values are <23, 517>. + * @return the new request that can be enqueued using {@link #enqueue(Request)} method. + */ + static Request newMtuRequest(int mtu) { + if (mtu < 23) + mtu = 23; + if (mtu > 517) + mtu = 517; + return new Request(Type.REQUEST_MTU, mtu); + } + + /** + * Requests the new connection priority. Acceptable values are: + *
    + *
  1. {@link BluetoothGatt#CONNECTION_PRIORITY_HIGH} - Interval: 11.25 -15 ms, latency: 0, supervision timeout: 20 sec,
  2. + *
  3. {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED} - Interval: 30 - 50 ms, latency: 0, supervision timeout: 20 sec,
  4. + *
  5. {@link BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER} - Interval: 100 - 125 ms, latency: 2, supervision timeout: 20 sec.
  6. + *
+ * + * @param priority one of: {@link BluetoothGatt#CONNECTION_PRIORITY_HIGH}, {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED}, + * {@link BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER}. + * @return the new request that can be enqueued using {@link #enqueue(Request)} method. + */ + static Request newConnectionPriorityRequest(int priority) { + if (priority < 0 || priority > 2) + priority = 0; // Balanced + return new Request(Type.REQUEST_CONNECTION_PRIORITY, priority); + } } /** @@ -337,6 +387,28 @@ public interface BleProfileApi { */ boolean setBatteryNotifications(final boolean enable); + /** + * Requests new MTU. On Android 4.3 and 4.4.x returns false. + * + * @return true if request has been enqueued + */ + boolean requestMtu(final int mtu); + + /** + * Requests the new connection priority. Acceptable values are: + *
    + *
  1. {@link BluetoothGatt#CONNECTION_PRIORITY_HIGH} - Interval: 11.25 -15 ms, latency: 0, supervision timeout: 20 sec,
  2. + *
  3. {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED} - Interval: 30 - 50 ms, latency: 0, supervision timeout: 20 sec,
  4. + *
  5. {@link BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER} - Interval: 100 - 125 ms, latency: 2, supervision timeout: 20 sec.
  6. + *
+ * On Android 4.3 and 4.4.x returns false. + * + * @param priority one of: {@link BluetoothGatt#CONNECTION_PRIORITY_HIGH}, {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED}, + * {@link BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER}. + * @return true if request has been enqueued + */ + boolean requestConnectionPriority(final int priority); + /** * Enqueues a new request. The request will be handled immediately if there is no operation in progress, * or automatically after the last enqueued one will finish.