wear fix overeager refactoring and plugin pluggable

This commit is contained in:
AdrianLxM 2016-11-17 16:38:58 +01:00
parent 2fd93a8e31
commit 761077e8ae
9 changed files with 553 additions and 9 deletions

View file

@ -81,6 +81,10 @@
android:enabled="true"
android:exported="false" />
<service android:name=".plugins.Wear.wearintegration.WatchUpdaterService" android:exported="true" >
<intent-filter> <action android:name="com.google.android.gms.wearable.BIND_LISTENER" /> </intent-filter>
</service>
<meta-data
android:name="io.fabric.ApiKey"
android:value="59d462666c664c57b29e1d79ea123e01f8057cfa" />

View file

@ -36,6 +36,7 @@ import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripFragment;
import info.nightscout.androidaps.plugins.TempBasals.TempBasalsFragment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment;
import info.nightscout.androidaps.plugins.VirtualPump.VirtualPumpFragment;
import info.nightscout.androidaps.plugins.Wear.WearFragment;
import io.fabric.sdk.android.Fabric;
@ -85,6 +86,9 @@ public class MainApp extends Application {
pluginsList.add(SourceNSClientFragment.getPlugin());
if (Config.SMSCOMMUNICATORENABLED)
pluginsList.add(SmsCommunicatorFragment.getPlugin());
pluginsList.add(WearFragment.getPlugin(this));
pluginsList.add(sConfigBuilder = ConfigBuilderFragment.getPlugin());
MainApp.getConfigBuilder().initialize();

View file

@ -18,15 +18,15 @@ public interface Intents {
String ACTION_RESTART = "info.nightscout.client.RESTART";
// xDrip -> App
String RECEIVER_PERMISSION = "info.nightscout.androidaps.permissions.RECEIVE_BG_ESTIMATE";
String RECEIVER_PERMISSION = "com.eveningoutpost.dexdrip.permissions.RECEIVE_BG_ESTIMATE";
String ACTION_NEW_BG_ESTIMATE = "info.nightscout.androidaps.BgEstimate";
String EXTRA_BG_ESTIMATE = "info.nightscout.androidaps.Extras.BgEstimate";
String EXTRA_BG_SLOPE = "info.nightscout.androidaps.Extras.BgSlope";
String EXTRA_BG_SLOPE_NAME = "info.nightscout.androidaps.Extras.BgSlopeName";
String EXTRA_SENSOR_BATTERY = "info.nightscout.androidaps.Extras.SensorBattery";
String EXTRA_TIMESTAMP = "info.nightscout.androidaps.Extras.Time";
String EXTRA_RAW = "info.nightscout.androidaps.Extras.Raw";
String ACTION_NEW_BG_ESTIMATE = "com.eveningoutpost.dexdrip.BgEstimate";
String EXTRA_BG_ESTIMATE = "com.eveningoutpost.dexdrip.Extras.BgEstimate";
String EXTRA_BG_SLOPE = "com.eveningoutpost.dexdrip.Extras.BgSlope";
String EXTRA_BG_SLOPE_NAME = "com.eveningoutpost.dexdrip.Extras.BgSlopeName";
String EXTRA_SENSOR_BATTERY = "com.eveningoutpost.dexdrip.Extras.SensorBattery";
String EXTRA_TIMESTAMP = "com.eveningoutpost.dexdrip.Extras.Time";
String EXTRA_RAW = "com.eveningoutpost.dexdrip.Extras.Raw";
String ACTION_NEW_BG_ESTIMATE_NO_DATA = "info.nightscout.androidaps.BgEstimateNoData";
String ACTION_NEW_BG_ESTIMATE_NO_DATA = "com.eveningoutpost.dexdrip.BgEstimateNoData";
}

View file

@ -0,0 +1,25 @@
package info.nightscout.androidaps.plugins.Wear;
import android.content.Context;
import info.nightscout.androidaps.interfaces.FragmentBase;
/**
* Created by adrian on 17/11/16.
*/
public class WearFragment implements FragmentBase {
private static WearPlugin wearPlugin;
public static WearPlugin getPlugin(Context ctx) {
if (wearPlugin == null){
wearPlugin = new WearPlugin(ctx);
}
return wearPlugin;
}
}

View file

@ -0,0 +1,115 @@
package info.nightscout.androidaps.plugins.Wear;
import android.content.Context;
import android.content.Intent;
import com.squareup.otto.Subscribe;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRefreshGui;
import info.nightscout.androidaps.events.EventTempBasalChange;
import info.nightscout.androidaps.events.EventTreatmentChange;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification;
import info.nightscout.androidaps.plugins.Wear.wearintegration.WatchUpdaterService;
/**
* Created by adrian on 17/11/16.
*/
public class WearPlugin implements PluginBase {
static boolean fragmentEnabled = true;
private final Context ctx;
WearPlugin(Context ctx){
this.ctx = ctx;
MainApp.bus().register(this);
}
@Override
public int getType() {
return PluginBase.GENERAL;
}
@Override
public String getFragmentClass() {
return WearFragment.class.getName();
}
@Override
public String getName() {
return "WearPlugin";
}
@Override
public boolean isEnabled(int type) {
return fragmentEnabled;
}
@Override
public boolean isVisibleInTabs(int type) {
return false;
}
@Override
public boolean canBeHidden(int type) {
return true;
}
@Override
public void setFragmentEnabled(int type, boolean fragmentEnabled) {
WearPlugin.fragmentEnabled = fragmentEnabled;
}
@Override
public void setFragmentVisible(int type, boolean fragmentVisible) {
}
private void sendDataToWatch(){
ctx.startService(new Intent(ctx, WatchUpdaterService.class));
}
/* @Subscribe
public void onStatusEvent(final EventPreferenceChange ev) {
sendDataToWatch();
}
@Subscribe
public void onStatusEvent(final EventRefreshGui ev) {
sendDataToWatch();
}
@Subscribe
public void onStatusEvent(final EventTreatmentChange ev) {
sendDataToWatch();
}*/
@Subscribe
public void onStatusEvent(final EventTempBasalChange ev) {
sendDataToWatch();
}
@Subscribe
public void onStatusEvent(final EventNewBG ev) {
sendDataToWatch();
}
/* @Subscribe
public void onStatusEvent(final EventNewOpenLoopNotification ev) {
sendDataToWatch();
}*/
@Subscribe
public void onStatusEvent(final EventNewBasalProfile ev) { sendDataToWatch(); }
}

View file

@ -0,0 +1,17 @@
package info.nightscout.androidaps.plugins.Wear.wearintegration;
import android.content.Context;
import android.content.Intent;
import android.support.v4.content.WakefulBroadcastReceiver;
/**
* Created by adrian on 14/02/16.
*/
public class ExternalStatusBroadcastReceier extends WakefulBroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
startWakefulService(context, new Intent(context, ExternalStatusService.class)
.setAction(ExternalStatusService.ACTION_NEW_EXTERNAL_STATUSLINE)
.putExtras(intent));
}
}

View file

@ -0,0 +1,61 @@
package info.nightscout.androidaps.plugins.Wear.wearintegration;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.support.v4.content.WakefulBroadcastReceiver;
/**
* Created by adrian on 14/02/16.
*/
public class ExternalStatusService extends IntentService{
//constants
public static final String EXTRA_STATUSLINE = "com.eveningoutpost.dexdrip.Extras.Statusline";
public static final String ACTION_NEW_EXTERNAL_STATUSLINE = "com.eveningoutpost.dexdrip.ExternalStatusline";
public static final String RECEIVER_PERMISSION = "com.eveningoutpost.dexdrip.permissions.RECEIVE_EXTERNAL_STATUSLINE";
public static final int MAX_LEN = 40;
public ExternalStatusService() {
super("ExternalStatusService");
setIntentRedelivery(true);
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent == null)
return;
final String action = intent.getAction();
try {
if (ACTION_NEW_EXTERNAL_STATUSLINE.equals(action)) {
String statusline = intent.getStringExtra(EXTRA_STATUSLINE);
if(statusline.length() > MAX_LEN){
statusline = statusline.substring(0, MAX_LEN);
}
if(statusline != null) {
// send to wear
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("wear_sync", false)) {
startService(new Intent(this, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_STATUS).putExtra("externalStatusString", statusline));
/*By integrating the watch part of Nightwatch we inherited the same wakelock
problems NW had - so adding the same quick fix for now.
TODO: properly "wakelock" the wear (and probably pebble) services
*/
PowerManager powerManager = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"quickFix4").acquire(15000);
}
}
}
} finally {
WakefulBroadcastReceiver.completeWakefulIntent(intent);
}
}
}

View file

@ -0,0 +1,52 @@
package info.nightscout.androidaps.plugins.Wear.wearintegration;
import android.os.AsyncTask;
import android.util.Log;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.DataApi;
import com.google.android.gms.wearable.DataMap;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.PutDataMapRequest;
import com.google.android.gms.wearable.PutDataRequest;
import com.google.android.gms.wearable.Wearable;
import java.util.concurrent.TimeUnit;
/**
* Created by stephenblack on 12/26/14.
*/
class SendToDataLayerThread extends AsyncTask<DataMap,Void,Void> {
private GoogleApiClient googleApiClient;
private static final String TAG = "SendDataThread";
String path;
SendToDataLayerThread(String path, GoogleApiClient pGoogleApiClient) {
this.path = path;
googleApiClient = pGoogleApiClient;
}
@Override
protected Void doInBackground(DataMap... params) {
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");
}
}
}
} catch (Exception e) {
Log.e(TAG, "Got exception sending data to wear: " + e.toString());
}
return null;
}
}

View file

@ -0,0 +1,266 @@
package info.nightscout.androidaps.plugins.Wear.wearintegration;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
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.DataMap;
import com.google.android.gms.wearable.MessageEvent;
import com.google.android.gms.wearable.PutDataMapRequest;
import com.google.android.gms.wearable.PutDataRequest;
import com.google.android.gms.wearable.Wearable;
import com.google.android.gms.wearable.WearableListenerService;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import info.nightscout.utils.ToastUtils;
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");
private GoogleApiClient googleApiClient;
public static final String WEARABLE_DATA_PATH = "/nightscout_watch_data";
public static final String WEARABLE_RESEND_PATH = "/nightscout_watch_data_resend";
private static final String OPEN_SETTINGS_PATH = "/openwearsettings";
private static final String NEW_STATUS_PATH = "/sendstatustowear";
boolean wear_integration = false;
boolean pebble_integration = false;
SharedPreferences mPrefs;
SharedPreferences.OnSharedPreferenceChangeListener mPreferencesListener;
@Override
public void onCreate() {
mPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
listenForChangeInSettings();
setSettings();
if (wear_integration) {
googleApiConnect();
}
}
public void listenForChangeInSettings() {
mPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
setSettings();
}
};
mPrefs.registerOnSharedPreferenceChangeListener(mPreferencesListener);
}
public void setSettings() {
//TODO Adrian: check if wear plugin is active or better: Never call from Plugin if not enabled!
wear_integration = true; //mPrefs.getBoolean("wear_sync", false);
if (wear_integration) {
googleApiConnect();
}
}
public void googleApiConnect() {
if(googleApiClient != null && (googleApiClient.isConnected() || googleApiClient.isConnecting())) { googleApiClient.disconnect(); }
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");
} else {
googleApiClient.connect();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
double timestamp = 0;
if (intent != null) {
timestamp = intent.getDoubleExtra("timestamp", 0);
}
String action = null;
if (intent != null) {
action = intent.getAction();
}
if (wear_integration) {
if (googleApiClient.isConnected()) {
if (ACTION_RESEND.equals(action)) {
resendData();
} else if (ACTION_OPEN_SETTINGS.equals(action)) {
sendNotification();
} else if (ACTION_SEND_STATUS.equals(action)) {
sendStatus(intent.getStringExtra("externalStatusString"));
} else {
sendData();
}
} else {
googleApiClient.connect();
}
}
return START_STICKY;
}
@Override
public void onConnected(Bundle connectionHint) {
sendData();
}
@Override
public void onMessageReceived(MessageEvent event) {
if (wear_integration) {
if (event != null && event.getPath().equals(WEARABLE_RESEND_PATH))
resendData();
}
}
public void sendData() {
/**
BgReading bg = BgReading.last();
if (bg != null) {
if(googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) { googleApiConnect(); }
if (wear_integration) {
new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient).execute(dataMap(bg, mPrefs, new BgGraphBuilder(getApplicationContext())));
}
}*/
ToastUtils.showToastInUiThread(this, "sendData()");
}
private void resendData() {
/**if(googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) { googleApiConnect(); }
long startTime = new Date().getTime() - (60000 * 60 * 24);
BgReading last_bg = BgReading.last();
List<BgReading> graph_bgs = BgReading.latestForGraph(60, startTime);
BgGraphBuilder bgGraphBuilder = new BgGraphBuilder(getApplicationContext());
if (!graph_bgs.isEmpty()) {
DataMap entries = dataMap(last_bg, mPrefs, bgGraphBuilder);
final ArrayList<DataMap> dataMaps = new ArrayList<>(graph_bgs.size());
for (BgReading bg : graph_bgs) {
dataMaps.add(dataMap(bg, mPrefs, bgGraphBuilder));
}
entries.putDataMapArrayList("entries", dataMaps);
new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient).execute(entries);
}*/
ToastUtils.showToastInUiThread(this, "resendData()");
}
private void sendNotification() {
if (googleApiClient.isConnected()) {
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(OPEN_SETTINGS_PATH);
//unique content
dataMapRequest.getDataMap().putDouble("timestamp", System.currentTimeMillis());
dataMapRequest.getDataMap().putString("openSettings", "openSettings");
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("OpenSettings", "No connection to wearable available!");
}
}
private void sendStatus(String status) {
if (googleApiClient.isConnected()) {
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(NEW_STATUS_PATH);
//unique content
dataMapRequest.getDataMap().putDouble("timestamp", System.currentTimeMillis());
dataMapRequest.getDataMap().putString("externalStatusString", status);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("SendStatus", "No connection to wearable available!");
}
}
/**private DataMap dataMap(BgReading bg, SharedPreferences sPrefs, BgGraphBuilder bgGraphBuilder) {
Double highMark = Double.parseDouble(sPrefs.getString("highValue", "170"));
Double lowMark = Double.parseDouble(sPrefs.getString("lowValue", "70"));
DataMap dataMap = new DataMap();
int battery = BgSendQueue.getBatteryLevel(getApplicationContext());
dataMap.putString("sgvString", bgGraphBuilder.unitized_string(bg.calculated_value));
dataMap.putString("slopeArrow", bg.slopeArrow());
dataMap.putDouble("timestamp", bg.timestamp); //TODO: change that to long (was like that in NW)
dataMap.putString("delta", bgGraphBuilder.unitizedDeltaString(true, true));
dataMap.putString("battery", "" + battery);
dataMap.putLong("sgvLevel", sgvLevel(bg.calculated_value, sPrefs, bgGraphBuilder));
dataMap.putInt("batteryLevel", (battery>=30)?1:0);
dataMap.putDouble("sgvDouble", bg.calculated_value);
dataMap.putDouble("high", inMgdl(highMark, sPrefs));
dataMap.putDouble("low", inMgdl(lowMark, sPrefs));
//TODO: Add raw again
//dataMap.putString("rawString", threeRaw((prefs.getString("units", "mgdl").equals("mgdl"))));
return dataMap;
}
// TODO: Integrate these helper methods into BGGraphBuilder.
// TODO: clean them up (no "if(boolean){return true; else return false;").
// TODO: Make the needed methods in BgGraphBuilder static.
public long sgvLevel(double sgv_double, SharedPreferences prefs, BgGraphBuilder bgGB) {
Double highMark = Double.parseDouble(prefs.getString("highValue", "170"));
Double lowMark = Double.parseDouble(prefs.getString("lowValue", "70"));
if(bgGB.unitized(sgv_double) >= highMark) {
return 1;
} else if (bgGB.unitized(sgv_double) >= lowMark) {
return 0;
} else {
return -1;
}
}
public double inMgdl(double value, SharedPreferences sPrefs) {
if (!doMgdl(sPrefs)) {
return value * Constants.MMOLL_TO_MGDL;
} else {
return value;
}
}
public boolean doMgdl(SharedPreferences sPrefs) {
String unit = sPrefs.getString("units", "mgdl");
if (unit.compareTo("mgdl") == 0) {
return true;
} else {
return false;
}
}
*/
@Override
public void onDestroy() {
if (googleApiClient != null && googleApiClient.isConnected()) {
googleApiClient.disconnect();
}
if (mPrefs != null && mPreferencesListener != null) {
mPrefs.unregisterOnSharedPreferenceChangeListener(mPreferencesListener);
}
}
@Override
public void onConnectionSuspended(int cause) {
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
}