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 @@
+
+