diff --git a/wear/build.gradle b/wear/build.gradle index cf7d6315..b9d61bfe 100644 --- a/wear/build.gradle +++ b/wear/build.gradle @@ -29,6 +29,10 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + compileOptions { + targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_1_8 + } } // exclude these from the build: diff --git a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/DevicesAdapter.java b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/DevicesAdapter.java index b454a462..188a3759 100644 --- a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/DevicesAdapter.java +++ b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/DevicesAdapter.java @@ -163,12 +163,7 @@ public class DevicesAdapter extends WearableListView.Adapter { return mAvailableText; } - private Runnable mStopScanTask = new Runnable() { - @Override - public void run() { - stopLeScan(); - } - }; + private Runnable mStopScanTask = () -> stopLeScan(); private ScanCallback mScanCallback = new ScanCallback() { @Override 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 e7a4ca02..61a329ba 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 @@ -44,6 +44,10 @@ import java.util.UUID; import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; /** + * 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. @@ -204,13 +208,12 @@ public class BleManager implements BleProfileApi { synchronized (mLock) { if (mBluetoothGatt != null) { // There are 2 ways of reconnecting to the same device: - // 1. Reusing the same BluetoothGatt object and calling connect() on it or + // 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). - // However, the autoConnect flag settings may have changed. If it did, try closing and opening new BluetoothGatt - // despite the difficulties. + // If shouldAutoConnect() method returned false we can't call gatt.connect() and have to close gatt and open it again. if (!mInitialConnection) { mBluetoothGatt.close(); mBluetoothGatt = null; @@ -235,26 +238,37 @@ public class BleManager implements BleProfileApi { } } - final boolean autoConnect = shouldAutoConnect(); - mUserDisconnected = !autoConnect; // We will receive Linkloss events only when the device is connected with autoConnect=true + 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; mConnectionState = BluetoothGatt.STATE_CONNECTING; - mBluetoothGatt = device.connectGatt(mContext, autoConnect, mGattCallback = new BleManagerGattCallback()); + mCallbacks.onDeviceConnecting(device); + mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback = new BleManagerGattCallback()); } /** - * Disconnects from the device. Does nothing if not connected. - * + * 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 (mConnected && mBluetoothGatt != null) { + if (mBluetoothGatt != null) { mConnectionState = BluetoothGatt.STATE_DISCONNECTING; mCallbacks.onDeviceDisconnecting(mBluetoothGatt.getDevice()); + final boolean wasConnected = mConnected; mBluetoothGatt.disconnect(); + + if (!wasConnected) { + // There will be no callback, the connection attempt will be stopped + mConnectionState = BluetoothGatt.STATE_DISCONNECTED; + mCallbacks.onDeviceDisconnected(mBluetoothGatt.getDevice()); + } return true; } return false; @@ -379,7 +393,7 @@ public class BleManager implements BleProfileApi { final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); if (descriptor != null) { descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); - return gatt.writeDescriptor(descriptor); + return internalWriteDescriptorWorkaround(descriptor); } return false; } @@ -403,7 +417,7 @@ public class BleManager implements BleProfileApi { final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); if (descriptor != null) { descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); - return gatt.writeDescriptor(descriptor); + return internalWriteDescriptorWorkaround(descriptor); } return false; } @@ -467,14 +481,7 @@ public class BleManager implements BleProfileApi { if (gatt == null || descriptor == null) return false; - // There was a bug in Android up to 6.0 where the descriptor was written using parent characteristic write type, instead of always Write With Response, - // as the spec says. - 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; + return internalWriteDescriptorWorkaround(descriptor); } @Override @@ -538,11 +545,34 @@ public class BleManager implements BleProfileApi { } else { descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); } - return gatt.writeDescriptor(descriptor); + 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; + } + @Override public boolean enqueue(final Request request) { if (mGattCallback != null) { @@ -615,13 +645,10 @@ public class BleManager implements BleProfileApi { */ 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. - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - // Some proximity tags (e.g. nRF PROXIMITY) initialize bonding automatically when connected. - if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_BONDING) { - gatt.discoverServices(); - } + mHandler.postDelayed(() -> { + // Some proximity tags (e.g. nRF PROXIMITY) initialize bonding automatically when connected. + if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_BONDING) { + gatt.discoverServices(); } }, delay); } else { @@ -629,15 +656,18 @@ public class BleManager implements BleProfileApi { mOperationInProgress = true; // no more calls are possible mInitQueue = null; mTaskQueue.clear(); - if (mConnected) { + 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()); } - return; + + if (wasConnected || status == BluetoothGatt.GATT_SUCCESS) + return; } // TODO Should the disconnect method be called or the connection is still valid? Does this ever happen? diff --git a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfileService.java b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfileService.java index fc139446..a046ea7d 100644 --- a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfileService.java +++ b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfileService.java @@ -370,12 +370,7 @@ public class BleProfileService extends Service implements BleManagerCallbacks { * an resource id of the message to be shown */ private void showToast(final int messageResId) { - mHandler.post(new Runnable() { - @Override - public void run() { - Toast.makeText(BleProfileService.this, messageResId, Toast.LENGTH_SHORT).show(); - } - }); + mHandler.post(() -> Toast.makeText(BleProfileService.this, messageResId, Toast.LENGTH_SHORT).show()); } /** diff --git a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTCommandsActivity.java b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTCommandsActivity.java index a57eb102..80ccdc6c 100644 --- a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTCommandsActivity.java +++ b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTCommandsActivity.java @@ -207,22 +207,12 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte final UartConfiguration configuration = new UartConfiguration(dataMap, id); // Update UI on UI thread - runOnUiThread(new Runnable() { - @Override - public void run() { - mAdapter.setConfiguration(configuration); - } - }); + runOnUiThread(() -> mAdapter.setConfiguration(configuration)); } else if (event.getType() == DataEvent.TYPE_DELETED) { // Configuration removed // Update UI on UI thread - runOnUiThread(new Runnable() { - @Override - public void run() { - mAdapter.setConfiguration(null); - } - }); + runOnUiThread(() -> mAdapter.setConfiguration(null)); } } } @@ -268,23 +258,20 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte * @param command the message */ private void sendMessageToHandheld(final @NonNull Context context, final @NonNull String command) { - new Thread(new Runnable() { - @Override - public void run() { - final GoogleApiClient client = new GoogleApiClient.Builder(context) - .addApi(Wearable.API) - .build(); - client.blockingConnect(); + new Thread(() -> { + final GoogleApiClient client = new GoogleApiClient.Builder(context) + .addApi(Wearable.API) + .build(); + client.blockingConnect(); - final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(client).await(); - for (Node node : nodes.getNodes()) { - final MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(client, node.getId(), Constants.UART.COMMAND, command.getBytes()).await(); - if (!result.getStatus().isSuccess()) { - Log.w(TAG, "Failed to send " + Constants.UART.COMMAND + " to " + node.getDisplayName()); - } + final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(client).await(); + for (Node node : nodes.getNodes()) { + final MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(client, node.getId(), Constants.UART.COMMAND, command.getBytes()).await(); + if (!result.getStatus().isSuccess()) { + Log.w(TAG, "Failed to send " + Constants.UART.COMMAND + " to " + node.getDisplayName()); } - client.disconnect(); } + client.disconnect(); }).start(); } } 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 ff9b2364..55c2ad3e 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 @@ -74,12 +74,7 @@ public class UARTCommandsAdapter extends GridPagerAdapter { final CircularButton icon = view.findViewById(R.id.icon); icon.getImageDrawable().setLevel(command.getIconIndex()); - icon.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(final View v) { - mListener.onCommandSelected(command); - } - }); + icon.setOnClickListener(v -> mListener.onCommandSelected(command)); } else { // Hide the icon view.findViewById(R.id.icon).setVisibility(View.GONE); 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 2c3c39a5..b8c9dd54 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 @@ -218,20 +218,17 @@ public class UARTConfigurationsActivity extends Activity implements GoogleApiCli private void populateConfigurations() { if (mGoogleApiClient.isConnected()) { final PendingResult