commit
751e87ca5e
11 changed files with 694 additions and 66 deletions
|
@ -68,6 +68,7 @@ android {
|
|||
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
||||
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
// if you change minSdkVersion to less than 11, you need to change executeTask for wear
|
||||
|
||||
ndk {
|
||||
moduleName "BleCommandUtil"
|
||||
|
@ -77,7 +78,7 @@ android {
|
|||
// 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
|
||||
// build with a deprecation warning
|
||||
abortOnError false
|
||||
// abortOnError false
|
||||
// (disabled entirely to avoid reports on the error, which would still be displayed
|
||||
// and it's easy to overlook that it's ignored)
|
||||
checkReleaseBuilds false
|
||||
|
@ -194,7 +195,7 @@ dependencies {
|
|||
implementation "org.slf4j:slf4j-api:1.7.12"
|
||||
implementation "com.jjoe64:graphview:4.0.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: "sightparser-release", ext: "aar")
|
||||
implementation 'com.madgag.spongycastle:core:1.58.0.0'
|
||||
|
|
|
@ -169,7 +169,63 @@
|
|||
android:name=".plugins.general.wear.wearintegration.WatchUpdaterService"
|
||||
android:exported="true">
|
||||
<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>
|
||||
</service>
|
||||
<service
|
||||
|
|
|
@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.general.wear;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
|
@ -35,6 +36,8 @@ public class WearPlugin extends PluginBase {
|
|||
private final Context ctx;
|
||||
|
||||
private static WearPlugin wearPlugin;
|
||||
private static String TAG = "WearPlugin";
|
||||
|
||||
|
||||
public static WearPlugin getPlugin() {
|
||||
return wearPlugin;
|
||||
|
@ -76,6 +79,9 @@ public class WearPlugin extends PluginBase {
|
|||
}
|
||||
|
||||
private void sendDataToWatch(boolean status, boolean basals, boolean bgValue) {
|
||||
|
||||
//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) {
|
||||
|
@ -93,15 +99,20 @@ public class WearPlugin extends PluginBase {
|
|||
}
|
||||
|
||||
void resendDataToWatch() {
|
||||
//Log.d(TAG, "WR: WearPlugin:resendDataToWatch");
|
||||
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_RESEND));
|
||||
}
|
||||
|
||||
void openSettings() {
|
||||
//Log.d(TAG, "WR: WearPlugin:openSettings");
|
||||
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_OPEN_SETTINGS));
|
||||
}
|
||||
|
||||
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);
|
||||
ctx.startService(intent);
|
||||
}
|
||||
|
|
|
@ -13,40 +13,127 @@ import com.google.android.gms.wearable.PutDataRequest;
|
|||
import com.google.android.gms.wearable.Wearable;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Created by emmablack on 12/26/14.
|
||||
*/
|
||||
class SendToDataLayerThread extends AsyncTask<DataMap,Void,Void> {
|
||||
private GoogleApiClient googleApiClient;
|
||||
private static final String TAG = "SendDataThread";
|
||||
String path;
|
||||
private static final String TAG = "SendToDataLayerThread";
|
||||
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) {
|
||||
// Log.d(TAG, logPrefix + "SendToDataLayerThread: " + path);
|
||||
this.path = path;
|
||||
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
|
||||
protected Void doInBackground(DataMap... params) {
|
||||
if (testlockup) {
|
||||
try {
|
||||
final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await(15, TimeUnit.SECONDS);
|
||||
for (Node node : nodes.getNodes()) {
|
||||
for (DataMap dataMap : params) {
|
||||
PutDataMapRequest putDMR = PutDataMapRequest.create(path);
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.e(TAG, logPrefix + "WARNING RUNNING TEST LOCK UP CODE - NEVER FOR PRODUCTION");
|
||||
Thread.sleep(1000000); // DEEEBBUUGGGG
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
|
||||
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.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Bundle;
|
||||
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.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.MessageEvent;
|
||||
import com.google.android.gms.wearable.Node;
|
||||
import com.google.android.gms.wearable.PutDataMapRequest;
|
||||
import com.google.android.gms.wearable.PutDataRequest;
|
||||
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.interfaces.PluginType;
|
||||
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.configBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus;
|
||||
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin;
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler;
|
||||
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.SP;
|
||||
import info.nightscout.androidaps.utils.SafeParse;
|
||||
import info.nightscout.androidaps.utils.ToastUtils;
|
||||
|
||||
public class WatchUpdaterService extends WearableListenerService implements
|
||||
GoogleApiClient.ConnectionCallbacks,
|
||||
GoogleApiClient.OnConnectionFailedListener {
|
||||
public class WatchUpdaterService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
||||
|
||||
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_SEND_STATUS = WatchUpdaterService.class.getName().concat(".SendStatus");
|
||||
|
@ -91,6 +105,17 @@ public class WatchUpdaterService extends WearableListenerService implements
|
|||
|
||||
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
|
||||
public void onCreate() {
|
||||
mPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||
|
@ -112,24 +137,24 @@ public class WatchUpdaterService extends WearableListenerService implements
|
|||
|
||||
public void setSettings() {
|
||||
wear_integration = WearPlugin.getPlugin().isEnabled(PluginType.GENERAL);
|
||||
// Log.d(TAG, "WR: wear_integration=" + wear_integration);
|
||||
if (wear_integration) {
|
||||
googleApiConnect();
|
||||
}
|
||||
}
|
||||
|
||||
public void googleApiConnect() {
|
||||
|
||||
private void googleApiConnect() {
|
||||
if (googleApiClient != null && (googleApiClient.isConnected() || googleApiClient.isConnecting())) {
|
||||
googleApiClient.disconnect();
|
||||
}
|
||||
googleApiClient = new GoogleApiClient.Builder(this)
|
||||
.addConnectionCallbacks(this)
|
||||
.addOnConnectionFailedListener(this)
|
||||
.addApi(Wearable.API)
|
||||
.build();
|
||||
googleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this)
|
||||
.addOnConnectionFailedListener(this).addApi(Wearable.API).build();
|
||||
Wearable.MessageApi.addListener(googleApiClient, this);
|
||||
if (googleApiClient.isConnected()) {
|
||||
Log.d("WatchUpdater", "API client is connected");
|
||||
log.debug(logPrefix + "API client is connected");
|
||||
} else {
|
||||
// Log.d("WatchUpdater", logPrefix + "API client is not connected and is trying to connect");
|
||||
googleApiClient.connect();
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +163,8 @@ public class WatchUpdaterService extends WearableListenerService implements
|
|||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
String action = intent != null ? intent.getAction() : null;
|
||||
|
||||
// Log.d(TAG, logPrefix + "onStartCommand: " + action);
|
||||
|
||||
if (wear_integration) {
|
||||
handler.post(() -> {
|
||||
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
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@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
|
||||
public void onMessageReceived(MessageEvent event) {
|
||||
|
||||
// Log.d(TAG, logPrefix + "onMessageRecieved: " + event);
|
||||
|
||||
if (wear_integration) {
|
||||
if (event != null && event.getPath().equals(WEARABLE_RESEND_PATH)) {
|
||||
resendData();
|
||||
|
@ -214,6 +291,7 @@ public class WatchUpdaterService extends WearableListenerService implements
|
|||
private void sendData() {
|
||||
|
||||
BgReading lastBG = DatabaseHelper.lastBg();
|
||||
// Log.d(TAG, logPrefix + "LastBg=" + lastBG);
|
||||
if (lastBG != null) {
|
||||
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
|
||||
|
||||
|
@ -228,11 +306,12 @@ public class WatchUpdaterService extends WearableListenerService implements
|
|||
return;
|
||||
}
|
||||
|
||||
new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient).execute(dataMap);
|
||||
executeTask(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient), dataMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private DataMap dataMapSingleBG(BgReading lastBG, GlucoseStatus glucoseStatus) {
|
||||
String units = ProfileFunctions.getInstance().getProfileUnits();
|
||||
|
||||
|
@ -287,7 +366,6 @@ public class WatchUpdaterService extends WearableListenerService implements
|
|||
deltastring += "+";
|
||||
} else {
|
||||
deltastring += "-";
|
||||
|
||||
}
|
||||
|
||||
boolean detailed = SP.getBoolean("wear_detailed_delta", false);
|
||||
|
@ -352,7 +430,7 @@ public class WatchUpdaterService extends WearableListenerService implements
|
|||
}
|
||||
}
|
||||
entries.putDataMapArrayList("entries", dataMaps);
|
||||
new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient).execute(entries);
|
||||
executeTask(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient), entries);
|
||||
}
|
||||
sendPreferences();
|
||||
sendBasals();
|
||||
|
@ -501,7 +579,7 @@ public class WatchUpdaterService extends WearableListenerService implements
|
|||
dm.putDataMapArrayList("boluses", boluses);
|
||||
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) {
|
||||
|
@ -548,6 +626,7 @@ public class WatchUpdaterService extends WearableListenerService implements
|
|||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||
dataMapRequest.getDataMap().putString("openSettings", "openSettings");
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
debugData("sendNotification", putDataRequest);
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
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().putInt("progresspercent", progresspercent);
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
debugData("sendBolusProgress", putDataRequest);
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
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);
|
||||
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
debugData("sendActionConfirmationRequest", putDataRequest);
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
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);
|
||||
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
debugData("sendChangeConfirmationRequest", putDataRequest);
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
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);
|
||||
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
debugData("sendCancelNotificationRequest", putDataRequest);
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} 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().putInt("batteryLevel", (phoneBattery >= 30) ? 1 : 0);
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
debugData("sendStatus", putDataRequest);
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
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().putBoolean("wearcontrol", wearcontrol);
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
debugData("sendPreferences", putDataRequest);
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
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
|
||||
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 {
|
||||
wearableVersion = "2.0.1"
|
||||
playServicesWearable = "10.2.1"
|
||||
}
|
||||
|
||||
def generateGitBuild = { ->
|
||||
|
@ -93,7 +94,7 @@ dependencies {
|
|||
//compile "com.ustwo.android:clockwise-wearable:1.0.2"
|
||||
compileOnly "com.google.android.wearable: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 "com.android.support:support-v4: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" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service android:name=".data.ListenerService">
|
||||
<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>
|
||||
</service>
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
|
@ -7,16 +10,24 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
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.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.DataEventBuffer;
|
||||
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.CPPActivity;
|
||||
import info.nightscout.androidaps.interaction.utils.SafeParse;
|
||||
import info.nightscout.androidaps.interaction.utils.WearUtil;
|
||||
|
||||
|
||||
/**
|
||||
* Created by emmablack on 12/26/14.
|
||||
*/
|
||||
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_RESEND_PATH = "/nightscout_watch_data_resend";
|
||||
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";
|
||||
|
||||
GoogleApiClient googleApiClient;
|
||||
private long lastRequest = 0;
|
||||
private DismissThread confirmThread;
|
||||
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> {
|
||||
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
|
||||
protected Void doInBackground(Void... params) {
|
||||
if (googleApiClient.isConnected()) {
|
||||
if (System.currentTimeMillis() - lastRequest > 20 * 1000) { // enforce 20-second debounce period
|
||||
// Log.d(TAG, logPrefix + "DataRequester: doInBack: " + params);
|
||||
|
||||
try {
|
||||
|
||||
forceGoogleApiConnect();
|
||||
DataMap datamap;
|
||||
|
||||
if (isCancelled()) {
|
||||
Log.d(TAG, "doInBackground CANCELLED programmatically");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (googleApiClient != null) {
|
||||
if (!googleApiClient.isConnected())
|
||||
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();
|
||||
|
||||
NodeApi.GetConnectedNodesResult nodes =
|
||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||
for (Node node : nodes.getNodes()) {
|
||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_RESEND_PATH, null);
|
||||
// NodeApi.GetConnectedNodesResult nodes =
|
||||
// Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||
if (localnode == null || (localnode != null && localnode.isEmpty()))
|
||||
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 {
|
||||
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
||||
if (googleApiClient.isConnected()) {
|
||||
if (System.currentTimeMillis() - lastRequest > 20 * 1000) { // enforce 20-second debounce period
|
||||
lastRequest = System.currentTimeMillis();
|
||||
|
||||
NodeApi.GetConnectedNodesResult nodes =
|
||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||
for (Node node : nodes.getNodes()) {
|
||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_RESEND_PATH, null);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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> {
|
||||
Context mContext;
|
||||
|
||||
|
@ -119,6 +248,8 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
// Log.d(TAG, logPrefix + "BolusCancelTask: doInBack: " + params);
|
||||
|
||||
if (googleApiClient.isConnected()) {
|
||||
NodeApi.GetConnectedNodesResult nodes =
|
||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||
|
@ -154,6 +285,9 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
|
||||
forceGoogleApiConnect();
|
||||
|
||||
if (googleApiClient.isConnected()) {
|
||||
NodeApi.GetConnectedNodesResult nodes =
|
||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||
|
@ -176,7 +310,7 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
}
|
||||
|
||||
public void requestData() {
|
||||
new DataRequester(this).execute();
|
||||
sendData(WEARABLE_RESEND_PATH, null);
|
||||
}
|
||||
|
||||
public void cancelBolus() {
|
||||
|
@ -191,7 +325,73 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
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)
|
||||
.addConnectionCallbacks(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
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
|
||||
// Log.d(TAG, logPrefix + "onStartCommand: Intent: " + intent);
|
||||
|
||||
if (intent != null && ACTION_RESEND.equals(intent.getAction())) {
|
||||
googleApiConnect();
|
||||
requestData();
|
||||
|
@ -256,13 +473,16 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
public void onDataChanged(DataEventBuffer dataEvents) {
|
||||
|
||||
DataMap dataMap;
|
||||
// Log.d(TAG, logPrefix + "onDataChanged: DataEvents=" + dataEvents);
|
||||
|
||||
for (DataEvent event : dataEvents) {
|
||||
|
||||
if (event.getType() == DataEvent.TYPE_CHANGED) {
|
||||
|
||||
|
||||
String path = event.getDataItem().getUri().getPath();
|
||||
|
||||
//Log.d(TAG, "WR: onDataChanged: Path: " + path + ", EventDataItem=" + event.getDataItem());
|
||||
|
||||
if (path.equals(OPEN_SETTINGS)) {
|
||||
Intent intent = new Intent(this, AAPSPreferences.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
@ -480,6 +700,21 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
googleApiClient.disconnect();
|
||||
}
|
||||
|
||||
if (googleApiClient != null) {
|
||||
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