Java 1.8 in wear module

This commit is contained in:
Aleksander Nowakowski
2017-11-09 12:59:30 +01:00
parent f7b2839292
commit 8bbba0e501
8 changed files with 101 additions and 101 deletions

View File

@@ -29,6 +29,10 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_1_8
}
} }
// exclude these from the build: // exclude these from the build:

View File

@@ -163,12 +163,7 @@ public class DevicesAdapter extends WearableListView.Adapter {
return mAvailableText; return mAvailableText;
} }
private Runnable mStopScanTask = new Runnable() { private Runnable mStopScanTask = () -> stopLeScan();
@Override
public void run() {
stopLeScan();
}
};
private ScanCallback mScanCallback = new ScanCallback() { private ScanCallback mScanCallback = new ScanCallback() {
@Override @Override

View File

@@ -44,6 +44,10 @@ import java.util.UUID;
import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; 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.
*
* <p>The BleManager is responsible for managing the low level communication with a Bluetooth Smart device. Please see profiles implementation for an example of use. * <p>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.</p> * This base manager has been tested against number of devices and samples from Nordic SDK.</p>
* <p>The manager handles connection events and initializes the device after establishing the connection. * <p>The manager handles connection events and initializes the device after establishing the connection.
@@ -204,13 +208,12 @@ public class BleManager implements BleProfileApi {
synchronized (mLock) { synchronized (mLock) {
if (mBluetoothGatt != null) { if (mBluetoothGatt != null) {
// There are 2 ways of reconnecting to the same device: // 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. // 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 // 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 // device.connectGatt(...) can't be called immediately or service discovery
// may never finish on some older devices (Nexus 4, Android 5.0.1). // 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 // If shouldAutoConnect() method returned false we can't call gatt.connect() and have to close gatt and open it again.
// despite the difficulties.
if (!mInitialConnection) { if (!mInitialConnection) {
mBluetoothGatt.close(); mBluetoothGatt.close();
mBluetoothGatt = null; mBluetoothGatt = null;
@@ -235,26 +238,37 @@ public class BleManager implements BleProfileApi {
} }
} }
final boolean autoConnect = shouldAutoConnect(); final boolean shouldAutoConnect = shouldAutoConnect();
mUserDisconnected = !autoConnect; // We will receive Linkloss events only when the device is connected with autoConnect=true 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; mBluetoothDevice = device;
mConnectionState = BluetoothGatt.STATE_CONNECTING; 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. * @return true if device is to be disconnected. False if it was already disconnected.
*/ */
public boolean disconnect() { public boolean disconnect() {
mUserDisconnected = true; mUserDisconnected = true;
mInitialConnection = false; mInitialConnection = false;
if (mConnected && mBluetoothGatt != null) { if (mBluetoothGatt != null) {
mConnectionState = BluetoothGatt.STATE_DISCONNECTING; mConnectionState = BluetoothGatt.STATE_DISCONNECTING;
mCallbacks.onDeviceDisconnecting(mBluetoothGatt.getDevice()); mCallbacks.onDeviceDisconnecting(mBluetoothGatt.getDevice());
final boolean wasConnected = mConnected;
mBluetoothGatt.disconnect(); 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 true;
} }
return false; return false;
@@ -379,7 +393,7 @@ public class BleManager implements BleProfileApi {
final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
if (descriptor != null) { if (descriptor != null) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
return gatt.writeDescriptor(descriptor); return internalWriteDescriptorWorkaround(descriptor);
} }
return false; return false;
} }
@@ -403,7 +417,7 @@ public class BleManager implements BleProfileApi {
final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
if (descriptor != null) { if (descriptor != null) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
return gatt.writeDescriptor(descriptor); return internalWriteDescriptorWorkaround(descriptor);
} }
return false; return false;
} }
@@ -467,14 +481,7 @@ public class BleManager implements BleProfileApi {
if (gatt == null || descriptor == null) if (gatt == null || descriptor == null)
return false; 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, return internalWriteDescriptorWorkaround(descriptor);
// 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;
} }
@Override @Override
@@ -538,11 +545,34 @@ public class BleManager implements BleProfileApi {
} else { } else {
descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
} }
return gatt.writeDescriptor(descriptor); return internalWriteDescriptorWorkaround(descriptor);
} }
return false; 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.
* <p>
* See: <a href="https://android.googlesource.com/platform/frameworks/base/+/942aebc95924ab1e7ea1e92aaf4e7fc45f695a6c%5E%21/#F0">
* https://android.googlesource.com/platform/frameworks/base/+/942aebc95924ab1e7ea1e92aaf4e7fc45f695a6c%5E%21/#F0</a>
* </p>
* @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 @Override
public boolean enqueue(final Request request) { public boolean enqueue(final Request request) {
if (mGattCallback != null) { if (mGattCallback != null) {
@@ -615,13 +645,10 @@ public class BleManager implements BleProfileApi {
*/ */
final boolean bonded = gatt.getDevice().getBondState() == BluetoothDevice.BOND_BONDED; 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. final int delay = bonded ? 1600 : 0; // around 1600 ms is required when connection interval is ~45ms.
mHandler.postDelayed(new Runnable() { mHandler.postDelayed(() -> {
@Override // Some proximity tags (e.g. nRF PROXIMITY) initialize bonding automatically when connected.
public void run() { if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_BONDING) {
// Some proximity tags (e.g. nRF PROXIMITY) initialize bonding automatically when connected. gatt.discoverServices();
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_BONDING) {
gatt.discoverServices();
}
} }
}, delay); }, delay);
} else { } else {
@@ -629,15 +656,18 @@ public class BleManager implements BleProfileApi {
mOperationInProgress = true; // no more calls are possible mOperationInProgress = true; // no more calls are possible
mInitQueue = null; mInitQueue = null;
mTaskQueue.clear(); 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 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. // 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) // This time it will set the autoConnect flag to true (gatt.connect() forces autoConnect true)
if (mInitialConnection) { if (mInitialConnection) {
connect(gatt.getDevice()); 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? // TODO Should the disconnect method be called or the connection is still valid? Does this ever happen?

View File

@@ -370,12 +370,7 @@ public class BleProfileService extends Service implements BleManagerCallbacks {
* an resource id of the message to be shown * an resource id of the message to be shown
*/ */
private void showToast(final int messageResId) { private void showToast(final int messageResId) {
mHandler.post(new Runnable() { mHandler.post(() -> Toast.makeText(BleProfileService.this, messageResId, Toast.LENGTH_SHORT).show());
@Override
public void run() {
Toast.makeText(BleProfileService.this, messageResId, Toast.LENGTH_SHORT).show();
}
});
} }
/** /**

View File

@@ -207,22 +207,12 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte
final UartConfiguration configuration = new UartConfiguration(dataMap, id); final UartConfiguration configuration = new UartConfiguration(dataMap, id);
// Update UI on UI thread // Update UI on UI thread
runOnUiThread(new Runnable() { runOnUiThread(() -> mAdapter.setConfiguration(configuration));
@Override
public void run() {
mAdapter.setConfiguration(configuration);
}
});
} else if (event.getType() == DataEvent.TYPE_DELETED) { } else if (event.getType() == DataEvent.TYPE_DELETED) {
// Configuration removed // Configuration removed
// Update UI on UI thread // Update UI on UI thread
runOnUiThread(new Runnable() { runOnUiThread(() -> mAdapter.setConfiguration(null));
@Override
public void run() {
mAdapter.setConfiguration(null);
}
});
} }
} }
} }
@@ -268,23 +258,20 @@ public class UARTCommandsActivity extends Activity implements UARTCommandsAdapte
* @param command the message * @param command the message
*/ */
private void sendMessageToHandheld(final @NonNull Context context, final @NonNull String command) { private void sendMessageToHandheld(final @NonNull Context context, final @NonNull String command) {
new Thread(new Runnable() { new Thread(() -> {
@Override final GoogleApiClient client = new GoogleApiClient.Builder(context)
public void run() { .addApi(Wearable.API)
final GoogleApiClient client = new GoogleApiClient.Builder(context) .build();
.addApi(Wearable.API) client.blockingConnect();
.build();
client.blockingConnect();
final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(client).await(); final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(client).await();
for (Node node : nodes.getNodes()) { for (Node node : nodes.getNodes()) {
final MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(client, node.getId(), Constants.UART.COMMAND, command.getBytes()).await(); final MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(client, node.getId(), Constants.UART.COMMAND, command.getBytes()).await();
if (!result.getStatus().isSuccess()) { if (!result.getStatus().isSuccess()) {
Log.w(TAG, "Failed to send " + Constants.UART.COMMAND + " to " + node.getDisplayName()); Log.w(TAG, "Failed to send " + Constants.UART.COMMAND + " to " + node.getDisplayName());
}
} }
client.disconnect();
} }
client.disconnect();
}).start(); }).start();
} }
} }

View File

@@ -74,12 +74,7 @@ public class UARTCommandsAdapter extends GridPagerAdapter {
final CircularButton icon = view.findViewById(R.id.icon); final CircularButton icon = view.findViewById(R.id.icon);
icon.getImageDrawable().setLevel(command.getIconIndex()); icon.getImageDrawable().setLevel(command.getIconIndex());
icon.setOnClickListener(new View.OnClickListener() { icon.setOnClickListener(v -> mListener.onCommandSelected(command));
@Override
public void onClick(final View v) {
mListener.onCommandSelected(command);
}
});
} else { } else {
// Hide the icon // Hide the icon
view.findViewById(R.id.icon).setVisibility(View.GONE); view.findViewById(R.id.icon).setVisibility(View.GONE);

View File

@@ -218,20 +218,17 @@ public class UARTConfigurationsActivity extends Activity implements GoogleApiCli
private void populateConfigurations() { private void populateConfigurations() {
if (mGoogleApiClient.isConnected()) { if (mGoogleApiClient.isConnected()) {
final PendingResult<DataItemBuffer> results = Wearable.DataApi.getDataItems(mGoogleApiClient, Uri.parse("wear:" + Constants.UART.CONFIGURATIONS), DataApi.FILTER_PREFIX); final PendingResult<DataItemBuffer> results = Wearable.DataApi.getDataItems(mGoogleApiClient, Uri.parse("wear:" + Constants.UART.CONFIGURATIONS), DataApi.FILTER_PREFIX);
results.setResultCallback(new ResultCallback<DataItemBuffer>() { results.setResultCallback(dataItems -> {
@Override final List<UartConfiguration> configurations = new ArrayList<>(dataItems.getCount());
public void onResult(final DataItemBuffer dataItems) { for (int i = 0; i < dataItems.getCount(); ++i) {
final List<UartConfiguration> configurations = new ArrayList<>(dataItems.getCount()); final DataItem item = dataItems.get(i);
for (int i = 0; i < dataItems.getCount(); ++i) { final long id = ContentUris.parseId(item.getUri());
final DataItem item = dataItems.get(i); final DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
final long id = ContentUris.parseId(item.getUri()); final UartConfiguration configuration = new UartConfiguration(dataMap, id);
final DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap(); configurations.add(configuration);
final UartConfiguration configuration = new UartConfiguration(dataMap, id);
configurations.add(configuration);
}
mAdapter.setConfigurations(configurations);
dataItems.release();
} }
mAdapter.setConfigurations(configurations);
dataItems.release();
}); });
} }
} }

View File

@@ -59,23 +59,20 @@ public class ActionReceiver extends BroadcastReceiver {
* @param message the message * @param message the message
*/ */
private void sendMessageToHandheld(final @NonNull Context context, final @NonNull String path, final @NonNull String message) { private void sendMessageToHandheld(final @NonNull Context context, final @NonNull String path, final @NonNull String message) {
new Thread(new Runnable() { new Thread(() -> {
@Override final GoogleApiClient client = new GoogleApiClient.Builder(context)
public void run() { .addApi(Wearable.API)
final GoogleApiClient client = new GoogleApiClient.Builder(context) .build();
.addApi(Wearable.API) client.blockingConnect();
.build();
client.blockingConnect();
final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(client).await(); final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(client).await();
for(Node node : nodes.getNodes()) { for(Node node : nodes.getNodes()) {
final MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(client, node.getId(), path, message.getBytes()).await(); final MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(client, node.getId(), path, message.getBytes()).await();
if (!result.getStatus().isSuccess()){ if (!result.getStatus().isSuccess()){
Log.w(TAG, "Failed to send " + path + " to " + node.getDisplayName()); Log.w(TAG, "Failed to send " + path + " to " + node.getDisplayName());
}
} }
client.disconnect();
} }
client.disconnect();
}).start(); }).start();
} }
} }