commit
751e87ca5e
11 changed files with 694 additions and 66 deletions
|
@ -68,6 +68,7 @@ android {
|
||||||
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
||||||
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'
|
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
|
// if you change minSdkVersion to less than 11, you need to change executeTask for wear
|
||||||
|
|
||||||
ndk {
|
ndk {
|
||||||
moduleName "BleCommandUtil"
|
moduleName "BleCommandUtil"
|
||||||
|
@ -77,7 +78,7 @@ android {
|
||||||
// TODO remove once wear dependency com.google.android.gms:play-services-wearable:7.3.0
|
// TODO remove once wear dependency com.google.android.gms:play-services-wearable:7.3.0
|
||||||
// has been upgraded (requiring significant code changes), which currently fails release
|
// has been upgraded (requiring significant code changes), which currently fails release
|
||||||
// build with a deprecation warning
|
// build with a deprecation warning
|
||||||
abortOnError false
|
// abortOnError false
|
||||||
// (disabled entirely to avoid reports on the error, which would still be displayed
|
// (disabled entirely to avoid reports on the error, which would still be displayed
|
||||||
// and it's easy to overlook that it's ignored)
|
// and it's easy to overlook that it's ignored)
|
||||||
checkReleaseBuilds false
|
checkReleaseBuilds false
|
||||||
|
@ -194,7 +195,7 @@ dependencies {
|
||||||
implementation "org.slf4j:slf4j-api:1.7.12"
|
implementation "org.slf4j:slf4j-api:1.7.12"
|
||||||
implementation "com.jjoe64:graphview:4.0.1"
|
implementation "com.jjoe64:graphview:4.0.1"
|
||||||
implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.1.1"
|
implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.1.1"
|
||||||
implementation "com.google.android.gms:play-services-wearable:7.5.0"
|
implementation 'com.google.android.gms:play-services-wearable:10.2.1'
|
||||||
implementation(name: "android-edittext-validator-v1.3.4-mod", ext: "aar")
|
implementation(name: "android-edittext-validator-v1.3.4-mod", ext: "aar")
|
||||||
implementation(name: "sightparser-release", ext: "aar")
|
implementation(name: "sightparser-release", ext: "aar")
|
||||||
implementation 'com.madgag.spongycastle:core:1.58.0.0'
|
implementation 'com.madgag.spongycastle:core:1.58.0.0'
|
||||||
|
|
|
@ -169,7 +169,63 @@
|
||||||
android:name=".plugins.general.wear.wearintegration.WatchUpdaterService"
|
android:name=".plugins.general.wear.wearintegration.WatchUpdaterService"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
|
<!-- <action android:name="com.google.android.gms.wearable.BIND_LISTENER" /> -->
|
||||||
|
<!-- listeners receive events that match the action and data filters -->
|
||||||
|
<action android:name="com.google.android.gms.wearable.CAPABILITY_CHANGED" />
|
||||||
|
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
|
||||||
|
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_data" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_data_resend" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_cancel_bolus" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_confirmactionstring" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_initiateactionstring" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/openwearsettings" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/sendstatustowear" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/sendpreferencestowear" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_basal" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_bolusprogress" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_actionconfirmationrequest" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_changeconfirmationrequest" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_cancelnotificationrequest" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
<service
|
<service
|
||||||
|
|
|
@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.general.wear;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.squareup.otto.Subscribe;
|
import com.squareup.otto.Subscribe;
|
||||||
|
|
||||||
|
@ -35,6 +36,8 @@ public class WearPlugin extends PluginBase {
|
||||||
private final Context ctx;
|
private final Context ctx;
|
||||||
|
|
||||||
private static WearPlugin wearPlugin;
|
private static WearPlugin wearPlugin;
|
||||||
|
private static String TAG = "WearPlugin";
|
||||||
|
|
||||||
|
|
||||||
public static WearPlugin getPlugin() {
|
public static WearPlugin getPlugin() {
|
||||||
return wearPlugin;
|
return wearPlugin;
|
||||||
|
@ -76,7 +79,10 @@ public class WearPlugin extends PluginBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendDataToWatch(boolean status, boolean basals, boolean bgValue) {
|
private void sendDataToWatch(boolean status, boolean basals, boolean bgValue) {
|
||||||
if (isEnabled(getType())) { //only start service when this plugin is enabled
|
|
||||||
|
//Log.d(TAG, "WR: WearPlugin:sendDataToWatch (status=" + status + ",basals=" + basals + ",bgValue=" + bgValue + ")");
|
||||||
|
|
||||||
|
if (isEnabled(getType())) { // only start service when this plugin is enabled
|
||||||
|
|
||||||
if (bgValue) {
|
if (bgValue) {
|
||||||
ctx.startService(new Intent(ctx, WatchUpdaterService.class));
|
ctx.startService(new Intent(ctx, WatchUpdaterService.class));
|
||||||
|
@ -93,15 +99,20 @@ public class WearPlugin extends PluginBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
void resendDataToWatch() {
|
void resendDataToWatch() {
|
||||||
|
//Log.d(TAG, "WR: WearPlugin:resendDataToWatch");
|
||||||
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_RESEND));
|
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_RESEND));
|
||||||
}
|
}
|
||||||
|
|
||||||
void openSettings() {
|
void openSettings() {
|
||||||
|
//Log.d(TAG, "WR: WearPlugin:openSettings");
|
||||||
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_OPEN_SETTINGS));
|
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_OPEN_SETTINGS));
|
||||||
}
|
}
|
||||||
|
|
||||||
void requestNotificationCancel(String actionstring) {
|
void requestNotificationCancel(String actionstring) {
|
||||||
Intent intent = new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_CANCEL_NOTIFICATION);
|
//Log.d(TAG, "WR: WearPlugin:requestNotificationCancel");
|
||||||
|
|
||||||
|
Intent intent = new Intent(ctx, WatchUpdaterService.class)
|
||||||
|
.setAction(WatchUpdaterService.ACTION_CANCEL_NOTIFICATION);
|
||||||
intent.putExtra("actionstring", actionstring);
|
intent.putExtra("actionstring", actionstring);
|
||||||
ctx.startService(intent);
|
ctx.startService(intent);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,40 +13,127 @@ import com.google.android.gms.wearable.PutDataRequest;
|
||||||
import com.google.android.gms.wearable.Wearable;
|
import com.google.android.gms.wearable.Wearable;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by emmablack on 12/26/14.
|
* Created by emmablack on 12/26/14.
|
||||||
*/
|
*/
|
||||||
class SendToDataLayerThread extends AsyncTask<DataMap,Void,Void> {
|
class SendToDataLayerThread extends AsyncTask<DataMap,Void,Void> {
|
||||||
private GoogleApiClient googleApiClient;
|
private GoogleApiClient googleApiClient;
|
||||||
private static final String TAG = "SendDataThread";
|
private static final String TAG = "SendToDataLayerThread";
|
||||||
String path;
|
private String path;
|
||||||
|
private String logPrefix = ""; // "WR: ";
|
||||||
|
private static int concurrency = 0;
|
||||||
|
private static int state = 0;
|
||||||
|
private static final ReentrantLock lock = new ReentrantLock();
|
||||||
|
private static long lastlock = 0;
|
||||||
|
private static final boolean testlockup = false; // always false in production
|
||||||
|
|
||||||
|
|
||||||
SendToDataLayerThread(String path, GoogleApiClient pGoogleApiClient) {
|
SendToDataLayerThread(String path, GoogleApiClient pGoogleApiClient) {
|
||||||
|
// Log.d(TAG, logPrefix + "SendToDataLayerThread: " + path);
|
||||||
this.path = path;
|
this.path = path;
|
||||||
googleApiClient = pGoogleApiClient;
|
googleApiClient = pGoogleApiClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
concurrency++;
|
||||||
|
if ((concurrency > 12) || ((concurrency > 3 && (lastlock != 0) && (tsl() - lastlock) > 300000))) {
|
||||||
|
// error if 9 concurrent threads or lock held for >5 minutes with concurrency of 4
|
||||||
|
final String err = "Wear Integration deadlock detected!! " + ((lastlock != 0) ? "locked" : "") + " state:"
|
||||||
|
+ state + " @" + hourMinuteString(tsl());
|
||||||
|
// Home.toaststaticnext(err);
|
||||||
|
Log.e(TAG, logPrefix + err);
|
||||||
|
}
|
||||||
|
if (concurrency < 0)
|
||||||
|
Log.d(TAG, logPrefix + "Wear Integration impossible concurrency!!");
|
||||||
|
|
||||||
|
Log.d(TAG, logPrefix + "SendDataToLayerThread pre-execute concurrency: " + concurrency);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(DataMap... params) {
|
protected Void doInBackground(DataMap... params) {
|
||||||
try {
|
if (testlockup) {
|
||||||
final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await(15, TimeUnit.SECONDS);
|
try {
|
||||||
for (Node node : nodes.getNodes()) {
|
Log.e(TAG, logPrefix + "WARNING RUNNING TEST LOCK UP CODE - NEVER FOR PRODUCTION");
|
||||||
for (DataMap dataMap : params) {
|
Thread.sleep(1000000); // DEEEBBUUGGGG
|
||||||
PutDataMapRequest putDMR = PutDataMapRequest.create(path);
|
} catch (Exception e) {
|
||||||
putDMR.getDataMap().putAll(dataMap);
|
|
||||||
PutDataRequest request = putDMR.asPutDataRequest();
|
|
||||||
DataApi.DataItemResult result = Wearable.DataApi.putDataItem(googleApiClient, request).await(15, TimeUnit.SECONDS);
|
|
||||||
if (result.getStatus().isSuccess()) {
|
|
||||||
Log.d(TAG, "DataMap: " + dataMap + " sent to: " + node.getDisplayName());
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "ERROR: failed to send DataMap");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "Got exception sending data to wear: " + e.toString());
|
|
||||||
}
|
}
|
||||||
|
sendToWear(params);
|
||||||
|
concurrency--;
|
||||||
|
Log.d(TAG, logPrefix + "SendDataToLayerThread post-execute concurrency: " + concurrency);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Debug function to expose where it might be locking up
|
||||||
|
private synchronized void sendToWear(final DataMap... params) {
|
||||||
|
if (!lock.tryLock()) {
|
||||||
|
Log.d(TAG, logPrefix + "Concurrent access - waiting for thread unlock");
|
||||||
|
lock.lock(); // enforce single threading
|
||||||
|
Log.d(TAG, logPrefix + "Thread unlocked - proceeding");
|
||||||
|
}
|
||||||
|
lastlock = tsl();
|
||||||
|
try {
|
||||||
|
if (state != 0) {
|
||||||
|
Log.e(TAG, logPrefix + "WEAR STATE ERROR: state=" + state);
|
||||||
|
}
|
||||||
|
state = 1;
|
||||||
|
final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await(15,
|
||||||
|
TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
Log.d(TAG, logPrefix + "Nodes: " + nodes);
|
||||||
|
|
||||||
|
state = 2;
|
||||||
|
for (Node node : nodes.getNodes()) {
|
||||||
|
state = 3;
|
||||||
|
for (DataMap dataMap : params) {
|
||||||
|
state = 4;
|
||||||
|
PutDataMapRequest putDMR = PutDataMapRequest.create(path);
|
||||||
|
state = 5;
|
||||||
|
putDMR.getDataMap().putAll(dataMap);
|
||||||
|
putDMR.setUrgent();
|
||||||
|
state = 6;
|
||||||
|
PutDataRequest request = putDMR.asPutDataRequest();
|
||||||
|
state = 7;
|
||||||
|
DataApi.DataItemResult result = Wearable.DataApi.putDataItem(googleApiClient, request).await(15,
|
||||||
|
TimeUnit.SECONDS);
|
||||||
|
state = 8;
|
||||||
|
if (result.getStatus().isSuccess()) {
|
||||||
|
Log.d(TAG, logPrefix + "DataMap: " + dataMap + " sent to: " + node.getDisplayName());
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, logPrefix + "ERROR: failed to send DataMap");
|
||||||
|
result = Wearable.DataApi.putDataItem(googleApiClient, request).await(30, TimeUnit.SECONDS);
|
||||||
|
if (result.getStatus().isSuccess()) {
|
||||||
|
Log.d(TAG, logPrefix + "DataMap retry: " + dataMap + " sent to: " + node.getDisplayName());
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, logPrefix + "ERROR on retry: failed to send DataMap: "
|
||||||
|
+ result.getStatus().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state = 9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state = 0;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, logPrefix + "Got exception in sendToWear: " + e.toString());
|
||||||
|
} finally {
|
||||||
|
lastlock = 0;
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static long tsl() {
|
||||||
|
return System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String hourMinuteString(long timestamp) {
|
||||||
|
return android.text.format.DateFormat.format("kk:mm", timestamp).toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
package info.nightscout.androidaps.plugins.general.wear.wearintegration;
|
package info.nightscout.androidaps.plugins.general.wear.wearintegration;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.AsyncTask;
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
@ -14,8 +22,11 @@ import android.util.Log;
|
||||||
|
|
||||||
import com.google.android.gms.common.ConnectionResult;
|
import com.google.android.gms.common.ConnectionResult;
|
||||||
import com.google.android.gms.common.api.GoogleApiClient;
|
import com.google.android.gms.common.api.GoogleApiClient;
|
||||||
|
import com.google.android.gms.wearable.CapabilityApi;
|
||||||
|
import com.google.android.gms.wearable.CapabilityInfo;
|
||||||
import com.google.android.gms.wearable.DataMap;
|
import com.google.android.gms.wearable.DataMap;
|
||||||
import com.google.android.gms.wearable.MessageEvent;
|
import com.google.android.gms.wearable.MessageEvent;
|
||||||
|
import com.google.android.gms.wearable.Node;
|
||||||
import com.google.android.gms.wearable.PutDataMapRequest;
|
import com.google.android.gms.wearable.PutDataMapRequest;
|
||||||
import com.google.android.gms.wearable.PutDataRequest;
|
import com.google.android.gms.wearable.PutDataRequest;
|
||||||
import com.google.android.gms.wearable.Wearable;
|
import com.google.android.gms.wearable.Wearable;
|
||||||
|
@ -42,21 +53,24 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorP
|
||||||
import info.nightscout.androidaps.plugins.treatments.Treatment;
|
import info.nightscout.androidaps.plugins.treatments.Treatment;
|
||||||
import info.nightscout.androidaps.interfaces.PluginType;
|
import info.nightscout.androidaps.interfaces.PluginType;
|
||||||
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus;
|
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus;
|
||||||
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin;
|
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin;
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||||
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler;
|
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler;
|
||||||
import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
|
import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
||||||
|
import info.nightscout.androidaps.plugins.treatments.Treatment;
|
||||||
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||||
import info.nightscout.androidaps.utils.DecimalFormatter;
|
import info.nightscout.androidaps.utils.DecimalFormatter;
|
||||||
import info.nightscout.androidaps.utils.SP;
|
import info.nightscout.androidaps.utils.SP;
|
||||||
import info.nightscout.androidaps.utils.SafeParse;
|
import info.nightscout.androidaps.utils.SafeParse;
|
||||||
import info.nightscout.androidaps.utils.ToastUtils;
|
import info.nightscout.androidaps.utils.ToastUtils;
|
||||||
|
|
||||||
public class WatchUpdaterService extends WearableListenerService implements
|
public class WatchUpdaterService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
||||||
GoogleApiClient.ConnectionCallbacks,
|
|
||||||
GoogleApiClient.OnConnectionFailedListener {
|
|
||||||
public static final String ACTION_RESEND = WatchUpdaterService.class.getName().concat(".Resend");
|
public static final String ACTION_RESEND = WatchUpdaterService.class.getName().concat(".Resend");
|
||||||
public static final String ACTION_OPEN_SETTINGS = WatchUpdaterService.class.getName().concat(".OpenSettings");
|
public static final String ACTION_OPEN_SETTINGS = WatchUpdaterService.class.getName().concat(".OpenSettings");
|
||||||
public static final String ACTION_SEND_STATUS = WatchUpdaterService.class.getName().concat(".SendStatus");
|
public static final String ACTION_SEND_STATUS = WatchUpdaterService.class.getName().concat(".SendStatus");
|
||||||
|
@ -91,6 +105,17 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
|
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
|
|
||||||
|
// Phone
|
||||||
|
private static final String CAPABILITY_PHONE_APP = "phone_app_sync_bgs";
|
||||||
|
private static final String MESSAGE_PATH_PHONE = "/phone_message_path";
|
||||||
|
// Wear
|
||||||
|
private static final String CAPABILITY_WEAR_APP = "wear_app_sync_bgs";
|
||||||
|
private static final String MESSAGE_PATH_WEAR = "/wear_message_path";
|
||||||
|
private String mWearNodeId = null;
|
||||||
|
private String localnode = null;
|
||||||
|
private String logPrefix = ""; // "WR: "
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
mPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
mPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||||
|
@ -112,24 +137,24 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
|
|
||||||
public void setSettings() {
|
public void setSettings() {
|
||||||
wear_integration = WearPlugin.getPlugin().isEnabled(PluginType.GENERAL);
|
wear_integration = WearPlugin.getPlugin().isEnabled(PluginType.GENERAL);
|
||||||
|
// Log.d(TAG, "WR: wear_integration=" + wear_integration);
|
||||||
if (wear_integration) {
|
if (wear_integration) {
|
||||||
googleApiConnect();
|
googleApiConnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void googleApiConnect() {
|
|
||||||
|
private void googleApiConnect() {
|
||||||
if (googleApiClient != null && (googleApiClient.isConnected() || googleApiClient.isConnecting())) {
|
if (googleApiClient != null && (googleApiClient.isConnected() || googleApiClient.isConnecting())) {
|
||||||
googleApiClient.disconnect();
|
googleApiClient.disconnect();
|
||||||
}
|
}
|
||||||
googleApiClient = new GoogleApiClient.Builder(this)
|
googleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this)
|
||||||
.addConnectionCallbacks(this)
|
.addOnConnectionFailedListener(this).addApi(Wearable.API).build();
|
||||||
.addOnConnectionFailedListener(this)
|
|
||||||
.addApi(Wearable.API)
|
|
||||||
.build();
|
|
||||||
Wearable.MessageApi.addListener(googleApiClient, this);
|
Wearable.MessageApi.addListener(googleApiClient, this);
|
||||||
if (googleApiClient.isConnected()) {
|
if (googleApiClient.isConnected()) {
|
||||||
Log.d("WatchUpdater", "API client is connected");
|
log.debug(logPrefix + "API client is connected");
|
||||||
} else {
|
} else {
|
||||||
|
// Log.d("WatchUpdater", logPrefix + "API client is not connected and is trying to connect");
|
||||||
googleApiClient.connect();
|
googleApiClient.connect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,6 +163,8 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
String action = intent != null ? intent.getAction() : null;
|
String action = intent != null ? intent.getAction() : null;
|
||||||
|
|
||||||
|
// Log.d(TAG, logPrefix + "onStartCommand: " + action);
|
||||||
|
|
||||||
if (wear_integration) {
|
if (wear_integration) {
|
||||||
handler.post(() -> {
|
handler.post(() -> {
|
||||||
if (googleApiClient.isConnected()) {
|
if (googleApiClient.isConnected()) {
|
||||||
|
@ -177,13 +204,63 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void updateWearSyncBgsCapability(CapabilityInfo capabilityInfo) {
|
||||||
|
Log.d("WatchUpdaterService", logPrefix + "CabilityInfo: " + capabilityInfo);
|
||||||
|
Set<Node> connectedNodes = capabilityInfo.getNodes();
|
||||||
|
mWearNodeId = pickBestNodeId(connectedNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String pickBestNodeId(Set<Node> nodes) {
|
||||||
|
String bestNodeId = null;
|
||||||
|
// Find a nearby node or pick one arbitrarily
|
||||||
|
for (Node node : nodes) {
|
||||||
|
if (node.isNearby()) {
|
||||||
|
return node.getId();
|
||||||
|
}
|
||||||
|
bestNodeId = node.getId();
|
||||||
|
}
|
||||||
|
return bestNodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConnected(Bundle connectionHint) {
|
public void onConnected(Bundle connectionHint) {
|
||||||
|
CapabilityApi.CapabilityListener capabilityListener = capabilityInfo -> {
|
||||||
|
updateWearSyncBgsCapability(capabilityInfo);
|
||||||
|
// Log.d(TAG, logPrefix + "onConnected onCapabilityChanged mWearNodeID:" + mWearNodeId);
|
||||||
|
// new CheckWearableConnected().execute();
|
||||||
|
};
|
||||||
|
|
||||||
|
Wearable.CapabilityApi.addCapabilityListener(googleApiClient, capabilityListener, CAPABILITY_WEAR_APP);
|
||||||
sendData();
|
sendData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPeerConnected(com.google.android.gms.wearable.Node peer) {// KS
|
||||||
|
super.onPeerConnected(peer);
|
||||||
|
String id = peer.getId();
|
||||||
|
String name = peer.getDisplayName();
|
||||||
|
// Log.d(TAG, logPrefix + "onPeerConnected peer name & ID: " + name + "|" + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPeerDisconnected(com.google.android.gms.wearable.Node peer) {// KS
|
||||||
|
super.onPeerDisconnected(peer);
|
||||||
|
String id = peer.getId();
|
||||||
|
String name = peer.getDisplayName();
|
||||||
|
// Log.d(TAG, logPrefix + "onPeerDisconnected peer name & ID: " + name + "|" + id);
|
||||||
|
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessageReceived(MessageEvent event) {
|
public void onMessageReceived(MessageEvent event) {
|
||||||
|
|
||||||
|
// Log.d(TAG, logPrefix + "onMessageRecieved: " + event);
|
||||||
|
|
||||||
if (wear_integration) {
|
if (wear_integration) {
|
||||||
if (event != null && event.getPath().equals(WEARABLE_RESEND_PATH)) {
|
if (event != null && event.getPath().equals(WEARABLE_RESEND_PATH)) {
|
||||||
resendData();
|
resendData();
|
||||||
|
@ -214,6 +291,7 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
private void sendData() {
|
private void sendData() {
|
||||||
|
|
||||||
BgReading lastBG = DatabaseHelper.lastBg();
|
BgReading lastBG = DatabaseHelper.lastBg();
|
||||||
|
// Log.d(TAG, logPrefix + "LastBg=" + lastBG);
|
||||||
if (lastBG != null) {
|
if (lastBG != null) {
|
||||||
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
|
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
|
||||||
|
|
||||||
|
@ -228,18 +306,19 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient).execute(dataMap);
|
executeTask(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient), dataMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private DataMap dataMapSingleBG(BgReading lastBG, GlucoseStatus glucoseStatus) {
|
private DataMap dataMapSingleBG(BgReading lastBG, GlucoseStatus glucoseStatus) {
|
||||||
String units = ProfileFunctions.getInstance().getProfileUnits();
|
String units = ProfileFunctions.getInstance().getProfileUnits();
|
||||||
|
|
||||||
Double lowLine = SafeParse.stringToDouble(mPrefs.getString("low_mark", "0"));
|
Double lowLine = SafeParse.stringToDouble(mPrefs.getString("low_mark", "0"));
|
||||||
Double highLine = SafeParse.stringToDouble(mPrefs.getString("high_mark", "0"));
|
Double highLine = SafeParse.stringToDouble(mPrefs.getString("high_mark", "0"));
|
||||||
|
|
||||||
//convert to mg/dl
|
// convert to mg/dl
|
||||||
if (!units.equals(Constants.MGDL)) {
|
if (!units.equals(Constants.MGDL)) {
|
||||||
lowLine *= Constants.MMOLL_TO_MGDL;
|
lowLine *= Constants.MMOLL_TO_MGDL;
|
||||||
highLine *= Constants.MMOLL_TO_MGDL;
|
highLine *= Constants.MMOLL_TO_MGDL;
|
||||||
|
@ -287,7 +366,6 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
deltastring += "+";
|
deltastring += "+";
|
||||||
} else {
|
} else {
|
||||||
deltastring += "-";
|
deltastring += "-";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean detailed = SP.getBoolean("wear_detailed_delta", false);
|
boolean detailed = SP.getBoolean("wear_detailed_delta", false);
|
||||||
|
@ -352,7 +430,7 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entries.putDataMapArrayList("entries", dataMaps);
|
entries.putDataMapArrayList("entries", dataMaps);
|
||||||
new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient).execute(entries);
|
executeTask(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient), entries);
|
||||||
}
|
}
|
||||||
sendPreferences();
|
sendPreferences();
|
||||||
sendBasals();
|
sendBasals();
|
||||||
|
@ -501,7 +579,7 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
dm.putDataMapArrayList("boluses", boluses);
|
dm.putDataMapArrayList("boluses", boluses);
|
||||||
dm.putDataMapArrayList("predictions", predictions);
|
dm.putDataMapArrayList("predictions", predictions);
|
||||||
|
|
||||||
new SendToDataLayerThread(BASAL_DATA_PATH, googleApiClient).execute(dm);
|
executeTask(new SendToDataLayerThread(BASAL_DATA_PATH, googleApiClient), dm);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataMap tempDatamap(long startTime, double startBasal, long to, double toBasal, double amount) {
|
private DataMap tempDatamap(long startTime, double startBasal, long to, double toBasal, double amount) {
|
||||||
|
@ -548,6 +626,7 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||||
dataMapRequest.getDataMap().putString("openSettings", "openSettings");
|
dataMapRequest.getDataMap().putString("openSettings", "openSettings");
|
||||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||||
|
debugData("sendNotification", putDataRequest);
|
||||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||||
} else {
|
} else {
|
||||||
Log.e("OpenSettings", "No connection to wearable available!");
|
Log.e("OpenSettings", "No connection to wearable available!");
|
||||||
|
@ -563,6 +642,7 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
dataMapRequest.getDataMap().putString("progressstatus", status);
|
dataMapRequest.getDataMap().putString("progressstatus", status);
|
||||||
dataMapRequest.getDataMap().putInt("progresspercent", progresspercent);
|
dataMapRequest.getDataMap().putInt("progresspercent", progresspercent);
|
||||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||||
|
debugData("sendBolusProgress", putDataRequest);
|
||||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||||
} else {
|
} else {
|
||||||
Log.e("BolusProgress", "No connection to wearable available!");
|
Log.e("BolusProgress", "No connection to wearable available!");
|
||||||
|
@ -582,6 +662,7 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
log.debug("Requesting confirmation from wear: " + actionstring);
|
log.debug("Requesting confirmation from wear: " + actionstring);
|
||||||
|
|
||||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||||
|
debugData("sendActionConfirmationRequest", putDataRequest);
|
||||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||||
} else {
|
} else {
|
||||||
Log.e("confirmationRequest", "No connection to wearable available!");
|
Log.e("confirmationRequest", "No connection to wearable available!");
|
||||||
|
@ -601,6 +682,7 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
log.debug("Requesting confirmation from wear: " + actionstring);
|
log.debug("Requesting confirmation from wear: " + actionstring);
|
||||||
|
|
||||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||||
|
debugData("sendChangeConfirmationRequest", putDataRequest);
|
||||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||||
} else {
|
} else {
|
||||||
Log.e("changeConfirmRequest", "No connection to wearable available!");
|
Log.e("changeConfirmRequest", "No connection to wearable available!");
|
||||||
|
@ -618,9 +700,10 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
log.debug("Canceling notification on wear: " + actionstring);
|
log.debug("Canceling notification on wear: " + actionstring);
|
||||||
|
|
||||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||||
|
debugData("sendCancelNotificationRequest", putDataRequest);
|
||||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||||
} else {
|
} else {
|
||||||
Log.e("cancelNotificationRequest", "No connection to wearable available!");
|
Log.e("cancelNotificationReq", "No connection to wearable available!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -683,6 +766,7 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
dataMapRequest.getDataMap().putBoolean("showBgi", mPrefs.getBoolean("wear_showbgi", false));
|
dataMapRequest.getDataMap().putBoolean("showBgi", mPrefs.getBoolean("wear_showbgi", false));
|
||||||
dataMapRequest.getDataMap().putInt("batteryLevel", (phoneBattery >= 30) ? 1 : 0);
|
dataMapRequest.getDataMap().putInt("batteryLevel", (phoneBattery >= 30) ? 1 : 0);
|
||||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||||
|
debugData("sendStatus", putDataRequest);
|
||||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||||
} else {
|
} else {
|
||||||
Log.e("SendStatus", "No connection to wearable available!");
|
Log.e("SendStatus", "No connection to wearable available!");
|
||||||
|
@ -699,12 +783,29 @@ public class WatchUpdaterService extends WearableListenerService implements
|
||||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||||
dataMapRequest.getDataMap().putBoolean("wearcontrol", wearcontrol);
|
dataMapRequest.getDataMap().putBoolean("wearcontrol", wearcontrol);
|
||||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||||
|
debugData("sendPreferences", putDataRequest);
|
||||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||||
} else {
|
} else {
|
||||||
Log.e("SendStatus", "No connection to wearable available!");
|
Log.e("SendStatus", "No connection to wearable available!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void debugData(String source, Object data) {
|
||||||
|
// Log.d(TAG, "WR: " + source + " " + data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void executeTask(AsyncTask task, DataMap... parameters) {
|
||||||
|
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[])parameters);
|
||||||
|
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||||
|
// task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
// } else {
|
||||||
|
// task.execute();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private String generateStatusString(Profile profile, String currentBasal, String iobSum, String iobDetail, String bgiString) {
|
private String generateStatusString(Profile profile, String currentBasal, String iobSum, String iobDetail, String bgiString) {
|
||||||
|
|
||||||
|
|
18
app/src/main/res/values/wear.xml
Normal file
18
app/src/main/res/values/wear.xml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<string-array name="android_wear_capabilities">
|
||||||
|
<item>phone_app_sync_bgs</item>
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
|
@ -2,6 +2,7 @@ apply plugin: 'com.android.application'
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
wearableVersion = "2.0.1"
|
wearableVersion = "2.0.1"
|
||||||
|
playServicesWearable = "10.2.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
def generateGitBuild = { ->
|
def generateGitBuild = { ->
|
||||||
|
@ -93,7 +94,7 @@ dependencies {
|
||||||
//compile "com.ustwo.android:clockwise-wearable:1.0.2"
|
//compile "com.ustwo.android:clockwise-wearable:1.0.2"
|
||||||
compileOnly "com.google.android.wearable:wearable:${wearableVersion}"
|
compileOnly "com.google.android.wearable:wearable:${wearableVersion}"
|
||||||
implementation "com.google.android.support:wearable:${wearableVersion}"
|
implementation "com.google.android.support:wearable:${wearableVersion}"
|
||||||
implementation "com.google.android.gms:play-services-wearable:7.3.0"
|
implementation "com.google.android.gms:play-services-wearable:${playServicesWearable}"
|
||||||
implementation(name:"ustwo-clockwise-debug", ext:"aar")
|
implementation(name:"ustwo-clockwise-debug", ext:"aar")
|
||||||
implementation "com.android.support:support-v4:27.0.1"
|
implementation "com.android.support:support-v4:27.0.1"
|
||||||
implementation 'com.android.support:wear:27.0.1'
|
implementation 'com.android.support:wear:27.0.1'
|
||||||
|
|
|
@ -168,9 +168,66 @@
|
||||||
<category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
|
<category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service android:name=".data.ListenerService">
|
<service android:name=".data.ListenerService">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
|
<!-- <action android:name="com.google.android.gms.wearable.BIND_LISTENER" /> -->
|
||||||
|
<!-- listeners receive events that match the action and data filters -->
|
||||||
|
<action android:name="com.google.android.gms.wearable.CAPABILITY_CHANGED" />
|
||||||
|
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
|
||||||
|
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_data" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_data_resend" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_cancel_bolus" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_confirmactionstring" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_initiateactionstring" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/openwearsettings" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/sendstatustowear" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/sendpreferencestowear" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_basal" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_bolusprogress" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_actionconfirmationrequest" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_changeconfirmationrequest" />
|
||||||
|
<data
|
||||||
|
android:scheme="wear"
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/nightscout_watch_cancelnotificationrequest" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package info.nightscout.androidaps.data;
|
package info.nightscout.androidaps.data;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
|
@ -7,16 +10,24 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.support.v4.app.NotificationManagerCompat;
|
import android.support.v4.app.NotificationManagerCompat;
|
||||||
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
|
||||||
import com.google.android.gms.common.ConnectionResult;
|
import com.google.android.gms.common.ConnectionResult;
|
||||||
import com.google.android.gms.common.api.GoogleApiClient;
|
import com.google.android.gms.common.api.GoogleApiClient;
|
||||||
|
import com.google.android.gms.common.api.PendingResult;
|
||||||
|
import com.google.android.gms.common.api.ResultCallback;
|
||||||
|
import com.google.android.gms.wearable.CapabilityApi;
|
||||||
|
import com.google.android.gms.wearable.CapabilityInfo;
|
||||||
|
import com.google.android.gms.wearable.ChannelApi;
|
||||||
import com.google.android.gms.wearable.DataEvent;
|
import com.google.android.gms.wearable.DataEvent;
|
||||||
import com.google.android.gms.wearable.DataEventBuffer;
|
import com.google.android.gms.wearable.DataEventBuffer;
|
||||||
import com.google.android.gms.wearable.DataMap;
|
import com.google.android.gms.wearable.DataMap;
|
||||||
|
@ -33,12 +44,15 @@ import info.nightscout.androidaps.R;
|
||||||
import info.nightscout.androidaps.interaction.actions.AcceptActivity;
|
import info.nightscout.androidaps.interaction.actions.AcceptActivity;
|
||||||
import info.nightscout.androidaps.interaction.actions.CPPActivity;
|
import info.nightscout.androidaps.interaction.actions.CPPActivity;
|
||||||
import info.nightscout.androidaps.interaction.utils.SafeParse;
|
import info.nightscout.androidaps.interaction.utils.SafeParse;
|
||||||
|
import info.nightscout.androidaps.interaction.utils.WearUtil;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by emmablack on 12/26/14.
|
* Created by emmablack on 12/26/14.
|
||||||
*/
|
*/
|
||||||
public class ListenerService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks,
|
public class ListenerService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks,
|
||||||
GoogleApiClient.OnConnectionFailedListener {
|
GoogleApiClient.OnConnectionFailedListener, ChannelApi.ChannelListener {
|
||||||
|
|
||||||
private static final String WEARABLE_DATA_PATH = "/nightscout_watch_data";
|
private static final String WEARABLE_DATA_PATH = "/nightscout_watch_data";
|
||||||
private static final String WEARABLE_RESEND_PATH = "/nightscout_watch_data_resend";
|
private static final String WEARABLE_RESEND_PATH = "/nightscout_watch_data_resend";
|
||||||
private static final String WEARABLE_CANCELBOLUS_PATH = "/nightscout_watch_cancel_bolus";
|
private static final String WEARABLE_CANCELBOLUS_PATH = "/nightscout_watch_cancel_bolus";
|
||||||
|
@ -67,49 +81,164 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
|
|
||||||
|
|
||||||
private static final String ACTION_RESEND_BULK = "com.dexdrip.stephenblack.nightwatch.RESEND_BULK_DATA";
|
private static final String ACTION_RESEND_BULK = "com.dexdrip.stephenblack.nightwatch.RESEND_BULK_DATA";
|
||||||
|
|
||||||
GoogleApiClient googleApiClient;
|
GoogleApiClient googleApiClient;
|
||||||
private long lastRequest = 0;
|
private long lastRequest = 0;
|
||||||
private DismissThread confirmThread;
|
private DismissThread confirmThread;
|
||||||
private DismissThread bolusprogressThread;
|
private DismissThread bolusprogressThread;
|
||||||
|
private static final String TAG = "ListenerService";
|
||||||
|
|
||||||
|
private DataRequester mDataRequester = null;
|
||||||
|
private static final int GET_CAPABILITIES_TIMEOUT_MS = 5000;
|
||||||
|
|
||||||
|
// Phone
|
||||||
|
private static final String CAPABILITY_PHONE_APP = "phone_app_sync_bgs";
|
||||||
|
private static final String MESSAGE_PATH_PHONE = "/phone_message_path";
|
||||||
|
// Wear
|
||||||
|
private static final String CAPABILITY_WEAR_APP = "wear_app_sync_bgs";
|
||||||
|
private static final String MESSAGE_PATH_WEAR = "/wear_message_path";
|
||||||
|
private String mPhoneNodeId = null;
|
||||||
|
private String localnode = null;
|
||||||
|
private String logPrefix = ""; // "WR: "
|
||||||
|
|
||||||
public class DataRequester extends AsyncTask<Void, Void, Void> {
|
public class DataRequester extends AsyncTask<Void, Void, Void> {
|
||||||
Context mContext;
|
Context mContext;
|
||||||
|
String path;
|
||||||
|
byte[] payload;
|
||||||
|
|
||||||
DataRequester(Context context) {
|
|
||||||
mContext = context;
|
DataRequester(Context context, String thispath, byte[] thispayload) {
|
||||||
|
path = thispath;
|
||||||
|
payload = thispayload;
|
||||||
|
// Log.d(TAG, logPrefix + "DataRequester DataRequester: " + thispath + " lastRequest:" + lastRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... params) {
|
protected Void doInBackground(Void... params) {
|
||||||
if (googleApiClient.isConnected()) {
|
// Log.d(TAG, logPrefix + "DataRequester: doInBack: " + params);
|
||||||
if (System.currentTimeMillis() - lastRequest > 20 * 1000) { // enforce 20-second debounce period
|
|
||||||
lastRequest = System.currentTimeMillis();
|
|
||||||
|
|
||||||
NodeApi.GetConnectedNodesResult nodes =
|
try {
|
||||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
|
||||||
for (Node node : nodes.getNodes()) {
|
forceGoogleApiConnect();
|
||||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_RESEND_PATH, null);
|
DataMap datamap;
|
||||||
}
|
|
||||||
|
if (isCancelled()) {
|
||||||
|
Log.d(TAG, "doInBackground CANCELLED programmatically");
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
if (googleApiClient != null) {
|
||||||
if (googleApiClient.isConnected()) {
|
if (!googleApiClient.isConnected())
|
||||||
if (System.currentTimeMillis() - lastRequest > 20 * 1000) { // enforce 20-second debounce period
|
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this code might not be needed in this way, but we need to see that later
|
||||||
|
if ((googleApiClient != null) && (googleApiClient.isConnected())) {
|
||||||
|
if ((System.currentTimeMillis() - lastRequest > 20 * 1000)) {
|
||||||
|
|
||||||
|
// enforce 20-second debounce period
|
||||||
lastRequest = System.currentTimeMillis();
|
lastRequest = System.currentTimeMillis();
|
||||||
|
|
||||||
NodeApi.GetConnectedNodesResult nodes =
|
// NodeApi.GetConnectedNodesResult nodes =
|
||||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
// Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||||
for (Node node : nodes.getNodes()) {
|
if (localnode == null || (localnode != null && localnode.isEmpty()))
|
||||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_RESEND_PATH, null);
|
setLocalNodeName();
|
||||||
|
|
||||||
|
CapabilityInfo capabilityInfo = getCapabilities();
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
Node phoneNode = null;
|
||||||
|
|
||||||
|
if (capabilityInfo != null) {
|
||||||
|
phoneNode = updatePhoneSyncBgsCapability(capabilityInfo);
|
||||||
|
count = capabilityInfo.getNodes().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "doInBackground connected. CapabilityApi.GetCapabilityResult mPhoneNodeID="
|
||||||
|
+ (phoneNode != null ? phoneNode.getId() : "") + " count=" + count + " localnode="
|
||||||
|
+ localnode);// KS
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
|
||||||
|
for (Node node : capabilityInfo.getNodes()) {
|
||||||
|
|
||||||
|
// Log.d(TAG, "doInBackground path: " + path);
|
||||||
|
|
||||||
|
switch (path) {
|
||||||
|
// simple send as is payloads
|
||||||
|
|
||||||
|
case WEARABLE_RESEND_PATH:
|
||||||
|
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(),
|
||||||
|
WEARABLE_RESEND_PATH, null);
|
||||||
|
break;
|
||||||
|
case WEARABLE_DATA_PATH:
|
||||||
|
case WEARABLE_CANCELBOLUS_PATH:
|
||||||
|
case WEARABLE_CONFIRM_ACTIONSTRING_PATH:
|
||||||
|
case WEARABLE_INITIATE_ACTIONSTRING_PATH:
|
||||||
|
case OPEN_SETTINGS:
|
||||||
|
case NEW_STATUS_PATH:
|
||||||
|
case NEW_PREFERENCES_PATH:
|
||||||
|
case BASAL_DATA_PATH:
|
||||||
|
case BOLUS_PROGRESS_PATH:
|
||||||
|
case ACTION_CONFIRMATION_REQUEST_PATH:
|
||||||
|
case NEW_CHANGECONFIRMATIONREQUEST_PATH:
|
||||||
|
case ACTION_CANCELNOTIFICATION_REQUEST_PATH: {
|
||||||
|
Log.w(TAG, logPrefix + "Unhandled path");
|
||||||
|
// sendMessagePayload(node, path, path, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:// SYNC_ALL_DATA
|
||||||
|
// this fall through is messy and non-deterministic for new paths
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Log.d(TAG, logPrefix + "doInBackground connected but getConnectedNodes returns 0.");
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no resend
|
||||||
|
Log.d(TAG, logPrefix + "Inside the timeout, will not be executed");
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, logPrefix + "Not connected for sending: api "
|
||||||
|
+ ((googleApiClient == null) ? "is NULL!" : "not null"));
|
||||||
|
if (googleApiClient != null) {
|
||||||
|
googleApiClient.connect();
|
||||||
|
} else {
|
||||||
|
googleApiConnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.e(TAG, logPrefix + "Error executing DataRequester in background. Exception: " + ex.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public CapabilityInfo getCapabilities() {
|
||||||
|
|
||||||
|
CapabilityApi.GetCapabilityResult capabilityResult = Wearable.CapabilityApi.getCapability(googleApiClient,
|
||||||
|
CAPABILITY_PHONE_APP, CapabilityApi.FILTER_REACHABLE).await(GET_CAPABILITIES_TIMEOUT_MS,
|
||||||
|
TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
if (!capabilityResult.getStatus().isSuccess()) {
|
||||||
|
Log.e(TAG, logPrefix + "doInBackground Failed to get capabilities, status: "
|
||||||
|
+ capabilityResult.getStatus().getStatusMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return capabilityResult.getCapability();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public class BolusCancelTask extends AsyncTask<Void, Void, Void> {
|
public class BolusCancelTask extends AsyncTask<Void, Void, Void> {
|
||||||
Context mContext;
|
Context mContext;
|
||||||
|
|
||||||
|
@ -119,6 +248,8 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... params) {
|
protected Void doInBackground(Void... params) {
|
||||||
|
// Log.d(TAG, logPrefix + "BolusCancelTask: doInBack: " + params);
|
||||||
|
|
||||||
if (googleApiClient.isConnected()) {
|
if (googleApiClient.isConnected()) {
|
||||||
NodeApi.GetConnectedNodesResult nodes =
|
NodeApi.GetConnectedNodesResult nodes =
|
||||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||||
|
@ -154,6 +285,9 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... params) {
|
protected Void doInBackground(Void... params) {
|
||||||
|
|
||||||
|
forceGoogleApiConnect();
|
||||||
|
|
||||||
if (googleApiClient.isConnected()) {
|
if (googleApiClient.isConnected()) {
|
||||||
NodeApi.GetConnectedNodesResult nodes =
|
NodeApi.GetConnectedNodesResult nodes =
|
||||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||||
|
@ -176,7 +310,7 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestData() {
|
public void requestData() {
|
||||||
new DataRequester(this).execute();
|
sendData(WEARABLE_RESEND_PATH, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cancelBolus() {
|
public void cancelBolus() {
|
||||||
|
@ -191,7 +325,73 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
new MessageActionTask(this, WEARABLE_INITIATE_ACTIONSTRING_PATH, actionstring).execute();
|
new MessageActionTask(this, WEARABLE_INITIATE_ACTIONSTRING_PATH, actionstring).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void googleApiConnect() {
|
|
||||||
|
private Node updatePhoneSyncBgsCapability(CapabilityInfo capabilityInfo) {
|
||||||
|
// Log.d(TAG, "CapabilityInfo: " + capabilityInfo);
|
||||||
|
|
||||||
|
Set<Node> connectedNodes = capabilityInfo.getNodes();
|
||||||
|
return pickBestNode(connectedNodes);
|
||||||
|
// mPhoneNodeId = pickBestNodeId(connectedNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Node pickBestNode(Set<Node> nodes) {
|
||||||
|
Node bestNode = null;
|
||||||
|
// Find a nearby node or pick one arbitrarily
|
||||||
|
for (Node node : nodes) {
|
||||||
|
if (node.isNearby()) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
bestNode = node;
|
||||||
|
}
|
||||||
|
return bestNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private synchronized void sendData(String path, byte[] payload) {
|
||||||
|
// Log.d(TAG, "WR: sendData: path: " + path + ", payload=" + payload);
|
||||||
|
|
||||||
|
if (path == null)
|
||||||
|
return;
|
||||||
|
if (mDataRequester != null) {
|
||||||
|
// Log.d(TAG, logPrefix + "sendData DataRequester != null lastRequest:" +
|
||||||
|
// WearUtil.dateTimeText(lastRequest));
|
||||||
|
if (mDataRequester.getStatus() != AsyncTask.Status.FINISHED) {
|
||||||
|
// Log.d(TAG, logPrefix + "sendData Should be canceled? Let run 'til finished.");
|
||||||
|
// mDataRequester.cancel(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, logPrefix + "sendData: execute lastRequest:" + WearUtil.dateTimeText(lastRequest));
|
||||||
|
mDataRequester = (DataRequester)new DataRequester(this, path, payload).execute();
|
||||||
|
// executeTask(mDataRequester);
|
||||||
|
|
||||||
|
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||||
|
// Log.d(TAG, "sendData SDK < M call execute lastRequest:" + WearUtil.dateTimeText(lastRequest));
|
||||||
|
// mDataRequester = (DataRequester) new DataRequester(this, path, payload).execute();
|
||||||
|
// } else {
|
||||||
|
// Log.d(TAG, "sendData SDK >= M call executeOnExecutor lastRequest:" + WearUtil.dateTimeText(lastRequest));
|
||||||
|
// // TODO xdrip executor
|
||||||
|
// mDataRequester = (DataRequester) new DataRequester(this, path, payload).executeOnExecutor(xdrip.executor);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void googleApiConnect() {
|
||||||
|
if (googleApiClient != null) {
|
||||||
|
// Remove old listener(s)
|
||||||
|
try {
|
||||||
|
Wearable.ChannelApi.removeListener(googleApiClient, this);
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Wearable.MessageApi.removeListener(googleApiClient, this);
|
||||||
|
} catch (Exception e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
googleApiClient = new GoogleApiClient.Builder(this)
|
googleApiClient = new GoogleApiClient.Builder(this)
|
||||||
.addConnectionCallbacks(this)
|
.addConnectionCallbacks(this)
|
||||||
.addOnConnectionFailedListener(this)
|
.addOnConnectionFailedListener(this)
|
||||||
|
@ -201,8 +401,25 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void forceGoogleApiConnect() {
|
||||||
|
if ((googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) || googleApiClient == null) {
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "forceGoogleApiConnect: forcing google api reconnection");
|
||||||
|
googleApiConnect();
|
||||||
|
Thread.sleep(2000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
|
||||||
|
// Log.d(TAG, logPrefix + "onStartCommand: Intent: " + intent);
|
||||||
|
|
||||||
if (intent != null && ACTION_RESEND.equals(intent.getAction())) {
|
if (intent != null && ACTION_RESEND.equals(intent.getAction())) {
|
||||||
googleApiConnect();
|
googleApiConnect();
|
||||||
requestData();
|
requestData();
|
||||||
|
@ -256,13 +473,16 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
public void onDataChanged(DataEventBuffer dataEvents) {
|
public void onDataChanged(DataEventBuffer dataEvents) {
|
||||||
|
|
||||||
DataMap dataMap;
|
DataMap dataMap;
|
||||||
|
// Log.d(TAG, logPrefix + "onDataChanged: DataEvents=" + dataEvents);
|
||||||
|
|
||||||
for (DataEvent event : dataEvents) {
|
for (DataEvent event : dataEvents) {
|
||||||
|
|
||||||
if (event.getType() == DataEvent.TYPE_CHANGED) {
|
if (event.getType() == DataEvent.TYPE_CHANGED) {
|
||||||
|
|
||||||
|
|
||||||
String path = event.getDataItem().getUri().getPath();
|
String path = event.getDataItem().getUri().getPath();
|
||||||
|
|
||||||
|
//Log.d(TAG, "WR: onDataChanged: Path: " + path + ", EventDataItem=" + event.getDataItem());
|
||||||
|
|
||||||
if (path.equals(OPEN_SETTINGS)) {
|
if (path.equals(OPEN_SETTINGS)) {
|
||||||
Intent intent = new Intent(this, AAPSPreferences.class);
|
Intent intent = new Intent(this, AAPSPreferences.class);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
@ -480,6 +700,21 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConnected(Bundle bundle) {
|
public void onConnected(Bundle bundle) {
|
||||||
|
// Log.d(TAG, logPrefix + "onConnected call requestData");
|
||||||
|
|
||||||
|
CapabilityApi.CapabilityListener capabilityListener = new CapabilityApi.CapabilityListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCapabilityChanged(CapabilityInfo capabilityInfo) {
|
||||||
|
updatePhoneSyncBgsCapability(capabilityInfo);
|
||||||
|
Log.d(TAG, logPrefix + "onConnected onCapabilityChanged mPhoneNodeID:" + mPhoneNodeId
|
||||||
|
+ ", Capability: " + capabilityInfo);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Wearable.CapabilityApi.addCapabilityListener(googleApiClient, capabilityListener, CAPABILITY_PHONE_APP);
|
||||||
|
|
||||||
|
Wearable.ChannelApi.addListener(googleApiClient, this);
|
||||||
requestData();
|
requestData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,14 +728,38 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void setLocalNodeName() {
|
||||||
|
forceGoogleApiConnect();
|
||||||
|
PendingResult<NodeApi.GetLocalNodeResult> result = Wearable.NodeApi.getLocalNode(googleApiClient);
|
||||||
|
result.setResultCallback(new ResultCallback<NodeApi.GetLocalNodeResult>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResult(NodeApi.GetLocalNodeResult getLocalNodeResult) {
|
||||||
|
if (!getLocalNodeResult.getStatus().isSuccess()) {
|
||||||
|
Log.e(TAG, "ERROR: failed to getLocalNode Status="
|
||||||
|
+ getLocalNodeResult.getStatus().getStatusMessage());
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "getLocalNode Status=: " + getLocalNodeResult.getStatus().getStatusMessage());
|
||||||
|
Node getnode = getLocalNodeResult.getNode();
|
||||||
|
localnode = getnode != null ? getnode.getDisplayName() + "|" + getnode.getId() : "";
|
||||||
|
Log.d(TAG, "setLocalNodeName. localnode=" + localnode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||||
googleApiClient.disconnect();
|
googleApiClient.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (googleApiClient != null) {
|
if (googleApiClient != null) {
|
||||||
Wearable.MessageApi.removeListener(googleApiClient, this);
|
Wearable.MessageApi.removeListener(googleApiClient, this);
|
||||||
|
Wearable.ChannelApi.removeListener(googleApiClient, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package info.nightscout.androidaps.interaction.utils;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by andy on 3/5/19.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class WearUtil {
|
||||||
|
|
||||||
|
|
||||||
|
public static String dateTimeText(long timeInMs) {
|
||||||
|
Date d = new Date(timeInMs);
|
||||||
|
return "" + d.getDay() + "." + d.getMonth() + "." + d.getYear() + " " + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
18
wear/src/main/res/values/wear.xml
Normal file
18
wear/src/main/res/values/wear.xml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<string-array name="android_wear_capabilities">
|
||||||
|
<item>phone_app_sync_bgs</item>
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
Loading…
Reference in a new issue