mirror of
https://github.com/aljazceru/Android-nRF-Toolbox.git
synced 2025-12-22 00:44:26 +01:00
Merge pull request #78 from NordicSemiconductor/hotfix/fix-foreground-service
Hotfix/fix foreground service
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion "28.0.3"
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.0"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "no.nordicsemi.android.nrftoolbox"
|
||||
minSdkVersion 18
|
||||
targetSdkVersion 28
|
||||
targetSdkVersion 29
|
||||
versionCode 69
|
||||
versionName "2.7.2"
|
||||
resConfigs "en"
|
||||
@@ -42,9 +42,9 @@ dependencies {
|
||||
//noinspection GradleDependency
|
||||
implementation 'com.google.android.gms:play-services-wearable:10.2.0'
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0-alpha04'
|
||||
implementation 'androidx.preference:preference:1.1.0-alpha04'
|
||||
implementation 'com.google.android.material:material:1.1.0-alpha05'
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
|
||||
implementation 'androidx.preference:preference:1.1.0-rc01'
|
||||
implementation 'com.google.android.material:material:1.1.0-alpha09'
|
||||
|
||||
implementation 'no.nordicsemi.android:log:2.2.0'
|
||||
implementation 'no.nordicsemi.android.support.v18:scanner:1.4.0'
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
<uses-permission android:name="no.nordicsemi.android.LOG" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.bluetooth_le"
|
||||
|
||||
@@ -8,11 +8,12 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import no.nordicsemi.android.log.Logger;
|
||||
import no.nordicsemi.android.nrftoolbox.FeaturesActivity;
|
||||
import no.nordicsemi.android.nrftoolbox.R;
|
||||
@@ -21,270 +22,294 @@ import no.nordicsemi.android.nrftoolbox.profile.BleProfileService;
|
||||
import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager;
|
||||
|
||||
public class CGMService extends BleProfileService implements CGMSManagerCallbacks {
|
||||
private static final String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.cgms.ACTION_DISCONNECT";
|
||||
private static final String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.cgms.ACTION_DISCONNECT";
|
||||
|
||||
public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL";
|
||||
public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL";
|
||||
public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL";
|
||||
public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL";
|
||||
|
||||
public static final String BROADCAST_NEW_CGMS_VALUE = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_NEW_CGMS_VALUE";
|
||||
public static final String BROADCAST_DATA_SET_CLEAR = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_DATA_SET_CLEAR";
|
||||
public static final String OPERATION_STARTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_STARTED";
|
||||
public static final String OPERATION_COMPLETED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_COMPLETED";
|
||||
public static final String OPERATION_SUPPORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_SUPPORTED";
|
||||
public static final String OPERATION_NOT_SUPPORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_NOT_SUPPORTED";
|
||||
public static final String OPERATION_FAILED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_FAILED";
|
||||
public static final String OPERATION_ABORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_ABORTED";
|
||||
public static final String EXTRA_CGMS_RECORD = "no.nordicsemi.android.nrftoolbox.cgms.EXTRA_CGMS_RECORD";
|
||||
public static final String EXTRA_DATA = "no.nordicsemi.android.nrftoolbox.cgms.EXTRA_DATA";
|
||||
public static final String BROADCAST_NEW_CGMS_VALUE = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_NEW_CGMS_VALUE";
|
||||
public static final String BROADCAST_DATA_SET_CLEAR = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_DATA_SET_CLEAR";
|
||||
public static final String OPERATION_STARTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_STARTED";
|
||||
public static final String OPERATION_COMPLETED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_COMPLETED";
|
||||
public static final String OPERATION_SUPPORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_SUPPORTED";
|
||||
public static final String OPERATION_NOT_SUPPORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_NOT_SUPPORTED";
|
||||
public static final String OPERATION_FAILED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_FAILED";
|
||||
public static final String OPERATION_ABORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_ABORTED";
|
||||
public static final String EXTRA_CGMS_RECORD = "no.nordicsemi.android.nrftoolbox.cgms.EXTRA_CGMS_RECORD";
|
||||
public static final String EXTRA_DATA = "no.nordicsemi.android.nrftoolbox.cgms.EXTRA_DATA";
|
||||
|
||||
private final static int NOTIFICATION_ID = 229;
|
||||
private final static int OPEN_ACTIVITY_REQ = 0;
|
||||
private final static int DISCONNECT_REQ = 1;
|
||||
private final static int NOTIFICATION_ID = 229;
|
||||
private final static int OPEN_ACTIVITY_REQ = 0;
|
||||
private final static int DISCONNECT_REQ = 1;
|
||||
|
||||
private CGMSManager mManager;
|
||||
private final LocalBinder mBinder = new CGMSBinder();
|
||||
private CGMSManager mManager;
|
||||
private final LocalBinder mBinder = new CGMSBinder();
|
||||
|
||||
/**
|
||||
* This local binder is an interface for the bonded activity to operate with the RSC sensor
|
||||
*/
|
||||
/**
|
||||
* This local binder is an interface for the bonded activity to operate with the RSC sensor
|
||||
*/
|
||||
|
||||
public class CGMSBinder extends LocalBinder {
|
||||
/**
|
||||
* Returns all records as a sparse array where sequence number is the key.
|
||||
*
|
||||
* @return the records list
|
||||
*/
|
||||
public SparseArray<CGMSRecord> getRecords() {
|
||||
return mManager.getRecords();
|
||||
}
|
||||
public class CGMSBinder extends LocalBinder {
|
||||
/**
|
||||
* Returns all records as a sparse array where sequence number is the key.
|
||||
*
|
||||
* @return the records list
|
||||
*/
|
||||
public SparseArray<CGMSRecord> getRecords() {
|
||||
return mManager.getRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the records list locally
|
||||
*/
|
||||
public void clear() {
|
||||
if (mManager != null)
|
||||
mManager.clear();
|
||||
}
|
||||
/**
|
||||
* Clears the records list locally
|
||||
*/
|
||||
public void clear() {
|
||||
if (mManager != null)
|
||||
mManager.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request to obtain the first (oldest) record from glucose device.
|
||||
* The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control
|
||||
* Point indication with status code ({@link CGMSManager# RESPONSE_SUCCESS} or other in case of error.
|
||||
*/
|
||||
public void getFirstRecord() {
|
||||
if (mManager != null)
|
||||
mManager.getFirstRecord();
|
||||
}
|
||||
/**
|
||||
* Sends the request to obtain the first (oldest) record from glucose device.
|
||||
* The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control
|
||||
* Point indication with status code ({@link CGMSManager# RESPONSE_SUCCESS} or other in case of error.
|
||||
*/
|
||||
public void getFirstRecord() {
|
||||
if (mManager != null)
|
||||
mManager.getFirstRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request to obtain the last (most recent) record from glucose device.
|
||||
* The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access
|
||||
* Control Point indication with status code Success or other in case of error.
|
||||
*/
|
||||
public void getLastRecord() {
|
||||
if (mManager != null)
|
||||
mManager.getLastRecord();
|
||||
}
|
||||
/**
|
||||
* Sends the request to obtain the last (most recent) record from glucose device.
|
||||
* The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access
|
||||
* Control Point indication with status code Success or other in case of error.
|
||||
*/
|
||||
public void getLastRecord() {
|
||||
if (mManager != null)
|
||||
mManager.getLastRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request to obtain all records from glucose device.
|
||||
* Initially we want to notify user about the number of the records so the Report Number of Stored Records is send.
|
||||
* The data will be returned to Glucose Measurement characteristic as a series of notifications followed
|
||||
* by Record Access Control Point indication with status code Success or other in case of error.
|
||||
*/
|
||||
public void getAllRecords() {
|
||||
if (mManager != null)
|
||||
mManager.getAllRecords();
|
||||
}
|
||||
/**
|
||||
* Sends the request to obtain all records from glucose device.
|
||||
* Initially we want to notify user about the number of the records so the Report Number of Stored Records is send.
|
||||
* The data will be returned to Glucose Measurement characteristic as a series of notifications followed
|
||||
* by Record Access Control Point indication with status code Success or other in case of error.
|
||||
*/
|
||||
public void getAllRecords() {
|
||||
if (mManager != null)
|
||||
mManager.getAllRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request to obtain all records from glucose device with sequence number greater
|
||||
* than the last one already obtained. The data will be returned to Glucose Measurement
|
||||
* characteristic as a series of notifications followed by Record Access Control Point
|
||||
* indication with status code Success or other in case of error.
|
||||
*/
|
||||
public void refreshRecords() {
|
||||
if (mManager != null)
|
||||
mManager.refreshRecords();
|
||||
}
|
||||
/**
|
||||
* Sends the request to obtain all records from glucose device with sequence number greater
|
||||
* than the last one already obtained. The data will be returned to Glucose Measurement
|
||||
* characteristic as a series of notifications followed by Record Access Control Point
|
||||
* indication with status code Success or other in case of error.
|
||||
*/
|
||||
public void refreshRecords() {
|
||||
if (mManager != null)
|
||||
mManager.refreshRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends abort operation signal to the device
|
||||
*/
|
||||
public void abort() {
|
||||
if (mManager != null)
|
||||
mManager.abort();
|
||||
}
|
||||
/**
|
||||
* Sends abort operation signal to the device
|
||||
*/
|
||||
public void abort() {
|
||||
if (mManager != null)
|
||||
mManager.abort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends Delete op code with All stored records parameter. This method may not be supported by the SDK sample.
|
||||
*/
|
||||
public void deleteAllRecords() {
|
||||
if (mManager != null)
|
||||
mManager.deleteAllRecords();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sends Delete op code with All stored records parameter. This method may not be supported by the SDK sample.
|
||||
*/
|
||||
public void deleteAllRecords() {
|
||||
if (mManager != null)
|
||||
mManager.deleteAllRecords();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalBinder getBinder() {
|
||||
return mBinder;
|
||||
}
|
||||
@Override
|
||||
protected LocalBinder getBinder() {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LoggableBleManager<CGMSManagerCallbacks> initializeManager() {
|
||||
return mManager = new CGMSManager(this);
|
||||
}
|
||||
@Override
|
||||
protected LoggableBleManager<CGMSManagerCallbacks> initializeManager() {
|
||||
return mManager = new CGMSManager(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ACTION_DISCONNECT);
|
||||
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
|
||||
}
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ACTION_DISCONNECT);
|
||||
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||
cancelNotification();
|
||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||
stopForegroundService();
|
||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRebind() {
|
||||
// when the activity rebinds to the service, remove the notification
|
||||
cancelNotification();
|
||||
}
|
||||
@Override
|
||||
protected void onRebind() {
|
||||
startForegroundService();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUnbind() {
|
||||
// when the activity closes we need to show the notification that user is connected to the sensor
|
||||
createNotification(R.string.csc_notification_connected_message, 0);
|
||||
}
|
||||
@Override
|
||||
protected void onUnbind() {
|
||||
startForegroundService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the notification
|
||||
*
|
||||
* @param messageResId the message resource id. The message must have one String parameter,<br />
|
||||
* f.e. <code><string name="name">%s is connected</string></code>
|
||||
* @param defaults signals that will be used to notify the user
|
||||
*/
|
||||
private void createNotification(final int messageResId, final int defaults) {
|
||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
final Intent targetIntent = new Intent(this, CGMSActivity.class);
|
||||
/**
|
||||
* Sets the service as a foreground service
|
||||
*/
|
||||
private void startForegroundService(){
|
||||
// when the activity closes we need to show the notification that user is connected to the peripheral sensor
|
||||
// We start the service as a foreground service as Android 8.0 (Oreo) onwards kills any running background services
|
||||
final Notification notification = createNotification(R.string.uart_notification_connected_message, 0);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForeground(NOTIFICATION_ID, notification);
|
||||
} else {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
}
|
||||
|
||||
final Intent disconnect = new Intent(ACTION_DISCONNECT);
|
||||
final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
/**
|
||||
* Stops the service as a foreground service
|
||||
*/
|
||||
private void stopForegroundService(){
|
||||
// when the activity rebinds to the service, remove the notification and stop the foreground service
|
||||
// on devices running Android 8.0 (Oreo) or above
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
stopForeground(true);
|
||||
} else {
|
||||
cancelNotification();
|
||||
}
|
||||
}
|
||||
|
||||
// both activities above have launchMode="singleTask" in the AndroidManifest.xml file, so if the task is already running, it will be resumed
|
||||
final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[]{parentIntent, targetIntent}, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL);
|
||||
builder.setContentIntent(pendingIntent);
|
||||
builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName()));
|
||||
builder.setSmallIcon(R.drawable.ic_stat_notify_cgms);
|
||||
builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true);
|
||||
builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.csc_notification_action_disconnect), disconnectAction));
|
||||
/**
|
||||
* Creates the notification
|
||||
*
|
||||
* @param messageResId the message resource id. The message must have one String parameter,<br />
|
||||
* f.e. <code><string name="name">%s is connected</string></code>
|
||||
* @param defaults signals that will be used to notify the user
|
||||
*/
|
||||
private Notification createNotification(final int messageResId, final int defaults) {
|
||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
final Intent targetIntent = new Intent(this, CGMSActivity.class);
|
||||
|
||||
final Notification notification = builder.build();
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
final Intent disconnect = new Intent(ACTION_DISCONNECT);
|
||||
final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
/**
|
||||
* Cancels the existing notification. If there is no active notification this method does nothing
|
||||
*/
|
||||
private void cancelNotification() {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
// both activities above have launchMode="singleTask" in the AndroidManifest.xml file, so if the task is already running, it will be resumed
|
||||
final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[]{parentIntent, targetIntent}, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL);
|
||||
builder.setContentIntent(pendingIntent);
|
||||
builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName()));
|
||||
builder.setSmallIcon(R.drawable.ic_stat_notify_cgms);
|
||||
builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true);
|
||||
builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.csc_notification_action_disconnect), disconnectAction));
|
||||
|
||||
/**
|
||||
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
|
||||
*/
|
||||
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||
if (isConnected())
|
||||
getBinder().disconnect();
|
||||
else
|
||||
stopSelf();
|
||||
}
|
||||
};
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCGMValueReceived(@NonNull final BluetoothDevice device, final CGMSRecord record) {
|
||||
final Intent broadcast = new Intent(BROADCAST_NEW_CGMS_VALUE);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_CGMS_RECORD, record);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
/**
|
||||
* Cancels the existing notification. If there is no active notification this method does nothing
|
||||
*/
|
||||
private void cancelNotification() {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOperationStarted(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_STARTED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
/**
|
||||
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
|
||||
*/
|
||||
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||
if (isConnected())
|
||||
getBinder().disconnect();
|
||||
else
|
||||
stopSelf();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onOperationCompleted(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_COMPLETED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onCGMValueReceived(@NonNull final BluetoothDevice device, final CGMSRecord record) {
|
||||
final Intent broadcast = new Intent(BROADCAST_NEW_CGMS_VALUE);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_CGMS_RECORD, record);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOperationFailed(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_FAILED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onOperationStarted(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_STARTED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOperationAborted(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_ABORTED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onOperationCompleted(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_COMPLETED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOperationNotSupported(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_NOT_SUPPORTED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, false);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onOperationFailed(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_FAILED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDatasetCleared(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(BROADCAST_DATA_SET_CLEAR);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onOperationAborted(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_ABORTED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNumberOfRecordsRequested(@NonNull final BluetoothDevice device, final int value) {
|
||||
if (value == 0)
|
||||
showToast(R.string.gls_progress_zero);
|
||||
else
|
||||
showToast(getResources().getQuantityString(R.plurals.gls_progress, value, value));
|
||||
@Override
|
||||
public void onOperationNotSupported(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_NOT_SUPPORTED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, false);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void onDatasetCleared(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(BROADCAST_DATA_SET_CLEAR);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
|
||||
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
|
||||
broadcast.putExtra(EXTRA_DEVICE, device);
|
||||
broadcast.putExtra(EXTRA_BATTERY_LEVEL, batteryLevel);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onNumberOfRecordsRequested(@NonNull final BluetoothDevice device, final int value) {
|
||||
if (value == 0)
|
||||
showToast(R.string.gls_progress_zero);
|
||||
else
|
||||
showToast(getResources().getQuantityString(R.plurals.gls_progress, value, value));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
|
||||
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
|
||||
broadcast.putExtra(EXTRA_DEVICE, device);
|
||||
broadcast.putExtra(EXTRA_BATTERY_LEVEL, batteryLevel);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,10 +30,11 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import no.nordicsemi.android.log.Logger;
|
||||
import no.nordicsemi.android.nrftoolbox.FeaturesActivity;
|
||||
import no.nordicsemi.android.nrftoolbox.R;
|
||||
@@ -42,168 +43,195 @@ import no.nordicsemi.android.nrftoolbox.profile.BleProfileService;
|
||||
import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager;
|
||||
|
||||
public class CSCService extends BleProfileService implements CSCManagerCallbacks {
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = "CSCService";
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = "CSCService";
|
||||
|
||||
public static final String BROADCAST_WHEEL_DATA = "no.nordicsemi.android.nrftoolbox.csc.BROADCAST_WHEEL_DATA";
|
||||
/** Speed in meters per second. */
|
||||
public static final String EXTRA_SPEED = "no.nordicsemi.android.nrftoolbox.csc.EXTRA_SPEED";
|
||||
/** Distance in meters. */
|
||||
public static final String EXTRA_DISTANCE = "no.nordicsemi.android.nrftoolbox.csc.EXTRA_DISTANCE";
|
||||
/** Total distance in meters. */
|
||||
public static final String EXTRA_TOTAL_DISTANCE = "no.nordicsemi.android.nrftoolbox.csc.EXTRA_TOTAL_DISTANCE";
|
||||
public static final String BROADCAST_WHEEL_DATA = "no.nordicsemi.android.nrftoolbox.csc.BROADCAST_WHEEL_DATA";
|
||||
/**
|
||||
* Speed in meters per second.
|
||||
*/
|
||||
public static final String EXTRA_SPEED = "no.nordicsemi.android.nrftoolbox.csc.EXTRA_SPEED";
|
||||
/**
|
||||
* Distance in meters.
|
||||
*/
|
||||
public static final String EXTRA_DISTANCE = "no.nordicsemi.android.nrftoolbox.csc.EXTRA_DISTANCE";
|
||||
/**
|
||||
* Total distance in meters.
|
||||
*/
|
||||
public static final String EXTRA_TOTAL_DISTANCE = "no.nordicsemi.android.nrftoolbox.csc.EXTRA_TOTAL_DISTANCE";
|
||||
|
||||
public static final String BROADCAST_CRANK_DATA = "no.nordicsemi.android.nrftoolbox.csc.BROADCAST_CRANK_DATA";
|
||||
public static final String EXTRA_GEAR_RATIO = "no.nordicsemi.android.nrftoolbox.csc.EXTRA_GEAR_RATIO";
|
||||
public static final String EXTRA_CADENCE = "no.nordicsemi.android.nrftoolbox.csc.EXTRA_CADENCE";
|
||||
public static final String BROADCAST_CRANK_DATA = "no.nordicsemi.android.nrftoolbox.csc.BROADCAST_CRANK_DATA";
|
||||
public static final String EXTRA_GEAR_RATIO = "no.nordicsemi.android.nrftoolbox.csc.EXTRA_GEAR_RATIO";
|
||||
public static final String EXTRA_CADENCE = "no.nordicsemi.android.nrftoolbox.csc.EXTRA_CADENCE";
|
||||
|
||||
public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL";
|
||||
public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL";
|
||||
public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL";
|
||||
public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL";
|
||||
|
||||
private static final String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.csc.ACTION_DISCONNECT";
|
||||
private static final String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.csc.ACTION_DISCONNECT";
|
||||
|
||||
private final static int NOTIFICATION_ID = 200;
|
||||
private final static int OPEN_ACTIVITY_REQ = 0;
|
||||
private final static int DISCONNECT_REQ = 1;
|
||||
private final static int NOTIFICATION_ID = 200;
|
||||
private final static int OPEN_ACTIVITY_REQ = 0;
|
||||
private final static int DISCONNECT_REQ = 1;
|
||||
|
||||
private final LocalBinder mBinder = new CSCBinder();
|
||||
private CSCManager mManager;
|
||||
private final LocalBinder mBinder = new CSCBinder();
|
||||
private CSCManager mManager;
|
||||
|
||||
/**
|
||||
* This local binder is an interface for the bonded activity to operate with the RSC sensor
|
||||
*/
|
||||
class CSCBinder extends LocalBinder {
|
||||
// empty
|
||||
}
|
||||
/**
|
||||
* This local binder is an interface for the bonded activity to operate with the RSC sensor
|
||||
*/
|
||||
class CSCBinder extends LocalBinder {
|
||||
// empty
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalBinder getBinder() {
|
||||
return mBinder;
|
||||
}
|
||||
@Override
|
||||
protected LocalBinder getBinder() {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LoggableBleManager<CSCManagerCallbacks> initializeManager() {
|
||||
return mManager = new CSCManager(this);
|
||||
}
|
||||
@Override
|
||||
protected LoggableBleManager<CSCManagerCallbacks> initializeManager() {
|
||||
return mManager = new CSCManager(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ACTION_DISCONNECT);
|
||||
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
|
||||
}
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ACTION_DISCONNECT);
|
||||
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||
cancelNotification();
|
||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||
cancelNotification();
|
||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRebind() {
|
||||
// when the activity rebinds to the service, remove the notification
|
||||
cancelNotification();
|
||||
@Override
|
||||
protected void onRebind() {
|
||||
stopForegroundService();
|
||||
|
||||
if (isConnected()) {
|
||||
// This method will read the Battery Level value, if possible and then try to enable battery notifications (if it has NOTIFY property).
|
||||
// If the Battery Level characteristic has only the NOTIFY property, it will only try to enable notifications.
|
||||
mManager.readBatteryLevelCharacteristic();
|
||||
}
|
||||
}
|
||||
if (isConnected()) {
|
||||
// This method will read the Battery Level value, if possible and then try to enable battery notifications (if it has NOTIFY property).
|
||||
// If the Battery Level characteristic has only the NOTIFY property, it will only try to enable notifications.
|
||||
mManager.readBatteryLevelCharacteristic();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUnbind() {
|
||||
// When we are connected, but the application is not open, we are not really interested in battery level notifications.
|
||||
// But we will still be receiving other values, if enabled.
|
||||
if (isConnected())
|
||||
mManager.disableBatteryLevelCharacteristicNotifications();
|
||||
@Override
|
||||
protected void onUnbind() {
|
||||
// When we are connected, but the application is not open, we are not really interested in battery level notifications.
|
||||
// But we will still be receiving other values, if enabled.
|
||||
if (isConnected())
|
||||
mManager.disableBatteryLevelCharacteristicNotifications();
|
||||
startForegroundService();
|
||||
}
|
||||
|
||||
// when the activity closes we need to show the notification that user is connected to the sensor
|
||||
createNotification(R.string.csc_notification_connected_message, 0);
|
||||
}
|
||||
@Override
|
||||
public void onDistanceChanged(@NonNull final BluetoothDevice device, final float totalDistance, final float distance, final float speed) {
|
||||
final Intent broadcast = new Intent(BROADCAST_WHEEL_DATA);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_SPEED, speed);
|
||||
broadcast.putExtra(EXTRA_DISTANCE, distance);
|
||||
broadcast.putExtra(EXTRA_TOTAL_DISTANCE, totalDistance);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDistanceChanged(@NonNull final BluetoothDevice device, final float totalDistance, final float distance, final float speed) {
|
||||
final Intent broadcast = new Intent(BROADCAST_WHEEL_DATA);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_SPEED, speed);
|
||||
broadcast.putExtra(EXTRA_DISTANCE, distance);
|
||||
broadcast.putExtra(EXTRA_TOTAL_DISTANCE, totalDistance);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onCrankDataChanged(@NonNull final BluetoothDevice device, final float crankCadence, final float gearRatio) {
|
||||
final Intent broadcast = new Intent(BROADCAST_CRANK_DATA);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_GEAR_RATIO, gearRatio);
|
||||
broadcast.putExtra(EXTRA_CADENCE, (int) crankCadence);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCrankDataChanged(@NonNull final BluetoothDevice device, final float crankCadence, final float gearRatio) {
|
||||
final Intent broadcast = new Intent(BROADCAST_CRANK_DATA);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_GEAR_RATIO, gearRatio);
|
||||
broadcast.putExtra(EXTRA_CADENCE, (int) crankCadence);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
|
||||
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_BATTERY_LEVEL, batteryLevel);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
|
||||
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_BATTERY_LEVEL, batteryLevel);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
/**
|
||||
* Sets the service as a foreground service
|
||||
*/
|
||||
private void startForegroundService(){
|
||||
// when the activity closes we need to show the notification that user is connected to the peripheral sensor
|
||||
// We start the service as a foreground service as Android 8.0 (Oreo) onwards kills any running background services
|
||||
final Notification notification = createNotification(R.string.uart_notification_connected_message, 0);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForeground(NOTIFICATION_ID, notification);
|
||||
} else {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the notification
|
||||
*
|
||||
* @param messageResId
|
||||
* the message resource id. The message must have one String parameter,<br />
|
||||
* f.e. <code><string name="name">%s is connected</string></code>
|
||||
* @param defaults
|
||||
* signals that will be used to notify the user
|
||||
*/
|
||||
private void createNotification(final int messageResId, final int defaults) {
|
||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
final Intent targetIntent = new Intent(this, CSCActivity.class);
|
||||
/**
|
||||
* Stops the service as a foreground service
|
||||
*/
|
||||
private void stopForegroundService(){
|
||||
// when the activity rebinds to the service, remove the notification and stop the foreground service
|
||||
// on devices running Android 8.0 (Oreo) or above
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
stopForeground(true);
|
||||
} else {
|
||||
cancelNotification();
|
||||
}
|
||||
}
|
||||
|
||||
final Intent disconnect = new Intent(ACTION_DISCONNECT);
|
||||
final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
/**
|
||||
* Creates the notification
|
||||
*
|
||||
* @param messageResId the message resource id. The message must have one String parameter,<br />
|
||||
* f.e. <code><string name="name">%s is connected</string></code>
|
||||
* @param defaults
|
||||
*/
|
||||
private Notification createNotification(final int messageResId, final int defaults) {
|
||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
final Intent targetIntent = new Intent(this, CSCActivity.class);
|
||||
|
||||
// both activities above have launchMode="singleTask" in the AndroidManifest.xml file, so if the task is already running, it will be resumed
|
||||
final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[] { parentIntent, targetIntent }, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL);
|
||||
builder.setContentIntent(pendingIntent);
|
||||
builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName()));
|
||||
builder.setSmallIcon(R.drawable.ic_stat_notify_csc);
|
||||
builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true);
|
||||
builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.csc_notification_action_disconnect), disconnectAction));
|
||||
final Intent disconnect = new Intent(ACTION_DISCONNECT);
|
||||
final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
final Notification notification = builder.build();
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
// both activities above have launchMode="singleTask" in the AndroidManifest.xml file, so if the task is already running, it will be resumed
|
||||
final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[]{parentIntent, targetIntent}, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL);
|
||||
builder.setContentIntent(pendingIntent);
|
||||
builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName()));
|
||||
builder.setSmallIcon(R.drawable.ic_stat_notify_csc);
|
||||
builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true);
|
||||
builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.csc_notification_action_disconnect), disconnectAction));
|
||||
|
||||
/**
|
||||
* Cancels the existing notification. If there is no active notification this method does nothing
|
||||
*/
|
||||
private void cancelNotification() {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
|
||||
*/
|
||||
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||
if (isConnected())
|
||||
getBinder().disconnect();
|
||||
else
|
||||
stopSelf();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Cancels the existing notification. If there is no active notification this method does nothing
|
||||
*/
|
||||
private void cancelNotification() {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
|
||||
*/
|
||||
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||
if (isConnected())
|
||||
getBinder().disconnect();
|
||||
else
|
||||
stopSelf();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
@@ -110,14 +112,12 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks
|
||||
|
||||
@Override
|
||||
protected void onRebind() {
|
||||
// when the activity rebinds to the service, remove the notification
|
||||
cancelNotification();
|
||||
stopForegroundService();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUnbind() {
|
||||
// when the activity closes we need to show the notification that user is connected to the sensor
|
||||
createNotification(R.string.hts_notification_connected_message, 0);
|
||||
startForegroundService();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -153,16 +153,42 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the service as a foreground service
|
||||
*/
|
||||
private void startForegroundService(){
|
||||
// when the activity closes we need to show the notification that user is connected to the peripheral sensor
|
||||
// We start the service as a foreground service as Android 8.0 (Oreo) onwards kills any running background services
|
||||
final Notification notification = createNotification(R.string.uart_notification_connected_message, 0);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForeground(NOTIFICATION_ID, notification);
|
||||
} else {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the service as a foreground service
|
||||
*/
|
||||
private void stopForegroundService(){
|
||||
// when the activity rebinds to the service, remove the notification and stop the foreground service
|
||||
// on devices running Android 8.0 (Oreo) or above
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
stopForeground(true);
|
||||
} else {
|
||||
cancelNotification();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the notification
|
||||
*
|
||||
* @param messageResId
|
||||
* @param messageResId
|
||||
* message resource id. The message must have one String parameter,<br />
|
||||
* f.e. <code><string name="name">%s is connected</string></code>
|
||||
* @param defaults
|
||||
* signals that will be used to notify the user
|
||||
*/
|
||||
private void createNotification(final int messageResId, final int defaults) {
|
||||
private Notification createNotification(final int messageResId, final int defaults) {
|
||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
final Intent targetIntent = new Intent(this, HTSActivity.class);
|
||||
@@ -179,9 +205,7 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks
|
||||
builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true);
|
||||
builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.hts_notification_action_disconnect), disconnectAction));
|
||||
|
||||
final Notification notification = builder.build();
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(NOTIFICATION_ID, notification);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -30,12 +30,13 @@ 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 androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import no.nordicsemi.android.log.Logger;
|
||||
import no.nordicsemi.android.nrftoolbox.FeaturesActivity;
|
||||
import no.nordicsemi.android.nrftoolbox.R;
|
||||
@@ -44,209 +45,239 @@ import no.nordicsemi.android.nrftoolbox.profile.BleProfileService;
|
||||
import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager;
|
||||
|
||||
public class RSCService extends BleProfileService implements RSCManagerCallbacks {
|
||||
private static final String TAG = "RSCService";
|
||||
private static final String TAG = "RSCService";
|
||||
|
||||
public static final String BROADCAST_RSC_MEASUREMENT = "no.nordicsemi.android.nrftoolbox.rsc.BROADCAST_RSC_MEASUREMENT";
|
||||
public static final String EXTRA_SPEED = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_SPEED";
|
||||
public static final String EXTRA_CADENCE = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_CADENCE";
|
||||
public static final String EXTRA_STRIDE_LENGTH = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_STRIDE_LENGTH";
|
||||
public static final String EXTRA_TOTAL_DISTANCE = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_TOTAL_DISTANCE";
|
||||
public static final String EXTRA_ACTIVITY = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_ACTIVITY";
|
||||
public static final String BROADCAST_RSC_MEASUREMENT = "no.nordicsemi.android.nrftoolbox.rsc.BROADCAST_RSC_MEASUREMENT";
|
||||
public static final String EXTRA_SPEED = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_SPEED";
|
||||
public static final String EXTRA_CADENCE = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_CADENCE";
|
||||
public static final String EXTRA_STRIDE_LENGTH = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_STRIDE_LENGTH";
|
||||
public static final String EXTRA_TOTAL_DISTANCE = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_TOTAL_DISTANCE";
|
||||
public static final String EXTRA_ACTIVITY = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_ACTIVITY";
|
||||
|
||||
public static final String BROADCAST_STRIDES_UPDATE = "no.nordicsemi.android.nrftoolbox.rsc.BROADCAST_STRIDES_UPDATE";
|
||||
public static final String EXTRA_STRIDES = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_STRIDES";
|
||||
public static final String EXTRA_DISTANCE = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_DISTANCE";
|
||||
public static final String BROADCAST_STRIDES_UPDATE = "no.nordicsemi.android.nrftoolbox.rsc.BROADCAST_STRIDES_UPDATE";
|
||||
public static final String EXTRA_STRIDES = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_STRIDES";
|
||||
public static final String EXTRA_DISTANCE = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_DISTANCE";
|
||||
|
||||
public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL";
|
||||
public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL";
|
||||
public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL";
|
||||
public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL";
|
||||
|
||||
private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.rsc.ACTION_DISCONNECT";
|
||||
private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.rsc.ACTION_DISCONNECT";
|
||||
|
||||
private RSCManager mManager;
|
||||
private RSCManager mManager;
|
||||
|
||||
/** The last value of a cadence */
|
||||
private float mCadence;
|
||||
/** Trip distance in cm */
|
||||
private long mDistance;
|
||||
/** Stride length in cm */
|
||||
private Integer mStrideLength;
|
||||
/** Number of steps in the trip */
|
||||
private int mStepsNumber;
|
||||
private boolean mTaskInProgress;
|
||||
private final Handler mHandler = new Handler();
|
||||
/**
|
||||
* The last value of a cadence
|
||||
*/
|
||||
private float mCadence;
|
||||
/**
|
||||
* Trip distance in cm
|
||||
*/
|
||||
private long mDistance;
|
||||
/**
|
||||
* Stride length in cm
|
||||
*/
|
||||
private Integer mStrideLength;
|
||||
/**
|
||||
* Number of steps in the trip
|
||||
*/
|
||||
private int mStepsNumber;
|
||||
private boolean mTaskInProgress;
|
||||
private final Handler mHandler = new Handler();
|
||||
|
||||
private final static int NOTIFICATION_ID = 200;
|
||||
private final static int OPEN_ACTIVITY_REQ = 0;
|
||||
private final static int DISCONNECT_REQ = 1;
|
||||
private final static int NOTIFICATION_ID = 200;
|
||||
private final static int OPEN_ACTIVITY_REQ = 0;
|
||||
private final static int DISCONNECT_REQ = 1;
|
||||
|
||||
private final LocalBinder mBinder = new RSCBinder();
|
||||
private final LocalBinder mBinder = new RSCBinder();
|
||||
|
||||
/**
|
||||
* This local binder is an interface for the bound activity to operate with the RSC sensor.
|
||||
*/
|
||||
class RSCBinder extends LocalBinder {
|
||||
// empty
|
||||
}
|
||||
/**
|
||||
* This local binder is an interface for the bound activity to operate with the RSC sensor.
|
||||
*/
|
||||
class RSCBinder extends LocalBinder {
|
||||
// empty
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalBinder getBinder() {
|
||||
return mBinder;
|
||||
}
|
||||
@Override
|
||||
protected LocalBinder getBinder() {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LoggableBleManager<RSCManagerCallbacks> initializeManager() {
|
||||
return mManager = new RSCManager(this);
|
||||
}
|
||||
@Override
|
||||
protected LoggableBleManager<RSCManagerCallbacks> initializeManager() {
|
||||
return mManager = new RSCManager(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ACTION_DISCONNECT);
|
||||
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
|
||||
}
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ACTION_DISCONNECT);
|
||||
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||
cancelNotification();
|
||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||
stopForegroundService();
|
||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRebind() {
|
||||
// when the activity rebinds to the service, remove the notification
|
||||
cancelNotification();
|
||||
@Override
|
||||
protected void onRebind() {
|
||||
stopForegroundService();
|
||||
|
||||
if (isConnected()) {
|
||||
// This method will read the Battery Level value, if possible and then try to enable battery notifications (if it has NOTIFY property).
|
||||
// If the Battery Level characteristic has only the NOTIFY property, it will only try to enable notifications.
|
||||
mManager.readBatteryLevelCharacteristic();
|
||||
}
|
||||
}
|
||||
if (isConnected()) {
|
||||
// This method will read the Battery Level value, if possible and then try to enable battery notifications (if it has NOTIFY property).
|
||||
// If the Battery Level characteristic has only the NOTIFY property, it will only try to enable notifications.
|
||||
mManager.readBatteryLevelCharacteristic();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUnbind() {
|
||||
// When we are connected, but the application is not open, we are not really interested in battery level notifications.
|
||||
// But we will still be receiving other values, if enabled.
|
||||
if (isConnected())
|
||||
mManager.disableBatteryLevelCharacteristicNotifications();
|
||||
@Override
|
||||
protected void onUnbind() {
|
||||
// When we are connected, but the application is not open, we are not really interested in battery level notifications.
|
||||
// But we will still be receiving other values, if enabled.
|
||||
if (isConnected())
|
||||
mManager.disableBatteryLevelCharacteristicNotifications();
|
||||
|
||||
// when the activity closes we need to show the notification that user is connected to the sensor
|
||||
createNotification(R.string.rsc_notification_connected_message, 0);
|
||||
}
|
||||
startForegroundService();
|
||||
}
|
||||
|
||||
private final Runnable mUpdateStridesTask = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!isConnected())
|
||||
return;
|
||||
private final Runnable mUpdateStridesTask = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!isConnected())
|
||||
return;
|
||||
|
||||
mStepsNumber++;
|
||||
mDistance += mStrideLength; // [cm]
|
||||
final Intent broadcast = new Intent(BROADCAST_STRIDES_UPDATE);
|
||||
broadcast.putExtra(EXTRA_STRIDES, mStepsNumber);
|
||||
broadcast.putExtra(EXTRA_DISTANCE, mDistance);
|
||||
LocalBroadcastManager.getInstance(RSCService.this).sendBroadcast(broadcast);
|
||||
mStepsNumber++;
|
||||
mDistance += mStrideLength; // [cm]
|
||||
final Intent broadcast = new Intent(BROADCAST_STRIDES_UPDATE);
|
||||
broadcast.putExtra(EXTRA_STRIDES, mStepsNumber);
|
||||
broadcast.putExtra(EXTRA_DISTANCE, mDistance);
|
||||
LocalBroadcastManager.getInstance(RSCService.this).sendBroadcast(broadcast);
|
||||
|
||||
if (mCadence > 0) {
|
||||
final long interval = (long) (1000.0f * 60.0f / mCadence);
|
||||
mHandler.postDelayed(mUpdateStridesTask, interval);
|
||||
} else {
|
||||
mTaskInProgress = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
if (mCadence > 0) {
|
||||
final long interval = (long) (1000.0f * 60.0f / mCadence);
|
||||
mHandler.postDelayed(mUpdateStridesTask, interval);
|
||||
} else {
|
||||
mTaskInProgress = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onRSCMeasurementReceived(@NonNull final BluetoothDevice device, final boolean running,
|
||||
final float instantaneousSpeed, final int instantaneousCadence,
|
||||
@Nullable final Integer strideLength,
|
||||
@Nullable final Long totalDistance) {
|
||||
final Intent broadcast = new Intent(BROADCAST_RSC_MEASUREMENT);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_SPEED, instantaneousSpeed);
|
||||
broadcast.putExtra(EXTRA_CADENCE, instantaneousCadence);
|
||||
broadcast.putExtra(EXTRA_STRIDE_LENGTH, strideLength);
|
||||
broadcast.putExtra(EXTRA_TOTAL_DISTANCE, totalDistance);
|
||||
broadcast.putExtra(EXTRA_ACTIVITY, running);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
@Override
|
||||
public void onRSCMeasurementReceived(@NonNull final BluetoothDevice device, final boolean running,
|
||||
final float instantaneousSpeed, final int instantaneousCadence,
|
||||
@Nullable final Integer strideLength,
|
||||
@Nullable final Long totalDistance) {
|
||||
final Intent broadcast = new Intent(BROADCAST_RSC_MEASUREMENT);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_SPEED, instantaneousSpeed);
|
||||
broadcast.putExtra(EXTRA_CADENCE, instantaneousCadence);
|
||||
broadcast.putExtra(EXTRA_STRIDE_LENGTH, strideLength);
|
||||
broadcast.putExtra(EXTRA_TOTAL_DISTANCE, totalDistance);
|
||||
broadcast.putExtra(EXTRA_ACTIVITY, running);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
|
||||
// Start strides counter if not in progress
|
||||
mCadence = instantaneousCadence;
|
||||
if (strideLength != null) {
|
||||
mStrideLength = strideLength;
|
||||
}
|
||||
if (!mTaskInProgress && strideLength != null && instantaneousCadence > 0) {
|
||||
mTaskInProgress = true;
|
||||
// Start strides counter if not in progress
|
||||
mCadence = instantaneousCadence;
|
||||
if (strideLength != null) {
|
||||
mStrideLength = strideLength;
|
||||
}
|
||||
if (!mTaskInProgress && strideLength != null && instantaneousCadence > 0) {
|
||||
mTaskInProgress = true;
|
||||
|
||||
final long interval = (long) (1000.0f * 60.0f / mCadence);
|
||||
mHandler.postDelayed(mUpdateStridesTask, interval);
|
||||
}
|
||||
}
|
||||
final long interval = (long) (1000.0f * 60.0f / mCadence);
|
||||
mHandler.postDelayed(mUpdateStridesTask, interval);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) {
|
||||
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_BATTERY_LEVEL, value);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) {
|
||||
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_BATTERY_LEVEL, value);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the notification
|
||||
*
|
||||
* @param messageResId
|
||||
* message resource id. The message must have one String parameter,<br />
|
||||
* f.e. <code><string name="name">%s is connected</string></code>
|
||||
* @param defaults
|
||||
* signals that will be used to notify the user
|
||||
*/
|
||||
private void createNotification(final int messageResId, final int defaults) {
|
||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
final Intent targetIntent = new Intent(this, RSCActivity.class);
|
||||
/**
|
||||
* Sets the service as a foreground service
|
||||
*/
|
||||
private void startForegroundService(){
|
||||
// when the activity closes we need to show the notification that user is connected to the peripheral sensor
|
||||
// We start the service as a foreground service as Android 8.0 (Oreo) onwards kills any running background services
|
||||
final Notification notification = createNotification(R.string.uart_notification_connected_message, 0);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForeground(NOTIFICATION_ID, notification);
|
||||
} else {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
}
|
||||
|
||||
final Intent disconnect = new Intent(ACTION_DISCONNECT);
|
||||
final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
/**
|
||||
* Stops the service as a foreground service
|
||||
*/
|
||||
private void stopForegroundService(){
|
||||
// when the activity rebinds to the service, remove the notification and stop the foreground service
|
||||
// on devices running Android 8.0 (Oreo) or above
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
stopForeground(true);
|
||||
} else {
|
||||
cancelNotification();
|
||||
}
|
||||
}
|
||||
|
||||
// both activities above have launchMode="singleTask" in the AndroidManifest.xml file, so if the task is already running, it will be resumed
|
||||
final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[] { parentIntent, targetIntent }, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL);
|
||||
builder.setContentIntent(pendingIntent);
|
||||
builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName()));
|
||||
builder.setSmallIcon(R.drawable.ic_stat_notify_rsc);
|
||||
builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true);
|
||||
builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.rsc_notification_action_disconnect), disconnectAction));
|
||||
/**
|
||||
* Creates the notification
|
||||
*
|
||||
* @param messageResId message resource id. The message must have one String parameter,<br />
|
||||
* f.e. <code><string name="name">%s is connected</string></code>
|
||||
* @param defaults
|
||||
*/
|
||||
private Notification createNotification(final int messageResId, final int defaults) {
|
||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
final Intent targetIntent = new Intent(this, RSCActivity.class);
|
||||
|
||||
final Notification notification = builder.build();
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
final Intent disconnect = new Intent(ACTION_DISCONNECT);
|
||||
final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
/**
|
||||
* Cancels the existing notification. If there is no active notification this method does nothing
|
||||
*/
|
||||
private void cancelNotification() {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
// both activities above have launchMode="singleTask" in the AndroidManifest.xml file, so if the task is already running, it will be resumed
|
||||
final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[]{parentIntent, targetIntent}, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL);
|
||||
builder.setContentIntent(pendingIntent);
|
||||
builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName()));
|
||||
builder.setSmallIcon(R.drawable.ic_stat_notify_rsc);
|
||||
builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true);
|
||||
builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.rsc_notification_action_disconnect), disconnectAction));
|
||||
|
||||
/**
|
||||
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
|
||||
*/
|
||||
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||
if (isConnected())
|
||||
getBinder().disconnect();
|
||||
else
|
||||
stopSelf();
|
||||
}
|
||||
};
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the existing notification. If there is no active notification this method does nothing
|
||||
*/
|
||||
private void cancelNotification() {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
|
||||
*/
|
||||
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||
if (isConnected())
|
||||
getBinder().disconnect();
|
||||
else
|
||||
stopSelf();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -30,10 +30,11 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import no.nordicsemi.android.log.Logger;
|
||||
import no.nordicsemi.android.nrftoolbox.FeaturesActivity;
|
||||
import no.nordicsemi.android.nrftoolbox.R;
|
||||
@@ -42,144 +43,168 @@ import no.nordicsemi.android.nrftoolbox.profile.BleProfileService;
|
||||
import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager;
|
||||
|
||||
public class TemplateService extends BleProfileService implements TemplateManagerCallbacks {
|
||||
public static final String BROADCAST_TEMPLATE_MEASUREMENT = "no.nordicsemi.android.nrftoolbox.template.BROADCAST_MEASUREMENT";
|
||||
public static final String EXTRA_DATA = "no.nordicsemi.android.nrftoolbox.template.EXTRA_DATA";
|
||||
public static final String BROADCAST_TEMPLATE_MEASUREMENT = "no.nordicsemi.android.nrftoolbox.template.BROADCAST_MEASUREMENT";
|
||||
public static final String EXTRA_DATA = "no.nordicsemi.android.nrftoolbox.template.EXTRA_DATA";
|
||||
|
||||
public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL";
|
||||
public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL";
|
||||
public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL";
|
||||
public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL";
|
||||
|
||||
private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.template.ACTION_DISCONNECT";
|
||||
private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.template.ACTION_DISCONNECT";
|
||||
|
||||
private final static int NOTIFICATION_ID = 864;
|
||||
private final static int OPEN_ACTIVITY_REQ = 0;
|
||||
private final static int DISCONNECT_REQ = 1;
|
||||
private final static int NOTIFICATION_ID = 864;
|
||||
private final static int OPEN_ACTIVITY_REQ = 0;
|
||||
private final static int DISCONNECT_REQ = 1;
|
||||
|
||||
private TemplateManager mManager;
|
||||
private TemplateManager mManager;
|
||||
|
||||
private final LocalBinder mBinder = new TemplateBinder();
|
||||
private final LocalBinder mBinder = new TemplateBinder();
|
||||
|
||||
/**
|
||||
* This local binder is an interface for the bound activity to operate with the sensor.
|
||||
*/
|
||||
class TemplateBinder extends LocalBinder {
|
||||
// TODO Define service API that may be used by a bound Activity
|
||||
/**
|
||||
* This local binder is an interface for the bound activity to operate with the sensor.
|
||||
*/
|
||||
class TemplateBinder extends LocalBinder {
|
||||
// TODO Define service API that may be used by a bound Activity
|
||||
|
||||
/**
|
||||
* Sends some important data to the device.
|
||||
*
|
||||
* @param parameter some parameter.
|
||||
*/
|
||||
public void performAction(final String parameter) {
|
||||
mManager.performAction(parameter);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sends some important data to the device.
|
||||
*
|
||||
* @param parameter some parameter.
|
||||
*/
|
||||
public void performAction(final String parameter) {
|
||||
mManager.performAction(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalBinder getBinder() {
|
||||
return mBinder;
|
||||
}
|
||||
@Override
|
||||
protected LocalBinder getBinder() {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LoggableBleManager<TemplateManagerCallbacks> initializeManager() {
|
||||
return mManager = new TemplateManager(this);
|
||||
}
|
||||
@Override
|
||||
protected LoggableBleManager<TemplateManagerCallbacks> initializeManager() {
|
||||
return mManager = new TemplateManager(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ACTION_DISCONNECT);
|
||||
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
|
||||
}
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ACTION_DISCONNECT);
|
||||
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||
cancelNotification();
|
||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||
stopForegroundService();
|
||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRebind() {
|
||||
// when the activity rebinds to the service, remove the notification
|
||||
cancelNotification();
|
||||
}
|
||||
@Override
|
||||
protected void onRebind() {
|
||||
stopForegroundService();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUnbind() {
|
||||
// when the activity closes we need to show the notification that user is connected to the sensor
|
||||
createNotification(R.string.template_notification_connected_message, 0);
|
||||
}
|
||||
@Override
|
||||
protected void onUnbind() {
|
||||
startForegroundService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) {
|
||||
final Intent broadcast = new Intent(BROADCAST_TEMPLATE_MEASUREMENT);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, value);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
@Override
|
||||
public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) {
|
||||
final Intent broadcast = new Intent(BROADCAST_TEMPLATE_MEASUREMENT);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, value);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
|
||||
if (!mBound) {
|
||||
// Here we may update the notification to display the current value.
|
||||
// TODO modify the notification here
|
||||
}
|
||||
}
|
||||
if (!mBound) {
|
||||
// Here we may update the notification to display the current value.
|
||||
// TODO modify the notification here
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
|
||||
@Override
|
||||
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the notification.
|
||||
*
|
||||
* @param messageResId message resource id. The message must have one String parameter,<br />
|
||||
* f.e. <code><string name="name">%s is connected</string></code>
|
||||
* @param defaults signals that will be used to notify the user
|
||||
*/
|
||||
private void createNotification(final int messageResId, final int defaults) {
|
||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
final Intent targetIntent = new Intent(this, TemplateActivity.class);
|
||||
/**
|
||||
* Sets the service as a foreground service
|
||||
*/
|
||||
private void startForegroundService(){
|
||||
// when the activity closes we need to show the notification that user is connected to the peripheral sensor
|
||||
// We start the service as a foreground service as Android 8.0 (Oreo) onwards kills any running background services
|
||||
final Notification notification = createNotification(R.string.uart_notification_connected_message, 0);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForeground(NOTIFICATION_ID, notification);
|
||||
} else {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
}
|
||||
|
||||
final Intent disconnect = new Intent(ACTION_DISCONNECT);
|
||||
final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
/**
|
||||
* Stops the service as a foreground service
|
||||
*/
|
||||
private void stopForegroundService(){
|
||||
// when the activity rebinds to the service, remove the notification and stop the foreground service
|
||||
// on devices running Android 8.0 (Oreo) or above
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
stopForeground(true);
|
||||
} else {
|
||||
cancelNotification();
|
||||
}
|
||||
}
|
||||
|
||||
// both activities above have launchMode="singleTask" in the AndroidManifest.xml file, so if the task is already running, it will be resumed
|
||||
final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[]{parentIntent, targetIntent}, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL);
|
||||
builder.setContentIntent(pendingIntent);
|
||||
builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName()));
|
||||
builder.setSmallIcon(R.drawable.ic_stat_notify_template);
|
||||
builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true);
|
||||
builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.template_notification_action_disconnect), disconnectAction));
|
||||
/**
|
||||
* Creates the notification.
|
||||
*
|
||||
* @param messageResId message resource id. The message must have one String parameter,<br />
|
||||
* f.e. <code><string name="name">%s is connected</string></code>
|
||||
* @param defaults signals that will be used to notify the user
|
||||
*/
|
||||
private Notification createNotification(final int messageResId, final int defaults) {
|
||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
final Intent targetIntent = new Intent(this, TemplateActivity.class);
|
||||
|
||||
final Notification notification = builder.build();
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
final Intent disconnect = new Intent(ACTION_DISCONNECT);
|
||||
final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
/**
|
||||
* Cancels the existing notification. If there is no active notification this method does nothing
|
||||
*/
|
||||
private void cancelNotification() {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
// both activities above have launchMode="singleTask" in the AndroidManifest.xml file, so if the task is already running, it will be resumed
|
||||
final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[]{parentIntent, targetIntent}, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL);
|
||||
builder.setContentIntent(pendingIntent);
|
||||
builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName()));
|
||||
builder.setSmallIcon(R.drawable.ic_stat_notify_template);
|
||||
builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true);
|
||||
builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.template_notification_action_disconnect), disconnectAction));
|
||||
|
||||
/**
|
||||
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
|
||||
*/
|
||||
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||
if (isConnected())
|
||||
getBinder().disconnect();
|
||||
else
|
||||
stopSelf();
|
||||
}
|
||||
};
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the existing notification. If there is no active notification this method does nothing
|
||||
*/
|
||||
private void cancelNotification() {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
|
||||
*/
|
||||
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||
if (isConnected())
|
||||
getBinder().disconnect();
|
||||
else
|
||||
stopSelf();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -30,9 +30,7 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -42,6 +40,9 @@ import com.google.android.gms.wearable.Node;
|
||||
import com.google.android.gms.wearable.NodeApi;
|
||||
import com.google.android.gms.wearable.Wearable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import no.nordicsemi.android.log.Logger;
|
||||
import no.nordicsemi.android.nrftoolbox.FeaturesActivity;
|
||||
import no.nordicsemi.android.nrftoolbox.R;
|
||||
@@ -51,269 +52,300 @@ import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager;
|
||||
import no.nordicsemi.android.nrftoolbox.wearable.common.Constants;
|
||||
|
||||
public class UARTService extends BleProfileService implements UARTManagerCallbacks {
|
||||
private static final String TAG = "UARTService";
|
||||
private static final String TAG = "UARTService";
|
||||
|
||||
public static final String BROADCAST_UART_TX = "no.nordicsemi.android.nrftoolbox.uart.BROADCAST_UART_TX";
|
||||
public static final String BROADCAST_UART_RX = "no.nordicsemi.android.nrftoolbox.uart.BROADCAST_UART_RX";
|
||||
public static final String EXTRA_DATA = "no.nordicsemi.android.nrftoolbox.uart.EXTRA_DATA";
|
||||
public static final String BROADCAST_UART_TX = "no.nordicsemi.android.nrftoolbox.uart.BROADCAST_UART_TX";
|
||||
public static final String BROADCAST_UART_RX = "no.nordicsemi.android.nrftoolbox.uart.BROADCAST_UART_RX";
|
||||
public static final String EXTRA_DATA = "no.nordicsemi.android.nrftoolbox.uart.EXTRA_DATA";
|
||||
|
||||
/** A broadcast message with this action and the message in {@link Intent#EXTRA_TEXT} will be sent t the UART device. */
|
||||
public final static String ACTION_SEND = "no.nordicsemi.android.nrftoolbox.uart.ACTION_SEND";
|
||||
/** A broadcast message with this action is triggered when a message is received from the UART device. */
|
||||
private final static String ACTION_RECEIVE = "no.nordicsemi.android.nrftoolbox.uart.ACTION_RECEIVE";
|
||||
/** Action send when user press the DISCONNECT button on the notification. */
|
||||
public final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.uart.ACTION_DISCONNECT";
|
||||
/** A source of an action. */
|
||||
public final static String EXTRA_SOURCE = "no.nordicsemi.android.nrftoolbox.uart.EXTRA_SOURCE";
|
||||
public final static int SOURCE_NOTIFICATION = 0;
|
||||
public final static int SOURCE_WEARABLE = 1;
|
||||
public final static int SOURCE_3RD_PARTY = 2;
|
||||
/**
|
||||
* A broadcast message with this action and the message in {@link Intent#EXTRA_TEXT} will be sent t the UART device.
|
||||
*/
|
||||
public final static String ACTION_SEND = "no.nordicsemi.android.nrftoolbox.uart.ACTION_SEND";
|
||||
/**
|
||||
* A broadcast message with this action is triggered when a message is received from the UART device.
|
||||
*/
|
||||
private final static String ACTION_RECEIVE = "no.nordicsemi.android.nrftoolbox.uart.ACTION_RECEIVE";
|
||||
/**
|
||||
* Action send when user press the DISCONNECT button on the notification.
|
||||
*/
|
||||
public final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.uart.ACTION_DISCONNECT";
|
||||
/**
|
||||
* A source of an action.
|
||||
*/
|
||||
public final static String EXTRA_SOURCE = "no.nordicsemi.android.nrftoolbox.uart.EXTRA_SOURCE";
|
||||
public final static int SOURCE_NOTIFICATION = 0;
|
||||
public final static int SOURCE_WEARABLE = 1;
|
||||
public final static int SOURCE_3RD_PARTY = 2;
|
||||
|
||||
private final static int NOTIFICATION_ID = 349; // random
|
||||
private final static int OPEN_ACTIVITY_REQ = 67; // random
|
||||
private final static int DISCONNECT_REQ = 97; // random
|
||||
private final static int NOTIFICATION_ID = 349; // random
|
||||
private final static int OPEN_ACTIVITY_REQ = 67; // random
|
||||
private final static int DISCONNECT_REQ = 97; // random
|
||||
|
||||
private GoogleApiClient mGoogleApiClient;
|
||||
private UARTManager mManager;
|
||||
private GoogleApiClient mGoogleApiClient;
|
||||
private UARTManager mManager;
|
||||
|
||||
private final LocalBinder mBinder = new UARTBinder();
|
||||
private final LocalBinder mBinder = new UARTBinder();
|
||||
|
||||
public class UARTBinder extends LocalBinder implements UARTInterface {
|
||||
@Override
|
||||
public void send(final String text) {
|
||||
mManager.send(text);
|
||||
}
|
||||
}
|
||||
public class UARTBinder extends LocalBinder implements UARTInterface {
|
||||
@Override
|
||||
public void send(final String text) {
|
||||
mManager.send(text);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalBinder getBinder() {
|
||||
return mBinder;
|
||||
}
|
||||
@Override
|
||||
protected LocalBinder getBinder() {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LoggableBleManager<UARTManagerCallbacks> initializeManager() {
|
||||
return mManager = new UARTManager(this);
|
||||
}
|
||||
@Override
|
||||
protected LoggableBleManager<UARTManagerCallbacks> initializeManager() {
|
||||
return mManager = new UARTManager(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldAutoConnect() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
protected boolean shouldAutoConnect() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
registerReceiver(mDisconnectActionBroadcastReceiver, new IntentFilter(ACTION_DISCONNECT));
|
||||
registerReceiver(mIntentBroadcastReceiver, new IntentFilter(ACTION_SEND));
|
||||
registerReceiver(mDisconnectActionBroadcastReceiver, new IntentFilter(ACTION_DISCONNECT));
|
||||
registerReceiver(mIntentBroadcastReceiver, new IntentFilter(ACTION_SEND));
|
||||
|
||||
mGoogleApiClient = new GoogleApiClient.Builder(this)
|
||||
.addApi(Wearable.API)
|
||||
.build();
|
||||
mGoogleApiClient.connect();
|
||||
}
|
||||
mGoogleApiClient = new GoogleApiClient.Builder(this)
|
||||
.addApi(Wearable.API)
|
||||
.build();
|
||||
mGoogleApiClient.connect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||
cancelNotification();
|
||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
||||
unregisterReceiver(mIntentBroadcastReceiver);
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||
stopForegroundService();
|
||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
||||
unregisterReceiver(mIntentBroadcastReceiver);
|
||||
|
||||
mGoogleApiClient.disconnect();
|
||||
mGoogleApiClient.disconnect();
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRebind() {
|
||||
// when the activity rebinds to the service, remove the notification
|
||||
cancelNotification();
|
||||
}
|
||||
@Override
|
||||
protected void onRebind() {
|
||||
stopForegroundService();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUnbind() {
|
||||
// when the activity closes we need to show the notification that user is connected to the sensor
|
||||
createNotification(R.string.uart_notification_connected_message, 0);
|
||||
}
|
||||
@Override
|
||||
protected void onUnbind() {
|
||||
startForegroundService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
|
||||
super.onDeviceConnected(device);
|
||||
sendMessageToWearables(Constants.UART.DEVICE_CONNECTED, notNull(getDeviceName()));
|
||||
}
|
||||
@Override
|
||||
public void onDeviceConnected(@NonNull final BluetoothDevice device) {
|
||||
super.onDeviceConnected(device);
|
||||
sendMessageToWearables(Constants.UART.DEVICE_CONNECTED, notNull(getDeviceName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean stopWhenDisconnected() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
protected boolean stopWhenDisconnected() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
||||
super.onDeviceDisconnected(device);
|
||||
sendMessageToWearables(Constants.UART.DEVICE_DISCONNECTED, notNull(getDeviceName()));
|
||||
}
|
||||
@Override
|
||||
public void onDeviceDisconnected(@NonNull final BluetoothDevice device) {
|
||||
super.onDeviceDisconnected(device);
|
||||
sendMessageToWearables(Constants.UART.DEVICE_DISCONNECTED, notNull(getDeviceName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
|
||||
super.onLinkLossOccurred(device);
|
||||
sendMessageToWearables(Constants.UART.DEVICE_LINKLOSS, notNull(getDeviceName()));
|
||||
}
|
||||
@Override
|
||||
public void onLinkLossOccurred(@NonNull final BluetoothDevice device) {
|
||||
super.onLinkLossOccurred(device);
|
||||
sendMessageToWearables(Constants.UART.DEVICE_LINKLOSS, notNull(getDeviceName()));
|
||||
}
|
||||
|
||||
private String notNull(final String name) {
|
||||
if (!TextUtils.isEmpty(name))
|
||||
return name;
|
||||
return getString(R.string.not_available);
|
||||
}
|
||||
private String notNull(final String name) {
|
||||
if (!TextUtils.isEmpty(name))
|
||||
return name;
|
||||
return getString(R.string.not_available);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataReceived(final BluetoothDevice device, final String data) {
|
||||
final Intent broadcast = new Intent(BROADCAST_UART_RX);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, data);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
@Override
|
||||
public void onDataReceived(final BluetoothDevice device, final String data) {
|
||||
final Intent broadcast = new Intent(BROADCAST_UART_RX);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, data);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
|
||||
// send the data received to other apps, e.g. the Tasker
|
||||
final Intent globalBroadcast = new Intent(ACTION_RECEIVE);
|
||||
globalBroadcast.putExtra(BluetoothDevice.EXTRA_DEVICE, getBluetoothDevice());
|
||||
globalBroadcast.putExtra(Intent.EXTRA_TEXT, data);
|
||||
sendBroadcast(globalBroadcast);
|
||||
}
|
||||
// send the data received to other apps, e.g. the Tasker
|
||||
final Intent globalBroadcast = new Intent(ACTION_RECEIVE);
|
||||
globalBroadcast.putExtra(BluetoothDevice.EXTRA_DEVICE, getBluetoothDevice());
|
||||
globalBroadcast.putExtra(Intent.EXTRA_TEXT, data);
|
||||
sendBroadcast(globalBroadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataSent(final BluetoothDevice device, final String data) {
|
||||
final Intent broadcast = new Intent(BROADCAST_UART_TX);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, data);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onDataSent(final BluetoothDevice device, final String data) {
|
||||
final Intent broadcast = new Intent(BROADCAST_UART_TX);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, data);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the given message to all connected wearables. If the path is equal to {@link Constants.UART#DEVICE_DISCONNECTED} the service will be stopped afterwards.
|
||||
* @param path message path
|
||||
* @param message the message
|
||||
*/
|
||||
private void sendMessageToWearables(final @NonNull String path, final @NonNull String message) {
|
||||
if(mGoogleApiClient.isConnected()) {
|
||||
new Thread(() -> {
|
||||
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();
|
||||
for(Node node : nodes.getNodes()) {
|
||||
Logger.v(getLogSession(), "[WEAR] Sending message '" + path + "' to " + node.getDisplayName());
|
||||
final MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(mGoogleApiClient, node.getId(), path, message.getBytes()).await();
|
||||
if(result.getStatus().isSuccess()){
|
||||
Logger.i(getLogSession(), "[WEAR] Message sent");
|
||||
} else {
|
||||
Logger.w(getLogSession(), "[WEAR] Sending message failed: " + result.getStatus().getStatusMessage());
|
||||
Log.w(TAG, "Failed to send " + path + " to " + node.getDisplayName());
|
||||
}
|
||||
}
|
||||
if (Constants.UART.DEVICE_DISCONNECTED.equals(path))
|
||||
stopService();
|
||||
}).start();
|
||||
} else {
|
||||
if (Constants.UART.DEVICE_DISCONNECTED.equals(path))
|
||||
stopService();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sends the given message to all connected wearables. If the path is equal to {@link Constants.UART#DEVICE_DISCONNECTED} the service will be stopped afterwards.
|
||||
*
|
||||
* @param path message path
|
||||
* @param message the message
|
||||
*/
|
||||
private void sendMessageToWearables(final @NonNull String path, final @NonNull String message) {
|
||||
if (mGoogleApiClient.isConnected()) {
|
||||
new Thread(() -> {
|
||||
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();
|
||||
for (Node node : nodes.getNodes()) {
|
||||
Logger.v(getLogSession(), "[WEAR] Sending message '" + path + "' to " + node.getDisplayName());
|
||||
final MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(mGoogleApiClient, node.getId(), path, message.getBytes()).await();
|
||||
if (result.getStatus().isSuccess()) {
|
||||
Logger.i(getLogSession(), "[WEAR] Message sent");
|
||||
} else {
|
||||
Logger.w(getLogSession(), "[WEAR] Sending message failed: " + result.getStatus().getStatusMessage());
|
||||
Log.w(TAG, "Failed to send " + path + " to " + node.getDisplayName());
|
||||
}
|
||||
}
|
||||
if (Constants.UART.DEVICE_DISCONNECTED.equals(path))
|
||||
stopService();
|
||||
}).start();
|
||||
} else {
|
||||
if (Constants.UART.DEVICE_DISCONNECTED.equals(path))
|
||||
stopService();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the notification
|
||||
*
|
||||
* @param messageResId
|
||||
* message resource id. The message must have one String parameter,<br />
|
||||
* f.e. <code><string name="name">%s is connected</string></code>
|
||||
* @param defaults
|
||||
* signals that will be used to notify the user
|
||||
*/
|
||||
private void createNotification(final int messageResId, final int defaults) {
|
||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
final Intent targetIntent = new Intent(this, UARTActivity.class);
|
||||
/**
|
||||
* Sets the service as a foreground service
|
||||
*/
|
||||
private void startForegroundService() {
|
||||
// when the activity closes we need to show the notification that user is connected to the peripheral sensor
|
||||
// We start the service as a foreground service as Android 8.0 (Oreo) onwards kills any running background services
|
||||
final Notification notification = createNotification(R.string.uart_notification_connected_message, 0);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForeground(NOTIFICATION_ID, notification);
|
||||
} else {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
}
|
||||
|
||||
final Intent disconnect = new Intent(ACTION_DISCONNECT);
|
||||
disconnect.putExtra(EXTRA_SOURCE, SOURCE_NOTIFICATION);
|
||||
final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
/**
|
||||
* Stops the service as a foreground service
|
||||
*/
|
||||
private void stopForegroundService() {
|
||||
// when the activity rebinds to the service, remove the notification and stop the foreground service
|
||||
// on devices running Android 8.0 (Oreo) or above
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
stopForeground(true);
|
||||
} else {
|
||||
cancelNotification();
|
||||
}
|
||||
}
|
||||
|
||||
// both activities above have launchMode="singleTask" in the AndroidManifest.xml file, so if the task is already running, it will be resumed
|
||||
final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[] { parentIntent, targetIntent }, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL);
|
||||
builder.setContentIntent(pendingIntent);
|
||||
builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName()));
|
||||
builder.setSmallIcon(R.drawable.ic_stat_notify_uart);
|
||||
builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true);
|
||||
builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.uart_notification_action_disconnect), disconnectAction));
|
||||
/**
|
||||
* Creates the notification
|
||||
*
|
||||
* @param messageResId message resource id. The message must have one String parameter,<br />
|
||||
* f.e. <code><string name="name">%s is connected</string></code>
|
||||
* @param defaults signals that will be used to notify the user
|
||||
*/
|
||||
protected Notification createNotification(final int messageResId, final int defaults) {
|
||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
final Intent targetIntent = new Intent(this, UARTActivity.class);
|
||||
|
||||
final Notification notification = builder.build();
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
final Intent disconnect = new Intent(ACTION_DISCONNECT);
|
||||
disconnect.putExtra(EXTRA_SOURCE, SOURCE_NOTIFICATION);
|
||||
final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
/**
|
||||
* Cancels the existing notification. If there is no active notification this method does nothing
|
||||
*/
|
||||
private void cancelNotification() {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
// both activities above have launchMode="singleTask" in the AndroidManifest.xml file, so if the task is already running, it will be resumed
|
||||
final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[]{parentIntent, targetIntent}, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL);
|
||||
builder.setContentIntent(pendingIntent);
|
||||
builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName()));
|
||||
builder.setSmallIcon(R.drawable.ic_stat_notify_uart);
|
||||
builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true);
|
||||
builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.uart_notification_action_disconnect), disconnectAction));
|
||||
|
||||
/**
|
||||
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
|
||||
*/
|
||||
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
final int source = intent.getIntExtra(EXTRA_SOURCE, SOURCE_NOTIFICATION);
|
||||
switch (source) {
|
||||
case SOURCE_NOTIFICATION:
|
||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||
break;
|
||||
case SOURCE_WEARABLE:
|
||||
Logger.i(getLogSession(), "[WEAR] '" + Constants.ACTION_DISCONNECT + "' message received");
|
||||
break;
|
||||
}
|
||||
if (isConnected())
|
||||
getBinder().disconnect();
|
||||
else
|
||||
stopSelf();
|
||||
}
|
||||
};
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast receiver that listens for {@link #ACTION_SEND} from other apps. Sends the String or int content of the {@link Intent#EXTRA_TEXT} extra to the remote device.
|
||||
* The integer content will be sent as String (65 -> "65", not 65 -> "A").
|
||||
*/
|
||||
private BroadcastReceiver mIntentBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
final boolean hasMessage = intent.hasExtra(Intent.EXTRA_TEXT);
|
||||
if (hasMessage) {
|
||||
String message = intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||
if (message == null) {
|
||||
final int intValue = intent.getIntExtra(Intent.EXTRA_TEXT, Integer.MIN_VALUE); // how big is the chance of such data?
|
||||
if (intValue != Integer.MIN_VALUE)
|
||||
message = String.valueOf(intValue);
|
||||
}
|
||||
/**
|
||||
* Cancels the existing notification. If there is no active notification this method does nothing
|
||||
*/
|
||||
private void cancelNotification() {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
if (message != null) {
|
||||
final int source = intent.getIntExtra(EXTRA_SOURCE, SOURCE_3RD_PARTY);
|
||||
switch (source) {
|
||||
case SOURCE_WEARABLE:
|
||||
Logger.i(getLogSession(), "[WEAR] '" + Constants.UART.COMMAND + "' message received with data: \"" + message + "\"");
|
||||
break;
|
||||
case SOURCE_3RD_PARTY:
|
||||
default:
|
||||
Logger.i(getLogSession(), "[Broadcast] " + ACTION_SEND + " broadcast received with data: \"" + message + "\"");
|
||||
break;
|
||||
}
|
||||
mManager.send(message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// No data od incompatible type of EXTRA_TEXT
|
||||
if (!hasMessage)
|
||||
Logger.i(getLogSession(), "[Broadcast] " + ACTION_SEND + " broadcast received no data.");
|
||||
else
|
||||
Logger.i(getLogSession(), "[Broadcast] " + ACTION_SEND + " broadcast received incompatible data type. Only String and int are supported.");
|
||||
}
|
||||
};
|
||||
/**
|
||||
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
|
||||
*/
|
||||
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
final int source = intent.getIntExtra(EXTRA_SOURCE, SOURCE_NOTIFICATION);
|
||||
switch (source) {
|
||||
case SOURCE_NOTIFICATION:
|
||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||
break;
|
||||
case SOURCE_WEARABLE:
|
||||
Logger.i(getLogSession(), "[WEAR] '" + Constants.ACTION_DISCONNECT + "' message received");
|
||||
break;
|
||||
}
|
||||
if (isConnected())
|
||||
getBinder().disconnect();
|
||||
else
|
||||
stopSelf();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Broadcast receiver that listens for {@link #ACTION_SEND} from other apps. Sends the String or int content of the {@link Intent#EXTRA_TEXT} extra to the remote device.
|
||||
* The integer content will be sent as String (65 -> "65", not 65 -> "A").
|
||||
*/
|
||||
private BroadcastReceiver mIntentBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
final boolean hasMessage = intent.hasExtra(Intent.EXTRA_TEXT);
|
||||
if (hasMessage) {
|
||||
String message = intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||
if (message == null) {
|
||||
final int intValue = intent.getIntExtra(Intent.EXTRA_TEXT, Integer.MIN_VALUE); // how big is the chance of such data?
|
||||
if (intValue != Integer.MIN_VALUE)
|
||||
message = String.valueOf(intValue);
|
||||
}
|
||||
|
||||
if (message != null) {
|
||||
final int source = intent.getIntExtra(EXTRA_SOURCE, SOURCE_3RD_PARTY);
|
||||
switch (source) {
|
||||
case SOURCE_WEARABLE:
|
||||
Logger.i(getLogSession(), "[WEAR] '" + Constants.UART.COMMAND + "' message received with data: \"" + message + "\"");
|
||||
break;
|
||||
case SOURCE_3RD_PARTY:
|
||||
default:
|
||||
Logger.i(getLogSession(), "[Broadcast] " + ACTION_SEND + " broadcast received with data: \"" + message + "\"");
|
||||
break;
|
||||
}
|
||||
mManager.send(message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// No data od incompatible type of EXTRA_TEXT
|
||||
if (!hasMessage)
|
||||
Logger.i(getLogSession(), "[Broadcast] " + ACTION_SEND + " broadcast received no data.");
|
||||
else
|
||||
Logger.i(getLogSession(), "[Broadcast] " + ACTION_SEND + " broadcast received incompatible data type. Only String and int are supported.");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user