diff --git a/README.md b/README.md index 2eddce80..6697316c 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ The wearable application may work in 2 modes: as a remote control of the phone, ![Scenario 1](resources/scenario_1.png) -2. Open the applications menu on Android Wear watch and click nRF Toolbox. The watch will now scan for all nearby Bluetooth Smart devices and show you them on a list. Select your UART device to connect to it. A list of your configurations will be shown, like in 1. As that was a direct connection from the watch to the UART target the phone, or any other watch will not be notified about it. +2. Open the applications menu on Android Wear watch and click nRF Toolbox. The watch will now scan for all nearby Bluetooth LE devices and show you them on a list. Select your UART device to connect to it. A list of your configurations will be shown, like in 1. As that was a direct connection from the watch to the UART target the phone, or any other watch will not be notified about it. ![Scenario 2](resources/scenario_2.png) @@ -84,7 +84,6 @@ The DFU has the following features: - Allows to update a soft device and bootloader from ZIP in one connection. - Pause, resume, and cancel file uploads. - Works in portrait and landscape orientation. -- Includes pre-installed examples that consist of the Bluetooth Smart heart rate service and running speed and cadence service. - **Secure DFU** is supported since nRF Toolbox 1.17.0. #### DFU Settings diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fe0e594e..97635037 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -64,7 +64,7 @@ Cancel BONDED DEVICES: AVAILABLE DEVICES: - Since Android 6.0 Marshmallow system requires granting access to device\'s location in order to scan for Bluetooth Smart devices. Bluetooth beacons may be used to determine the phone\'s and user\'s location. + Since Android 6.0 Marshmallow system requires granting access to device\'s location in order to scan for Bluetooth LE devices. Bluetooth beacons may be used to determine the phone\'s and user\'s location. %1$tR:%1$tS.%1$tL diff --git a/app/src/main/res/values/strings_template.xml b/app/src/main/res/values/strings_template.xml index f63f4ee5..8b596157 100644 --- a/app/src/main/res/values/strings_template.xml +++ b/app/src/main/res/values/strings_template.xml @@ -48,6 +48,6 @@ This is an empty profile that may be easily adopted to match customer requirements. - The Bluetooth Smart connection is handled by the Manager in Template Service. + The Bluetooth Low Energy connection is handled by the Manager in Template Service. \n\nBy default this profile displays the Heart Rate value. \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 93eadd71..3dbd0f8b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,9 +3,9 @@ include ':app', ':wear', ':common' // Uncomment these lines if you want to import the BLE Library and BLE Common Library as a project, // not from jcenter: -include ':ble', ':ble-common' -project(':ble').projectDir = file('../Android-BLE-Library/ble') -project(':ble-common').projectDir = file('../Android-BLE-Common-Library/ble-common') +// include ':ble', ':ble-common' +// project(':ble').projectDir = file('../Android-BLE-Library/ble') +// project(':ble-common').projectDir = file('../Android-BLE-Common-Library/ble-common') // Uncomment these lines if you want to import the DFULibrary as a project, not from jcenter: 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 7dc5a902..497bb7a2 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 @@ -49,7 +49,7 @@ import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; * 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. + *

The BleManager is responsible for managing the low level communication with a Bluetooth Low Energy 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. *

    @@ -754,8 +754,15 @@ public class BleManager implements BleProfileApi { initQueue.addFirst(Request.newEnableBatteryLevelNotificationsRequest()); // 2. Read Battery Level characteristic (if such does not exist, this will be skipped) initQueue.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) + // 1. On devices running Android 4.3-5.x, 8.x and 9.0 the Service Changed + // characteristic needs to be enabled by the app (for bonded devices). + // The request will be ignored if there is no Service Changed characteristic. + // This "fix" broke this in Android 8: + // https://android-review.googlesource.com/c/platform/system/bt/+/239970 + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M + || Build.VERSION.SDK_INT == Build.VERSION_CODES.O + || Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1 + || Build.VERSION.SDK_INT == Build.VERSION_CODES.P) initQueue.addFirst(Request.newEnableServiceChangedIndicationsRequest()); operationInProgress = false; diff --git a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTCommandsAdapter.java b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTCommandsAdapter.java index f21994f3..84f0329d 100644 --- a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTCommandsAdapter.java +++ b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTCommandsAdapter.java @@ -33,7 +33,7 @@ import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.nrftoolbox.uart.domain.Command; import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration; -public class UARTCommandsAdapter extends GridPagerAdapter { +class UARTCommandsAdapter extends GridPagerAdapter { private final OnCommandSelectedListener listener; private UartConfiguration configuration; @@ -41,12 +41,12 @@ public class UARTCommandsAdapter extends GridPagerAdapter { void onCommandSelected(final Command command); } - public UARTCommandsAdapter(final UartConfiguration configuration, final OnCommandSelectedListener listener) { + UARTCommandsAdapter(final UartConfiguration configuration, final OnCommandSelectedListener listener) { this.configuration = configuration; this.listener = listener; } - public void setConfiguration(final UartConfiguration configuration) { + void setConfiguration(final UartConfiguration configuration) { // Configuration is null when it has been deleted on the handheld this.configuration = configuration; notifyDataSetChanged(); diff --git a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTConfigurationsActivity.java b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTConfigurationsActivity.java index 909532d8..8b1872b9 100644 --- a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTConfigurationsActivity.java +++ b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTConfigurationsActivity.java @@ -33,6 +33,8 @@ import android.content.ServiceConnection; import android.net.Uri; import android.os.Bundle; import android.os.IBinder; + +import androidx.annotation.NonNull; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import android.support.wearable.view.WearableListView; import android.widget.Toast; @@ -170,7 +172,7 @@ public class UARTConfigurationsActivity extends Activity implements GoogleApiCli } @Override - public void onConnectionFailed(final ConnectionResult connectionResult) { + public void onConnectionFailed(@NonNull final ConnectionResult connectionResult) { finish(); } diff --git a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTConfigurationsAdapter.java b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTConfigurationsAdapter.java index 6c0778e0..d14a966e 100644 --- a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTConfigurationsAdapter.java +++ b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTConfigurationsAdapter.java @@ -35,18 +35,18 @@ import androidx.annotation.NonNull; import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration; -public class UARTConfigurationsAdapter extends WearableListView.Adapter { +class UARTConfigurationsAdapter extends WearableListView.Adapter { private final LayoutInflater inflater; private List configurations; - public UARTConfigurationsAdapter(final Context context) { + UARTConfigurationsAdapter(final Context context) { inflater = LayoutInflater.from(context); } /** * Populates the adapter with list of configurations. */ - public void setConfigurations(final List configurations) { + void setConfigurations(final List configurations) { this.configurations = configurations; notifyDataSetChanged(); } @@ -68,11 +68,11 @@ public class UARTConfigurationsAdapter extends WearableListView.Adapter { return configurations != null ? configurations.size() : 0; } - public static class ConfigurationViewHolder extends WearableListView.ViewHolder { + static class ConfigurationViewHolder extends WearableListView.ViewHolder { private UartConfiguration configuration; private TextView name; - public ConfigurationViewHolder(final View itemView) { + ConfigurationViewHolder(final View itemView) { super(itemView); name = itemView.findViewById(R.id.name); @@ -83,7 +83,7 @@ public class UARTConfigurationsAdapter extends WearableListView.Adapter { name.setText(configuration.getName()); } - public UartConfiguration getConfiguration() { + UartConfiguration getConfiguration() { return configuration; } } diff --git a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTProfile.java b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTProfile.java index 7a12ed62..b0070f28 100644 --- a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTProfile.java +++ b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTProfile.java @@ -34,10 +34,11 @@ import no.nordicsemi.android.nrftoolbox.ble.BleManager; import no.nordicsemi.android.nrftoolbox.ble.BleProfile; import no.nordicsemi.android.nrftoolbox.ble.BleProfileApi; -public class UARTProfile extends BleProfile { +class UARTProfile extends BleProfile { /** Broadcast sent when a UART message is received. */ - public static final String BROADCAST_DATA_RECEIVED = "no.nordicsemi.android.nrftoolbox.uart.BROADCAST_DATA_RECEIVED"; + static final String BROADCAST_DATA_RECEIVED = "no.nordicsemi.android.nrftoolbox.uart.BROADCAST_DATA_RECEIVED"; /** The message. */ + @SuppressWarnings("unused") public static final String EXTRA_DATA = "no.nordicsemi.android.nrftoolbox.EXTRA_DATA"; /** Nordic UART Service UUID */ @@ -56,39 +57,45 @@ public class UARTProfile extends BleProfile { */ public static boolean matchDevice(final BluetoothGatt gatt) { final BluetoothGattService service = gatt.getService(UART_SERVICE_UUID); - return service != null && service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID) != null && service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID) != null; + return service != null + && service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID) != null + && service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID) != null; } - private BluetoothGattCharacteristic tXCharacteristic; - private BluetoothGattCharacteristic rXCharacteristic; + @SuppressWarnings("unused") + private BluetoothGattCharacteristic txCharacteristic; + private BluetoothGattCharacteristic rxCharacteristic; private byte[] outgoingBuffer; private int bufferOffset; @Override protected Deque initGatt(final BluetoothGatt gatt) { final BluetoothGattService service = gatt.getService(UART_SERVICE_UUID); - tXCharacteristic = service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID); - rXCharacteristic = service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID); + txCharacteristic = service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID); + rxCharacteristic = service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID); - final int rxProperties = rXCharacteristic.getProperties(); + final int rxProperties = rxCharacteristic.getProperties(); boolean writeRequest = (rxProperties & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0; - // Set the WRITE REQUEST type when the characteristic supports it. This will allow to send long write (also if the characteristic support it). - // In case there is no WRITE REQUEST property, this manager will divide texts longer then 20 bytes into up to 20 bytes chunks. + // Set the WRITE REQUEST type when the characteristic supports it. This will allow to send + // long write (also if the characteristic support it). + // In case there is no WRITE REQUEST property, this manager will divide texts longer then + // 20 bytes into up to 20 bytes chunks. if (writeRequest) - rXCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT); + rxCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT); - // We don't want to enable notifications on TX characteristic as we are not showing them here. A watch may be just used to send data. At least now. + // We don't want to enable notifications on TX characteristic as we are not showing them here. + // A watch may be just used to send data. At least now. // final LinkedList requests = new LinkedList<>(); -// requests.add(BleProfileApi.Request.newEnableNotificationsRequest(tXCharacteristic)); +// requests.add(BleProfileApi.Request.newEnableNotificationsRequest(txCharacteristic)); // return requests; return null; } @Override protected void release() { - tXCharacteristic = null; - rXCharacteristic = null; + txCharacteristic = null; + rxCharacteristic = null; } @Override @@ -107,7 +114,7 @@ public class UARTProfile extends BleProfile { outgoingBuffer = null; } else { // Otherwise... final int length = Math.min(buffer.length - bufferOffset, MAX_PACKET_SIZE); - getApi().enqueue(BleProfileApi.Request.newWriteRequest(rXCharacteristic, buffer, bufferOffset, length)); + getApi().enqueue(BleProfileApi.Request.newWriteRequest(rxCharacteristic, buffer, bufferOffset, length)); bufferOffset += length; } } @@ -116,9 +123,9 @@ public class UARTProfile extends BleProfile { * Sends the given text to RX characteristic. * @param text the text to be sent */ - public void send(final String text) { + void send(final String text) { // Are we connected? - if (rXCharacteristic == null) + if (rxCharacteristic == null) return; // An outgoing buffer may not be null if there is already another packet being sent. We do nothing in this case. @@ -128,15 +135,15 @@ public class UARTProfile extends BleProfile { // Depending on whether the characteristic has the WRITE REQUEST property or not, we will either send it as it is (hoping the long write is implemented), // or divide it into up to 20 bytes chunks and send them one by one. - final boolean writeRequest = (rXCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0; + final boolean writeRequest = (rxCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0; if (!writeRequest) { // no WRITE REQUEST property final int length = Math.min(buffer.length, MAX_PACKET_SIZE); bufferOffset += length; - getApi().enqueue(BleProfileApi.Request.newWriteRequest(rXCharacteristic, buffer, 0, length)); + getApi().enqueue(BleProfileApi.Request.newWriteRequest(rxCharacteristic, buffer, 0, length)); } else { // there is WRITE REQUEST property, let's try Long Write bufferOffset = buffer.length; - getApi().enqueue(BleProfileApi.Request.newWriteRequest(rXCharacteristic, buffer, 0, buffer.length)); + getApi().enqueue(BleProfileApi.Request.newWriteRequest(rxCharacteristic, buffer, 0, buffer.length)); } } }