diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index df86b0ef65..339c7e2716 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -356,6 +356,16 @@ android:resource="@xml/x_drip_widget_info" /> + + + + + + + + lastReadings = BgReading.latest(2); BgReading lastReading = null; diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/WidgetUpdateService.java b/app/src/main/java/com/eveningoutpost/dexdrip/WidgetUpdateService.java index 595d1abb45..6cc2b9dbff 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/WidgetUpdateService.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/WidgetUpdateService.java @@ -15,36 +15,16 @@ import com.eveningoutpost.dexdrip.Models.UserError.Log; public class WidgetUpdateService extends Service { + static Context context; private static final String TAG = "WidgetUpdateService"; - - private boolean isRegistered = false; - - public static void staticRefreshWidgets() - { - try { - Context context = xdrip.getAppContext(); - if (AppWidgetManager.getInstance(context).getAppWidgetIds(new ComponentName(context, xDripWidget.class)).length > 0) { - context.startService(new Intent(context, WidgetUpdateService.class)); - } - } catch (Exception e) - { - Log.e(TAG,"Got exception in staticRefreshWidgets: "+e); - } - } + private static Class widgetClasses[] = { xDripWidget.class, gearWidget.class }; private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context ctx, Intent intent) { final PowerManager.WakeLock wl = JoH.getWakeLock("xdrip-widget-bcast", 20000); //Log.d(TAG, "onReceive("+intent.getAction()+")"); - if (intent.getAction().compareTo(Intent.ACTION_TIME_TICK) == 0) { - updateCurrentBgInfo(); - } else if (intent.getAction().compareTo(Intent.ACTION_SCREEN_ON) == 0) { - enableClockTicks(); - updateCurrentBgInfo(); - } else if (intent.getAction().compareTo(Intent.ACTION_SCREEN_OFF) == 0) { - disableClockTicks(); - } + if (intent.getAction().compareTo(Intent.ACTION_TIME_TICK) == 0) updateCurrentBgInfo(); JoH.releaseWakeLock(wl); } }; @@ -55,41 +35,17 @@ public WidgetUpdateService() {} @Override public void onCreate() { + context = getApplicationContext(); super.onCreate(); - PowerManager pm = (PowerManager) getSystemService(Service.POWER_SERVICE); - Log.d(TAG, "onCreate"); - if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && pm.isInteractive()) || - (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && pm.isScreenOn())) - enableClockTicks(); - else - disableClockTicks(); } - private void enableClockTicks() { + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + //Gear widget needs clock ticks all the time to keep time updated in widget Log.d(TAG, "enableClockTicks"); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_TIME_TICK); - intentFilter.addAction(Intent.ACTION_SCREEN_ON); - intentFilter.addAction(Intent.ACTION_SCREEN_OFF); - if (isRegistered) - unregisterReceiver(broadcastReceiver); registerReceiver(broadcastReceiver, intentFilter); - isRegistered = true; - } - - private void disableClockTicks() { - Log.d(TAG, "disableClockTicks"); - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_SCREEN_ON); - intentFilter.addAction(Intent.ACTION_SCREEN_OFF); - if (isRegistered) - unregisterReceiver(broadcastReceiver); - registerReceiver(broadcastReceiver, intentFilter); - isRegistered = true; - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { updateCurrentBgInfo(); return START_STICKY; } @@ -97,19 +53,23 @@ public int onStartCommand(Intent intent, int flags, int startId) { @Override public void onDestroy() { super.onDestroy(); - if (broadcastReceiver != null) { - unregisterReceiver(broadcastReceiver); - isRegistered = false; - } + unregisterReceiver(broadcastReceiver); } - public void updateCurrentBgInfo() { - Log.d(TAG, "Sending update flag to widget"); - int ids[] = AppWidgetManager.getInstance(getApplication()).getAppWidgetIds(new ComponentName(getApplication(), xDripWidget.class)); - Log.d(TAG, "Updating " + ids.length + " widgets"); - Intent intent = new Intent(this,xDripWidget.class); - intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,ids); - sendBroadcast(intent); + public static void updateCurrentBgInfo() { + Log.d(TAG, "Sending update flag to widgets"); + int ids[]; + Intent intent; + //iterate each widget type, get IDs of all instances, update + for (Class widgetClass : widgetClasses) { + ids = AppWidgetManager.getInstance(context).getAppWidgetIds(new ComponentName(context, widgetClass)); + if (ids.length > 0) { + Log.d(TAG, "Updating " + ids.length + " " + widgetClass.getName() + " instances"); + intent = new Intent(context, widgetClass); + intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids); + context.sendBroadcast(intent); + } + } } } diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/gearWidget.java b/app/src/main/java/com/eveningoutpost/dexdrip/gearWidget.java new file mode 100644 index 0000000000..03c2cf84b6 --- /dev/null +++ b/app/src/main/java/com/eveningoutpost/dexdrip/gearWidget.java @@ -0,0 +1,207 @@ +package com.eveningoutpost.dexdrip; + +import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProvider; +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.PowerManager; +import android.view.View; +import android.widget.RemoteViews; + +import com.eveningoutpost.dexdrip.Models.BgReading; +import com.eveningoutpost.dexdrip.Models.JoH; +import com.eveningoutpost.dexdrip.Models.UserError.Log; +import com.eveningoutpost.dexdrip.UtilityModels.BgGraphBuilder; +import com.eveningoutpost.dexdrip.UtilityModels.BgSparklineBuilder; +import com.eveningoutpost.dexdrip.UtilityModels.ColorCache; +import com.eveningoutpost.dexdrip.UtilityModels.Pref; +import com.eveningoutpost.dexdrip.calibrations.PluggableCalibration; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + + +/** + * Implementation of App Widget functionality. + */ +public class gearWidget extends AppWidgetProvider { + + public static final String TAG = "gearWidget"; + private static final boolean use_best_glucose = true; + + @Override + public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + final PowerManager.WakeLock wl = JoH.getWakeLock("gear-widget-onupdate", 20000); + final int N = appWidgetIds.length; + for (int i = 0; i < N; i++) { + + //update the widget + updateAppWidget(context, appWidgetManager, appWidgetIds[i]); + + } + JoH.releaseWakeLock(wl); + } + + @Override + public void onEnabled(Context context) { + Log.d(TAG, "Widget enabled"); + context.startService(new Intent(context, WidgetUpdateService.class)); + } + + @Override + public void onDisabled(Context context) { + Log.d(TAG, "Widget disabled"); + // Enter relevant functionality for when the last widget is disabled + } + + private static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { + RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.gear_widget); + Log.d(TAG, "Update widget signal received"); + + //Add behaviour: open xDrip on click + Intent intent = new Intent(context, Home.class); + PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); + views.setOnClickPendingIntent(R.id.gearWidget, pendingIntent); + displayCurrentInfo(appWidgetManager, appWidgetId, context, views); + try { + appWidgetManager.updateAppWidget(appWidgetId, views); + // needed to catch RuntimeException and DeadObjectException + } catch (Exception e) { + Log.e(TAG, "Got Rexception in widget update: " + e); + } + } + + + private static void displayCurrentInfo(AppWidgetManager appWidgetManager, int appWidgetId, Context context, RemoteViews views) { + BgGraphBuilder bgGraphBuilder = new BgGraphBuilder(context); + BgReading lastBgreading = BgReading.lastNoSenssor(); + + //update time and date + SimpleDateFormat formatter = new SimpleDateFormat(); + Date now = new Date(); + formatter.applyPattern("h:mm a"); + views.setTextViewText(R.id.textTime, formatter.format(now)); + formatter.applyPattern("MMMM dd, YYYY"); + views.setTextViewText(R.id.textDate, formatter.format(now)); + formatter.applyPattern("EEEE"); + views.setTextViewText(R.id.textDay, formatter.format(now)); + + if (lastBgreading != null) { + double estimate = 0; + double estimated_delta = -9999; + try { + int height = appWidgetManager.getAppWidgetOptions(appWidgetId).getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT); + int width = appWidgetManager.getAppWidgetOptions(appWidgetId).getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH); + views.setImageViewBitmap(R.id.widgetGraph, new BgSparklineBuilder(context) + .setBgGraphBuilder(bgGraphBuilder) + .setShowFiltered(Pref.getBooleanDefaultFalse("show_filtered_curve")) + .setBackgroundColor(ColorCache.getCol(ColorCache.X.color_widget_chart_background)) + .setHeight(height).setWidth(width).showHighLine(true).showLowLine(true).showAxes(true).build()); + + final BestGlucose.DisplayGlucose dg = (use_best_glucose) ? BestGlucose.getDisplayGlucose() : null; + estimate = (dg != null) ? dg.mgdl : lastBgreading.calculated_value; + String extrastring = ""; + String slope_arrow = (dg != null) ? dg.delta_arrow : lastBgreading.slopeArrow(); + String stringEstimate; + + if (dg == null) { + // if not using best glucose helper + if (BestGlucose.compensateNoise()) { + estimate = BgGraphBuilder.best_bg_estimate; // this needs scaling based on noise intensity + estimated_delta = BgGraphBuilder.best_bg_estimate - BgGraphBuilder.last_bg_estimate; + slope_arrow = BgReading.slopeToArrowSymbol(estimated_delta / (BgGraphBuilder.DEXCOM_PERIOD / 60000)); // delta by minute + //currentBgValueText.setTypeface(null, Typeface.ITALIC); + extrastring = " \u26A0"; // warning symbol ! + + } + // TODO functionize this check as it is in multiple places + if (Pref.getBooleanDefaultFalse("display_glucose_from_plugin") && (PluggableCalibration.getCalibrationPluginFromPreferences() != null)) { + extrastring += " " + context.getString(R.string.p_in_circle); + } + } else { + // TODO make a couple of getters in dg for these functions + extrastring = " "+dg.extra_string + ((dg.from_plugin) ? " " + context.getString(R.string.p_in_circle) : ""); + estimated_delta = dg.delta_mgdl; + // TODO properly illustrate + standardize warning level + if (dg.warning > 1) slope_arrow = ""; + } + + // TODO use dg stale calculation and/or preformatted text + if ((new Date().getTime()) - Home.stale_data_millis() - lastBgreading.timestamp > 0) { +// estimate = lastBgreading.calculated_value; + Log.d(TAG, "old value, estimate " + estimate); + stringEstimate = bgGraphBuilder.unitized_string(estimate); + + //views.setTextViewText(R.id.widgetArrow, "--"); + slope_arrow = "--"; + views.setInt(R.id.widgetBg, "setPaintFlags", Paint.STRIKE_THRU_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG); + } else { +// estimate = lastBgreading.calculated_value; + stringEstimate = bgGraphBuilder.unitized_string(estimate); + + if (lastBgreading.hide_slope) { + slope_arrow = "--"; + } + Log.d(TAG, "newish value, estimate " + stringEstimate + slope_arrow); + + + views.setInt(R.id.widgetBg, "setPaintFlags", 0); + } + views.setTextViewText(R.id.widgetBg, stringEstimate); + views.setTextViewText(R.id.widgetArrow, slope_arrow); + + // is it really necessary to read this data once here and again in unitizedDeltaString? + // couldn't we just use the unitizedDeltaString to detect the error condition? + List bgReadingList = BgReading.latest(2, Home.get_follower()); + + if (estimated_delta == -9999) { + // use original delta + if (bgReadingList != null && bgReadingList.size() == 2) { + + views.setTextViewText(R.id.widgetDelta, bgGraphBuilder.unitizedDeltaString(true, true, Home.get_follower())); + } else { + views.setTextViewText(R.id.widgetDelta, "--"); + } + } else { + // use compensated estimate + views.setTextViewText(R.id.widgetDelta, bgGraphBuilder.unitizedDeltaStringRaw(true, true, estimated_delta)); + } + + // TODO use dg preformatted localized string + int timeAgo = (int) Math.floor((new Date().getTime() - lastBgreading.timestamp) / (1000 * 60)); + if (timeAgo == 1) { + views.setTextViewText(R.id.readingAge, timeAgo + " Minute ago" + extrastring); + } else { + views.setTextViewText(R.id.readingAge, timeAgo + " Minutes ago" + extrastring); + } + if (timeAgo > 15) { + views.setTextColor(R.id.readingAge, Color.parseColor("#FFBB33")); + } else { + views.setTextColor(R.id.readingAge, Color.WHITE); + } + + if (bgGraphBuilder.unitized(estimate) <= bgGraphBuilder.lowMark) { + views.setTextColor(R.id.widgetBg, Color.parseColor("#C30909")); + views.setTextColor(R.id.widgetDelta, Color.parseColor("#C30909")); + views.setTextColor(R.id.widgetArrow, Color.parseColor("#C30909")); + } else if (bgGraphBuilder.unitized(estimate) >= bgGraphBuilder.highMark) { + views.setTextColor(R.id.widgetBg, Color.parseColor("#FFBB33")); + views.setTextColor(R.id.widgetDelta, Color.parseColor("#FFBB33")); + views.setTextColor(R.id.widgetArrow, Color.parseColor("#FFBB33")); + } else { + views.setTextColor(R.id.widgetBg, Color.WHITE); + views.setTextColor(R.id.widgetDelta, Color.WHITE); + views.setTextColor(R.id.widgetArrow, Color.WHITE); + } + } catch (RuntimeException e) { + Log.e(TAG, "Got exception in displaycurrentinfo: " + e); + } + } + } +} + + diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/xdrip.java b/app/src/main/java/com/eveningoutpost/dexdrip/xdrip.java index 40aec92b50..423a3f7d4d 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/xdrip.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/xdrip.java @@ -3,6 +3,7 @@ import android.annotation.SuppressLint; import android.app.Application; import android.content.Context; +import android.content.Intent; import android.content.ContextWrapper; import android.content.res.Configuration; import android.os.Build; @@ -53,6 +54,10 @@ public class xdrip extends Application { public void onCreate() { xdrip.context = getApplicationContext(); super.onCreate(); + + //start widget update service to capture time ticks + this.startService(new Intent(this, WidgetUpdateService.class)); + try { if (PreferenceManager.getDefaultSharedPreferences(xdrip.context).getBoolean("enable_crashlytics", true)) { initCrashlytics(this); diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/xdrip_BACKUP_21232.java b/app/src/main/java/com/eveningoutpost/dexdrip/xdrip_BACKUP_21232.java new file mode 100644 index 0000000000..9ccba77061 --- /dev/null +++ b/app/src/main/java/com/eveningoutpost/dexdrip/xdrip_BACKUP_21232.java @@ -0,0 +1,237 @@ +package com.eveningoutpost.dexdrip; + +import android.annotation.SuppressLint; +import android.app.Application; +import android.content.Context; +<<<<<<< HEAD +import android.content.Intent; +======= +import android.content.ContextWrapper; +>>>>>>> upstream/master +import android.content.res.Configuration; +import android.os.Build; +import android.preference.PreferenceManager; +import android.util.Log; + +import com.crashlytics.android.Crashlytics; +import com.crashlytics.android.core.CrashlyticsCore; +import com.eveningoutpost.dexdrip.Models.AlertType; +import com.eveningoutpost.dexdrip.Models.JoH; +import com.eveningoutpost.dexdrip.Models.Reminder; +import com.eveningoutpost.dexdrip.Services.ActivityRecognizedService; +import com.eveningoutpost.dexdrip.Services.BluetoothGlucoseMeter; +import com.eveningoutpost.dexdrip.Services.MissedReadingService; +import com.eveningoutpost.dexdrip.Services.PlusSyncService; +import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter; +import com.eveningoutpost.dexdrip.UtilityModels.IdempotentMigrations; +import com.eveningoutpost.dexdrip.UtilityModels.PlusAsyncExecutor; +import com.eveningoutpost.dexdrip.UtilityModels.Pref; +import com.eveningoutpost.dexdrip.UtilityModels.VersionTracker; +import com.eveningoutpost.dexdrip.calibrations.PluggableCalibration; +import com.eveningoutpost.dexdrip.webservices.XdripWebService; + +import java.util.Locale; + +import io.fabric.sdk.android.Fabric; + +//import com.bugfender.sdk.Bugfender; + +/** + * Created by Emma Black on 3/21/15. + */ + +public class xdrip extends Application { + + private static final String TAG = "xdrip.java"; + @SuppressLint("StaticFieldLeak") + private static Context context; + private static boolean fabricInited = false; + private static boolean bfInited = false; + private static Locale LOCALE; + public static PlusAsyncExecutor executor; + public static boolean useBF = false; + private static Boolean isRunningTestCache; + + + @Override + public void onCreate() { + xdrip.context = getApplicationContext(); + super.onCreate(); + + //start widget update service to capture time ticks + this.startService(new Intent(this, WidgetUpdateService.class)); + + try { + if (PreferenceManager.getDefaultSharedPreferences(xdrip.context).getBoolean("enable_crashlytics", true)) { + initCrashlytics(this); + initBF(); + } + } catch (Exception e) { + Log.e(TAG, e.toString()); + } + executor = new PlusAsyncExecutor(); + PreferenceManager.setDefaultValues(this, R.xml.pref_general, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_data_sync, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_advanced_settings, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_notifications, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_data_source, true); + PreferenceManager.setDefaultValues(this, R.xml.xdrip_plus_defaults, true); + PreferenceManager.setDefaultValues(this, R.xml.xdrip_plus_prefs, true); + + checkForcedEnglish(xdrip.context); + + + JoH.ratelimit("policy-never", 3600); // don't on first load + new IdempotentMigrations(getApplicationContext()).performAll(); + + + if (!isRunningTest()) { + MissedReadingService.delayedLaunch(); + NFCReaderX.handleHomeScreenScanPreference(getApplicationContext()); + AlertType.fromSettings(getApplicationContext()); + //new CollectionServiceStarter(getApplicationContext()).start(getApplicationContext()); + CollectionServiceStarter.restartCollectionServiceBackground(); + PlusSyncService.startSyncService(context, "xdrip.java"); + if (Pref.getBoolean("motion_tracking_enabled", false)) { + ActivityRecognizedService.startActivityRecogniser(getApplicationContext()); + } + BluetoothGlucoseMeter.startIfEnabled(); + XdripWebService.immortality(); + VersionTracker.updateDevice(); + + } else { + Log.d(TAG, "Detected running test mode, holding back on background processes"); + } + Reminder.firstInit(xdrip.getAppContext()); + PluggableCalibration.invalidateCache(); + } + + public synchronized static void initCrashlytics(Context context) { + if ((!fabricInited) && !isRunningTest()) { + try { + Crashlytics crashlyticsKit = new Crashlytics.Builder() + .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()) + .build(); + Fabric.with(context, crashlyticsKit); + } catch (Exception e) { + Log.e(TAG, e.toString()); + } + fabricInited = true; + } + } + + public static synchronized boolean isRunningTest() { + if (null == isRunningTestCache) { + boolean test_framework; + try { + Class.forName("android.support.test.espresso.Espresso"); + test_framework = true; + } catch (ClassNotFoundException e) { + test_framework = false; + } + isRunningTestCache = test_framework; + } + return isRunningTestCache; + } + + public synchronized static void initBF() { + try { + if (PreferenceManager.getDefaultSharedPreferences(xdrip.context).getBoolean("enable_bugfender", false)) { + new Thread() { + @Override + public void run() { + String app_id = PreferenceManager.getDefaultSharedPreferences(xdrip.context).getString("bugfender_appid", "").trim(); + if (!useBF && (app_id.length() > 10)) { + if (!bfInited) { + //Bugfender.init(xdrip.context, app_id, BuildConfig.DEBUG); + bfInited = true; + } + useBF = true; + } + } + }.start(); + } else { + useBF = false; + } + } catch (Exception e) { + // + } + } + + + public static Context getAppContext() { + return xdrip.context; + } + + public static boolean checkAppContext(Context context) { + if (getAppContext() == null) { + xdrip.context = context; + return false; + } else { + return true; + } + } + + public static void checkForcedEnglish(Context context) { + if (Pref.getBoolean("force_english", false)) { + final String forced_language = Pref.getString("forced_language", "en"); + final String current_language = Locale.getDefault().getLanguage(); + if (!current_language.equals(forced_language)) { + Log.i(TAG, "Forcing locale: " + forced_language + " was: " + current_language); + LOCALE = new Locale(forced_language, "", ""); + Locale.setDefault(LOCALE); + final Configuration config = context.getResources().getConfiguration(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + config.setLocale(LOCALE); + } else { + config.locale = LOCALE; + } + try { + ((Application) context).getBaseContext().getResources().updateConfiguration(config, ((Application) context).getBaseContext().getResources().getDisplayMetrics()); + } catch (ClassCastException e) { + // + } + try { + context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics()); + } catch (ClassCastException e) { + // + + } + } + Log.d(TAG, "Already set to locale: " + forced_language); + } + } + + // force language on oreo activities + public static Context getLangContext(Context context) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && Pref.getBooleanDefaultFalse("force_english")) { + final String forced_language = Pref.getString("forced_language", "en"); + final Configuration config = context.getResources().getConfiguration(); + + if (LOCALE == null) LOCALE = new Locale(forced_language); + Locale.setDefault(LOCALE); + config.setLocale(LOCALE); + context = context.createConfigurationContext(config); + //Log.d(TAG, "Sending language context for: " + LOCALE); + return new ContextWrapper(context); + } else { + return context; + } + } catch (Exception e) { + Log.e(TAG, "Got exception in getLangContext: " + e); + return context; + } + } + + + public static String gs(int id) { + return getAppContext().getString(id); + } + + public static String gs(int id, String... args) { + return getAppContext().getString(id, (Object[]) args); + } + + //} +} diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/xdrip_BASE_21232.java b/app/src/main/java/com/eveningoutpost/dexdrip/xdrip_BASE_21232.java new file mode 100644 index 0000000000..b16938859c --- /dev/null +++ b/app/src/main/java/com/eveningoutpost/dexdrip/xdrip_BASE_21232.java @@ -0,0 +1,194 @@ +package com.eveningoutpost.dexdrip; + +import android.annotation.SuppressLint; +import android.app.Application; +import android.content.Context; +import android.content.res.Configuration; +import android.preference.PreferenceManager; +import android.util.Log; + +import com.crashlytics.android.Crashlytics; +import com.crashlytics.android.core.CrashlyticsCore; +import com.eveningoutpost.dexdrip.Models.AlertType; +import com.eveningoutpost.dexdrip.Models.JoH; +import com.eveningoutpost.dexdrip.Models.Reminder; +import com.eveningoutpost.dexdrip.Services.ActivityRecognizedService; +import com.eveningoutpost.dexdrip.Services.BluetoothGlucoseMeter; +import com.eveningoutpost.dexdrip.Services.MissedReadingService; +import com.eveningoutpost.dexdrip.Services.PlusSyncService; +import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter; +import com.eveningoutpost.dexdrip.UtilityModels.IdempotentMigrations; +import com.eveningoutpost.dexdrip.UtilityModels.PlusAsyncExecutor; +import com.eveningoutpost.dexdrip.UtilityModels.Pref; +import com.eveningoutpost.dexdrip.calibrations.PluggableCalibration; +import com.eveningoutpost.dexdrip.webservices.XdripWebService; + +import java.util.Locale; + +import io.fabric.sdk.android.Fabric; + +//import com.bugfender.sdk.Bugfender; + +/** + * Created by Emma Black on 3/21/15. + */ + +public class xdrip extends Application { + + private static final String TAG = "xdrip.java"; + @SuppressLint("StaticFieldLeak") + private static Context context; + private static boolean fabricInited = false; + private static boolean bfInited = false; + private static Locale LOCALE; + public static PlusAsyncExecutor executor; + public static boolean useBF = false; + private static Boolean isRunningTestCache; + + + @Override + public void onCreate() { + xdrip.context = getApplicationContext(); + super.onCreate(); + try { + if (PreferenceManager.getDefaultSharedPreferences(xdrip.context).getBoolean("enable_crashlytics", true)) { + initCrashlytics(this); + initBF(); + } + } catch (Exception e) { + Log.e(TAG, e.toString()); + } + executor = new PlusAsyncExecutor(); + PreferenceManager.setDefaultValues(this, R.xml.pref_general, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_data_sync, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_advanced_settings, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_notifications, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_data_source, true); + PreferenceManager.setDefaultValues(this, R.xml.xdrip_plus_defaults, true); + PreferenceManager.setDefaultValues(this, R.xml.xdrip_plus_prefs, true); + + checkForcedEnglish(xdrip.context); + + + JoH.ratelimit("policy-never", 3600); // don't on first load + new IdempotentMigrations(getApplicationContext()).performAll(); + + + if (!isRunningTest()) { + MissedReadingService.delayedLaunch(); + NFCReaderX.handleHomeScreenScanPreference(getApplicationContext()); + AlertType.fromSettings(getApplicationContext()); + new CollectionServiceStarter(getApplicationContext()).start(getApplicationContext()); + PlusSyncService.startSyncService(context, "xdrip.java"); + if (Pref.getBoolean("motion_tracking_enabled", false)) { + ActivityRecognizedService.startActivityRecogniser(getApplicationContext()); + } + BluetoothGlucoseMeter.startIfEnabled(); + XdripWebService.immortality(); + + } else { + Log.d(TAG, "Detected running test mode, holding back on background processes"); + } + Reminder.firstInit(xdrip.getAppContext()); + PluggableCalibration.invalidateCache(); + } + + public synchronized static void initCrashlytics(Context context) { + if ((!fabricInited) && !isRunningTest()) { + try { + Crashlytics crashlyticsKit = new Crashlytics.Builder() + .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()) + .build(); + Fabric.with(context, crashlyticsKit); + } catch (Exception e) { + Log.e(TAG, e.toString()); + } + fabricInited = true; + } + } + + public static synchronized boolean isRunningTest() { + if (null == isRunningTestCache) { + boolean test_framework; + try { + Class.forName("android.support.test.espresso.Espresso"); + test_framework = true; + } catch (ClassNotFoundException e) { + test_framework = false; + } + isRunningTestCache = test_framework; + } + return isRunningTestCache; + } + + public synchronized static void initBF() { + try { + if (PreferenceManager.getDefaultSharedPreferences(xdrip.context).getBoolean("enable_bugfender", false)) { + new Thread() { + @Override + public void run() { + String app_id = PreferenceManager.getDefaultSharedPreferences(xdrip.context).getString("bugfender_appid", "").trim(); + if (!useBF && (app_id.length() > 10)) { + if (!bfInited) { + //Bugfender.init(xdrip.context, app_id, BuildConfig.DEBUG); + bfInited = true; + } + useBF = true; + } + } + }.start(); + } else { + useBF = false; + } + } catch (Exception e) { + // + } + } + + + public static Context getAppContext() { + return xdrip.context; + } + + public static boolean checkAppContext(Context context) { + if (getAppContext() == null) { + xdrip.context = context; + return false; + } else { + return true; + } + } + + public static void checkForcedEnglish(Context context) { + // if (Locale.getDefault() != Locale.ENGLISH) { + // Log.d(TAG, "Locale is non-english"); + if (Pref.getBoolean("force_english", false)) { + final String forced_language = Pref.getString("forced_language", "en"); + final String current_language = Locale.getDefault().getLanguage(); + if (!current_language.equals(forced_language)) { + Log.i(TAG, "Forcing locale: " + forced_language + " was: " + current_language); + LOCALE = new Locale(forced_language, "", ""); + Locale.setDefault(LOCALE); + Configuration config = context.getResources().getConfiguration(); + config.locale = LOCALE; + try { + ((Application) context).getBaseContext().getResources().updateConfiguration(config, ((Application) context).getBaseContext().getResources().getDisplayMetrics()); + } catch (ClassCastException e) { + Log.i(TAG, "Using activity context instead of base for Locale change"); + context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics()); + } + } + Log.d(TAG, "Already set to locale: " + forced_language); + } + } + + public static String gs(int id) { + return getAppContext().getString(id); + } + + public static String gs(int id, String... args) { + return getAppContext().getString(id, (Object[]) args); + } + + //} +} diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/xdrip_LOCAL_21232.java b/app/src/main/java/com/eveningoutpost/dexdrip/xdrip_LOCAL_21232.java new file mode 100644 index 0000000000..337a62bdbb --- /dev/null +++ b/app/src/main/java/com/eveningoutpost/dexdrip/xdrip_LOCAL_21232.java @@ -0,0 +1,199 @@ +package com.eveningoutpost.dexdrip; + +import android.annotation.SuppressLint; +import android.app.Application; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.preference.PreferenceManager; +import android.util.Log; + +import com.crashlytics.android.Crashlytics; +import com.crashlytics.android.core.CrashlyticsCore; +import com.eveningoutpost.dexdrip.Models.AlertType; +import com.eveningoutpost.dexdrip.Models.JoH; +import com.eveningoutpost.dexdrip.Models.Reminder; +import com.eveningoutpost.dexdrip.Services.ActivityRecognizedService; +import com.eveningoutpost.dexdrip.Services.BluetoothGlucoseMeter; +import com.eveningoutpost.dexdrip.Services.MissedReadingService; +import com.eveningoutpost.dexdrip.Services.PlusSyncService; +import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter; +import com.eveningoutpost.dexdrip.UtilityModels.IdempotentMigrations; +import com.eveningoutpost.dexdrip.UtilityModels.PlusAsyncExecutor; +import com.eveningoutpost.dexdrip.UtilityModels.Pref; +import com.eveningoutpost.dexdrip.calibrations.PluggableCalibration; +import com.eveningoutpost.dexdrip.webservices.XdripWebService; + +import java.util.Locale; + +import io.fabric.sdk.android.Fabric; + +//import com.bugfender.sdk.Bugfender; + +/** + * Created by Emma Black on 3/21/15. + */ + +public class xdrip extends Application { + + private static final String TAG = "xdrip.java"; + @SuppressLint("StaticFieldLeak") + private static Context context; + private static boolean fabricInited = false; + private static boolean bfInited = false; + private static Locale LOCALE; + public static PlusAsyncExecutor executor; + public static boolean useBF = false; + private static Boolean isRunningTestCache; + + + @Override + public void onCreate() { + xdrip.context = getApplicationContext(); + super.onCreate(); + + //start widget update service to capture time ticks + this.startService(new Intent(this, WidgetUpdateService.class)); + + try { + if (PreferenceManager.getDefaultSharedPreferences(xdrip.context).getBoolean("enable_crashlytics", true)) { + initCrashlytics(this); + initBF(); + } + } catch (Exception e) { + Log.e(TAG, e.toString()); + } + executor = new PlusAsyncExecutor(); + PreferenceManager.setDefaultValues(this, R.xml.pref_general, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_data_sync, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_advanced_settings, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_notifications, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_data_source, true); + PreferenceManager.setDefaultValues(this, R.xml.xdrip_plus_defaults, true); + PreferenceManager.setDefaultValues(this, R.xml.xdrip_plus_prefs, true); + + checkForcedEnglish(xdrip.context); + + + JoH.ratelimit("policy-never", 3600); // don't on first load + new IdempotentMigrations(getApplicationContext()).performAll(); + + + if (!isRunningTest()) { + MissedReadingService.delayedLaunch(); + NFCReaderX.handleHomeScreenScanPreference(getApplicationContext()); + AlertType.fromSettings(getApplicationContext()); + new CollectionServiceStarter(getApplicationContext()).start(getApplicationContext()); + PlusSyncService.startSyncService(context, "xdrip.java"); + if (Pref.getBoolean("motion_tracking_enabled", false)) { + ActivityRecognizedService.startActivityRecogniser(getApplicationContext()); + } + BluetoothGlucoseMeter.startIfEnabled(); + XdripWebService.immortality(); + + } else { + Log.d(TAG, "Detected running test mode, holding back on background processes"); + } + Reminder.firstInit(xdrip.getAppContext()); + PluggableCalibration.invalidateCache(); + } + + public synchronized static void initCrashlytics(Context context) { + if ((!fabricInited) && !isRunningTest()) { + try { + Crashlytics crashlyticsKit = new Crashlytics.Builder() + .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()) + .build(); + Fabric.with(context, crashlyticsKit); + } catch (Exception e) { + Log.e(TAG, e.toString()); + } + fabricInited = true; + } + } + + public static synchronized boolean isRunningTest() { + if (null == isRunningTestCache) { + boolean test_framework; + try { + Class.forName("android.support.test.espresso.Espresso"); + test_framework = true; + } catch (ClassNotFoundException e) { + test_framework = false; + } + isRunningTestCache = test_framework; + } + return isRunningTestCache; + } + + public synchronized static void initBF() { + try { + if (PreferenceManager.getDefaultSharedPreferences(xdrip.context).getBoolean("enable_bugfender", false)) { + new Thread() { + @Override + public void run() { + String app_id = PreferenceManager.getDefaultSharedPreferences(xdrip.context).getString("bugfender_appid", "").trim(); + if (!useBF && (app_id.length() > 10)) { + if (!bfInited) { + //Bugfender.init(xdrip.context, app_id, BuildConfig.DEBUG); + bfInited = true; + } + useBF = true; + } + } + }.start(); + } else { + useBF = false; + } + } catch (Exception e) { + // + } + } + + + public static Context getAppContext() { + return xdrip.context; + } + + public static boolean checkAppContext(Context context) { + if (getAppContext() == null) { + xdrip.context = context; + return false; + } else { + return true; + } + } + + public static void checkForcedEnglish(Context context) { + // if (Locale.getDefault() != Locale.ENGLISH) { + // Log.d(TAG, "Locale is non-english"); + if (Pref.getBoolean("force_english", false)) { + final String forced_language = Pref.getString("forced_language", "en"); + final String current_language = Locale.getDefault().getLanguage(); + if (!current_language.equals(forced_language)) { + Log.i(TAG, "Forcing locale: " + forced_language + " was: " + current_language); + LOCALE = new Locale(forced_language, "", ""); + Locale.setDefault(LOCALE); + Configuration config = context.getResources().getConfiguration(); + config.locale = LOCALE; + try { + ((Application) context).getBaseContext().getResources().updateConfiguration(config, ((Application) context).getBaseContext().getResources().getDisplayMetrics()); + } catch (ClassCastException e) { + Log.i(TAG, "Using activity context instead of base for Locale change"); + context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics()); + } + } + Log.d(TAG, "Already set to locale: " + forced_language); + } + } + + public static String gs(int id) { + return getAppContext().getString(id); + } + + public static String gs(int id, String... args) { + return getAppContext().getString(id, (Object[]) args); + } + + //} +} diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/xdrip_REMOTE_21232.java b/app/src/main/java/com/eveningoutpost/dexdrip/xdrip_REMOTE_21232.java new file mode 100644 index 0000000000..40aec92b50 --- /dev/null +++ b/app/src/main/java/com/eveningoutpost/dexdrip/xdrip_REMOTE_21232.java @@ -0,0 +1,229 @@ +package com.eveningoutpost.dexdrip; + +import android.annotation.SuppressLint; +import android.app.Application; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.res.Configuration; +import android.os.Build; +import android.preference.PreferenceManager; +import android.util.Log; + +import com.crashlytics.android.Crashlytics; +import com.crashlytics.android.core.CrashlyticsCore; +import com.eveningoutpost.dexdrip.Models.AlertType; +import com.eveningoutpost.dexdrip.Models.JoH; +import com.eveningoutpost.dexdrip.Models.Reminder; +import com.eveningoutpost.dexdrip.Services.ActivityRecognizedService; +import com.eveningoutpost.dexdrip.Services.BluetoothGlucoseMeter; +import com.eveningoutpost.dexdrip.Services.MissedReadingService; +import com.eveningoutpost.dexdrip.Services.PlusSyncService; +import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter; +import com.eveningoutpost.dexdrip.UtilityModels.IdempotentMigrations; +import com.eveningoutpost.dexdrip.UtilityModels.PlusAsyncExecutor; +import com.eveningoutpost.dexdrip.UtilityModels.Pref; +import com.eveningoutpost.dexdrip.UtilityModels.VersionTracker; +import com.eveningoutpost.dexdrip.calibrations.PluggableCalibration; +import com.eveningoutpost.dexdrip.webservices.XdripWebService; + +import java.util.Locale; + +import io.fabric.sdk.android.Fabric; + +//import com.bugfender.sdk.Bugfender; + +/** + * Created by Emma Black on 3/21/15. + */ + +public class xdrip extends Application { + + private static final String TAG = "xdrip.java"; + @SuppressLint("StaticFieldLeak") + private static Context context; + private static boolean fabricInited = false; + private static boolean bfInited = false; + private static Locale LOCALE; + public static PlusAsyncExecutor executor; + public static boolean useBF = false; + private static Boolean isRunningTestCache; + + + @Override + public void onCreate() { + xdrip.context = getApplicationContext(); + super.onCreate(); + try { + if (PreferenceManager.getDefaultSharedPreferences(xdrip.context).getBoolean("enable_crashlytics", true)) { + initCrashlytics(this); + initBF(); + } + } catch (Exception e) { + Log.e(TAG, e.toString()); + } + executor = new PlusAsyncExecutor(); + PreferenceManager.setDefaultValues(this, R.xml.pref_general, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_data_sync, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_advanced_settings, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_notifications, true); + PreferenceManager.setDefaultValues(this, R.xml.pref_data_source, true); + PreferenceManager.setDefaultValues(this, R.xml.xdrip_plus_defaults, true); + PreferenceManager.setDefaultValues(this, R.xml.xdrip_plus_prefs, true); + + checkForcedEnglish(xdrip.context); + + + JoH.ratelimit("policy-never", 3600); // don't on first load + new IdempotentMigrations(getApplicationContext()).performAll(); + + + if (!isRunningTest()) { + MissedReadingService.delayedLaunch(); + NFCReaderX.handleHomeScreenScanPreference(getApplicationContext()); + AlertType.fromSettings(getApplicationContext()); + //new CollectionServiceStarter(getApplicationContext()).start(getApplicationContext()); + CollectionServiceStarter.restartCollectionServiceBackground(); + PlusSyncService.startSyncService(context, "xdrip.java"); + if (Pref.getBoolean("motion_tracking_enabled", false)) { + ActivityRecognizedService.startActivityRecogniser(getApplicationContext()); + } + BluetoothGlucoseMeter.startIfEnabled(); + XdripWebService.immortality(); + VersionTracker.updateDevice(); + + } else { + Log.d(TAG, "Detected running test mode, holding back on background processes"); + } + Reminder.firstInit(xdrip.getAppContext()); + PluggableCalibration.invalidateCache(); + } + + public synchronized static void initCrashlytics(Context context) { + if ((!fabricInited) && !isRunningTest()) { + try { + Crashlytics crashlyticsKit = new Crashlytics.Builder() + .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()) + .build(); + Fabric.with(context, crashlyticsKit); + } catch (Exception e) { + Log.e(TAG, e.toString()); + } + fabricInited = true; + } + } + + public static synchronized boolean isRunningTest() { + if (null == isRunningTestCache) { + boolean test_framework; + try { + Class.forName("android.support.test.espresso.Espresso"); + test_framework = true; + } catch (ClassNotFoundException e) { + test_framework = false; + } + isRunningTestCache = test_framework; + } + return isRunningTestCache; + } + + public synchronized static void initBF() { + try { + if (PreferenceManager.getDefaultSharedPreferences(xdrip.context).getBoolean("enable_bugfender", false)) { + new Thread() { + @Override + public void run() { + String app_id = PreferenceManager.getDefaultSharedPreferences(xdrip.context).getString("bugfender_appid", "").trim(); + if (!useBF && (app_id.length() > 10)) { + if (!bfInited) { + //Bugfender.init(xdrip.context, app_id, BuildConfig.DEBUG); + bfInited = true; + } + useBF = true; + } + } + }.start(); + } else { + useBF = false; + } + } catch (Exception e) { + // + } + } + + + public static Context getAppContext() { + return xdrip.context; + } + + public static boolean checkAppContext(Context context) { + if (getAppContext() == null) { + xdrip.context = context; + return false; + } else { + return true; + } + } + + public static void checkForcedEnglish(Context context) { + if (Pref.getBoolean("force_english", false)) { + final String forced_language = Pref.getString("forced_language", "en"); + final String current_language = Locale.getDefault().getLanguage(); + if (!current_language.equals(forced_language)) { + Log.i(TAG, "Forcing locale: " + forced_language + " was: " + current_language); + LOCALE = new Locale(forced_language, "", ""); + Locale.setDefault(LOCALE); + final Configuration config = context.getResources().getConfiguration(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + config.setLocale(LOCALE); + } else { + config.locale = LOCALE; + } + try { + ((Application) context).getBaseContext().getResources().updateConfiguration(config, ((Application) context).getBaseContext().getResources().getDisplayMetrics()); + } catch (ClassCastException e) { + // + } + try { + context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics()); + } catch (ClassCastException e) { + // + + } + } + Log.d(TAG, "Already set to locale: " + forced_language); + } + } + + // force language on oreo activities + public static Context getLangContext(Context context) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && Pref.getBooleanDefaultFalse("force_english")) { + final String forced_language = Pref.getString("forced_language", "en"); + final Configuration config = context.getResources().getConfiguration(); + + if (LOCALE == null) LOCALE = new Locale(forced_language); + Locale.setDefault(LOCALE); + config.setLocale(LOCALE); + context = context.createConfigurationContext(config); + //Log.d(TAG, "Sending language context for: " + LOCALE); + return new ContextWrapper(context); + } else { + return context; + } + } catch (Exception e) { + Log.e(TAG, "Got exception in getLangContext: " + e); + return context; + } + } + + + public static String gs(int id) { + return getAppContext().getString(id); + } + + public static String gs(int id, String... args) { + return getAppContext().getString(id, (Object[]) args); + } + + //} +} diff --git a/app/src/main/res/drawable/gear_widget_preview.png b/app/src/main/res/drawable/gear_widget_preview.png new file mode 100644 index 0000000000..d80e144277 Binary files /dev/null and b/app/src/main/res/drawable/gear_widget_preview.png differ diff --git a/app/src/main/res/layout/gear_widget.xml b/app/src/main/res/layout/gear_widget.xml new file mode 100644 index 0000000000..717db6b74d --- /dev/null +++ b/app/src/main/res/layout/gear_widget.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml/gear_widget_info.xml b/app/src/main/res/xml/gear_widget_info.xml new file mode 100644 index 0000000000..6526b57ed8 --- /dev/null +++ b/app/src/main/res/xml/gear_widget_info.xml @@ -0,0 +1,10 @@ + +