diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e58d589f..285abea9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,20 @@ ###Changelog +####Version (0.9.6) +* Again some UI/theme improvements +* New preference to reconnect after connection loss (defaults to true) +* Fix crash when dealing with certain old preference values +* Mi Band: automatically reconnect when back in range after connection loss +* Mi Band 1S: display heart rate value again when invoked via the Debug view + +####Version (0.9.5) +* Several UI Improvements +* Easier First-time setup by using a FAB +* Optional Dark Theme +* Notification App Blacklist is now sorted +* Gadgetbridge Icon in the notification bar displays connection state +* Logging is now configurable without restart +* Mi Band 1S: Initial live heartrate tracking +* Fix certain crash in charts activity on slower devices (#277) ####Version (0.9.4) * Pebble: support pebble health datalog messages of firmware 3.11 (this adds support for deep sleep!) diff --git a/app/build.gradle b/app/build.gradle index aa9c5660a..65c680fd0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,8 @@ android { targetSdkVersion 23 // note: always bump BOTH versionCode and versionName! - versionName "0.9.4" - versionCode 48 + versionName "0.9.6" + versionCode 50 } buildTypes { release { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index 2667274b8..5cdf5fc9e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -7,11 +7,13 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; +import android.content.res.Resources; import android.os.Build; import android.os.Build.VERSION; import android.preference.PreferenceManager; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; +import android.util.TypedValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,6 +25,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; import nodomain.freeyourgadget.gadgetbridge.database.ActivityDatabaseHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBConstants; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; @@ -33,7 +37,9 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; +import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs; import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; //import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothConnectReceiver; @@ -54,6 +60,9 @@ public class GBApplication extends Application { private static final int CURRENT_PREFS_VERSION = 2; private static LimitedQueue mIDSenderLookup = new LimitedQueue(16); private static DaoSession daoSession; + private static Appender fileLogger; + private static Prefs prefs; + private static GBPrefs gbPrefs; public static final String ACTION_QUIT = "nodomain.freeyourgadget.gadgetbridge.gbapplication.action.quit"; @@ -87,10 +96,12 @@ public class GBApplication extends Application { super.onCreate(); sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); + prefs = new Prefs(sharedPrefs); + gbPrefs = new GBPrefs(prefs); // don't do anything here before we set up logging, otherwise // slf4j may be implicitly initialized before we properly configured it. - setupLogging(); + setupLogging(isFileLoggingEnabled()); if (getPrefsFileVersion() != CURRENT_PREFS_VERSION) { migratePrefs(getPrefsFileVersion()); @@ -125,35 +136,71 @@ public class GBApplication extends Application { } public static boolean isFileLoggingEnabled() { - return sharedPrefs.getBoolean("log_to_file", false); + return prefs.getBoolean("log_to_file", false); } - private void setupLogging() { - if (isFileLoggingEnabled()) { - try { + public static void setupLogging(boolean enable) { + try { + if (fileLogger == null) { File dir = FileUtils.getExternalFilesDir(); // used by assets/logback.xml since the location cannot be statically determined System.setProperty("GB_LOGFILES_DIR", dir.getAbsolutePath()); - getLogger().info("Gadgetbridge version: " + BuildConfig.VERSION_NAME); - } catch (IOException ex) { - Log.e("GBApplication", "External files dir not available, cannot log to file", ex); - removeFileLogger(); + rememberFileLogger(); } - } else { - removeFileLogger(); + if (enable) { + startFileLogger(); + } else { + stopFileLogger(); + } + getLogger().info("Gadgetbridge version: " + BuildConfig.VERSION_NAME); + } catch (IOException ex) { + Log.e("GBApplication", "External files dir not available, cannot log to file", ex); + stopFileLogger(); } } - private void removeFileLogger() { + private static void startFileLogger() { + if (fileLogger != null && !fileLogger.isStarted()) { + addFileLogger(fileLogger); + fileLogger.start(); + } + } + + private static void stopFileLogger() { + if (fileLogger != null && fileLogger.isStarted()) { + fileLogger.stop(); + removeFileLogger(fileLogger); + } + } + + private static void rememberFileLogger() { + ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + fileLogger = root.getAppender("FILE"); + } + + private static void addFileLogger(Appender fileLogger) { try { ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); - root.detachAppender("FILE"); + if (!root.isAttached(fileLogger)) { + root.addAppender(fileLogger); + } } catch (Throwable ex) { Log.e("GBApplication", "Error removing logger FILE appender", ex); } } - private Logger getLogger() { + private static void removeFileLogger(Appender fileLogger) { + try { + ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + if (root.isAttached(fileLogger)) { + root.detachAppender(fileLogger); + } + } catch (Throwable ex) { + Log.e("GBApplication", "Error removing logger FILE appender", ex); + } + } + + private static Logger getLogger() { return LoggerFactory.getLogger(GBApplication.class); } @@ -320,6 +367,27 @@ public class GBApplication extends Application { } public static boolean isDarkThemeEnabled() { - return sharedPrefs.getString("pref_key_theme", context.getString(R.string.pref_theme_value_light)).equals(context.getString(R.string.pref_theme_value_dark)); + return prefs.getString("pref_key_theme", context.getString(R.string.pref_theme_value_light)).equals(context.getString(R.string.pref_theme_value_dark)); + } + + public static int getTextColor(Context context) { + TypedValue typedValue = new TypedValue(); + Resources.Theme theme = context.getTheme(); + theme.resolveAttribute(android.R.attr.textColor, typedValue, true); + return typedValue.data; + } + public static int getBackgroundColor(Context context) { + TypedValue typedValue = new TypedValue(); + Resources.Theme theme = context.getTheme(); + theme.resolveAttribute(android.R.attr.background, typedValue, true); + return typedValue.data; + } + + public static Prefs getPrefs() { + return prefs; + } + + public static GBPrefs getGBPrefs() { + return gbPrefs; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java index 2d62ce046..965a0cfd6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java @@ -2,6 +2,7 @@ package nodomain.freeyourgadget.gadgetbridge.activities; import android.content.res.Configuration; import android.os.Bundle; +import android.preference.EditTextPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceActivity; @@ -12,6 +13,7 @@ import android.support.v4.app.NavUtils; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatDelegate; import android.support.v7.widget.Toolbar; +import android.text.InputType; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; @@ -41,6 +43,14 @@ public abstract class AbstractSettingsActivity extends PreferenceActivity { private static class SimpleSetSummaryOnChangeListener implements Preference.OnPreferenceChangeListener { @Override public boolean onPreferenceChange(Preference preference, Object value) { + if (preference instanceof EditTextPreference) { + if (((EditTextPreference) preference).getEditText().getKeyListener().getInputType() == InputType.TYPE_CLASS_NUMBER) { + if ("".equals(String.valueOf(value))) { + // reject empty numeric input + return false; + } + } + } updateSummary(preference, value); return true; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java index bef494383..c7db9fc71 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java @@ -4,11 +4,9 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Bundle; -import android.preference.PreferenceManager; import android.support.v4.app.NavUtils; import android.support.v4.content.LocalBroadcastManager; import android.view.LayoutInflater; @@ -47,7 +45,6 @@ public class AppBlacklistActivity extends GBActivity { } }; - private SharedPreferences sharedPrefs; private IdentityHashMap nameMap; @Override @@ -56,7 +53,6 @@ public class AppBlacklistActivity extends GBActivity { setContentView(R.layout.activity_appblacklist); final PackageManager pm = getPackageManager(); - sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); final List packageList = pm.getInstalledApplications(PackageManager.GET_META_DATA); ListView appListView = (ListView) findViewById(R.id.appListView); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java index 5be4f6f09..2e6bbba04 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java @@ -4,10 +4,8 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; -import android.preference.PreferenceManager; import android.support.v4.app.NavUtils; import android.support.v4.content.LocalBroadcastManager; import android.view.ContextMenu; @@ -34,6 +32,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp; import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.PebbleProtocol; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.PebbleUtils; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class AppManagerActivity extends GBActivity { @@ -59,7 +58,7 @@ public class AppManagerActivity extends GBActivity { appList.add(new GBDeviceApp(uuid, appName, appCreator, "", appType)); } - if (sharedPrefs.getBoolean("pebble_force_untested", false)) { + if (prefs.getBoolean("pebble_force_untested", false)) { appList.addAll(getSystemApps()); } @@ -68,7 +67,7 @@ public class AppManagerActivity extends GBActivity { } }; - private SharedPreferences sharedPrefs; + private Prefs prefs; private final List appList = new ArrayList<>(); private GBDeviceAppAdapter mGBDeviceAppAdapter; @@ -130,7 +129,7 @@ public class AppManagerActivity extends GBActivity { throw new IllegalArgumentException("Must provide a device when invoking this activity"); } - sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + prefs = GBApplication.getPrefs(); setContentView(R.layout.activity_appmanager); @@ -150,7 +149,7 @@ public class AppManagerActivity extends GBActivity { appList.addAll(getCachedApps()); - if (sharedPrefs.getBoolean("pebble_force_untested", false)) { + if (prefs.getBoolean("pebble_force_untested", false)) { appList.addAll(getSystemApps()); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java index 49f8e7a75..0a978d5d3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java @@ -1,9 +1,7 @@ package nodomain.freeyourgadget.gadgetbridge.activities; import android.content.Intent; -import android.content.SharedPreferences; import android.os.Bundle; -import android.preference.PreferenceManager; import android.view.MenuItem; import android.widget.ListView; @@ -16,6 +14,7 @@ import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.adapter.GBAlarmListAdapter; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst; import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_ALARMS; @@ -34,12 +33,12 @@ public class ConfigureAlarms extends GBActivity { setContentView(R.layout.activity_configure_alarms); - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); - preferencesAlarmListSet = sharedPrefs.getStringSet(PREF_MIBAND_ALARMS, new HashSet()); + Prefs prefs = GBApplication.getPrefs(); + preferencesAlarmListSet = prefs.getStringSet(PREF_MIBAND_ALARMS, new HashSet()); if (preferencesAlarmListSet.isEmpty()) { //initialize the preferences preferencesAlarmListSet = new HashSet<>(Arrays.asList(GBAlarm.DEFAULT_ALARMS)); - sharedPrefs.edit().putStringSet(PREF_MIBAND_ALARMS, preferencesAlarmListSet).apply(); + prefs.getPreferences().edit().putStringSet(PREF_MIBAND_ALARMS, preferencesAlarmListSet).apply(); } mGBAlarmListAdapter = new GBAlarmListAdapter(this, preferencesAlarmListSet); @@ -66,9 +65,9 @@ public class ConfigureAlarms extends GBActivity { } private void updateAlarmsFromPrefs() { - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); - preferencesAlarmListSet = sharedPrefs.getStringSet(PREF_MIBAND_ALARMS, new HashSet()); - int reservedSlots = Integer.parseInt(sharedPrefs.getString(MiBandConst.PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR, "0")); + Prefs prefs = GBApplication.getPrefs(); + preferencesAlarmListSet = prefs.getStringSet(PREF_MIBAND_ALARMS, new HashSet()); + int reservedSlots = prefs.getInt(MiBandConst.PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR, 0); mGBAlarmListAdapter.setAlarmList(preferencesAlarmListSet, reservedSlots); mGBAlarmListAdapter.notifyDataSetChanged(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java index b9ad4d98b..7ddb5a884 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java @@ -10,11 +10,9 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; -import android.preference.PreferenceManager; import android.support.design.widget.FloatingActionButton; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; @@ -46,6 +44,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; import nodomain.freeyourgadget.gadgetbridge.util.GB; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class ControlCenter extends GBActivity { @@ -184,9 +183,9 @@ public class ControlCenter extends GBActivity { /* * Ask for permission to intercept notifications on first run. */ - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); - if (sharedPrefs.getBoolean("firstrun", true)) { - sharedPrefs.edit().putBoolean("firstrun", false).apply(); + Prefs prefs = GBApplication.getPrefs(); + if (prefs.getBoolean("firstrun", true)) { + prefs.getPreferences().edit().putBoolean("firstrun", false).apply(); Intent enableIntent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"); startActivity(enableIntent); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java index a6eee7750..d7d81f692 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java @@ -13,6 +13,7 @@ import android.os.Bundle; import android.support.v4.app.NavUtils; import android.support.v4.app.NotificationCompat; import android.support.v4.app.RemoteInput; +import android.support.v4.content.LocalBroadcastManager; import android.view.MenuItem; import android.view.View; import android.widget.Button; @@ -29,6 +30,7 @@ import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; +import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; @@ -63,15 +65,22 @@ public class DebugActivity extends GBActivity { @Override public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { - case GBApplication.ACTION_QUIT: + case GBApplication.ACTION_QUIT: { finish(); break; - case ACTION_REPLY: + } + case ACTION_REPLY: { Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); CharSequence reply = remoteInput.getCharSequence(EXTRA_REPLY); LOG.info("got wearable reply: " + reply); GB.toast(context, "got wearable reply: " + reply, Toast.LENGTH_SHORT, GB.INFO); break; + } + case DeviceService.ACTION_HEARTRATE_MEASUREMENT: { + int hrValue = intent.getIntExtra(DeviceService.EXTRA_HEART_RATE_VALUE, -1); + GB.toast(DebugActivity.this, "Heart Rate measured: " + hrValue, Toast.LENGTH_LONG, GB.INFO); + break; + } } } }; @@ -84,7 +93,9 @@ public class DebugActivity extends GBActivity { IntentFilter filter = new IntentFilter(); filter.addAction(GBApplication.ACTION_QUIT); filter.addAction(ACTION_REPLY); - registerReceiver(mReceiver, filter); + filter.addAction(DeviceService.ACTION_HEARTRATE_MEASUREMENT); + LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filter); + registerReceiver(mReceiver, filter); // for ACTION_REPLY editContent = (EditText) findViewById(R.id.editContent); sendSMSButton = (Button) findViewById(R.id.sendSMSButton); @@ -348,6 +359,7 @@ public class DebugActivity extends GBActivity { @Override protected void onDestroy() { super.onDestroy(); + LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver); unregisterReceiver(mReceiver); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java index d541af9cc..c8bfe8356 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java @@ -12,6 +12,7 @@ import android.widget.Toast; import java.io.IOException; import java.util.List; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandPreferencesActivity; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; @@ -88,16 +89,18 @@ public class SettingsActivity extends AbstractSettingsActivity { pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newVal) { - if (Boolean.TRUE.equals(newVal)) { - try { + boolean doEnable = Boolean.TRUE.equals(newVal); + try { + if (doEnable) { FileUtils.getExternalFilesDir(); // ensures that it is created - } catch (IOException ex) { - GB.toast(getApplicationContext(), - getString(R.string.error_creating_directory_for_logfiles, ex.getLocalizedMessage()), - Toast.LENGTH_LONG, - GB.ERROR, - ex); } + GBApplication.setupLogging(doEnable); + } catch (IOException ex) { + GB.toast(getApplicationContext(), + getString(R.string.error_creating_directory_for_logfiles, ex.getLocalizedMessage()), + Toast.LENGTH_LONG, + GB.ERROR, + ex); } return true; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java index 41c611143..b4c776eef 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java @@ -4,13 +4,11 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.res.Resources; import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.FragmentActivity; import android.support.v4.content.LocalBroadcastManager; -import android.util.TypedValue; import android.view.View; import com.github.mikephil.charting.charts.BarLineChartBase; @@ -39,6 +37,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBFragment; import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils; @@ -151,13 +150,8 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } protected void init() { - TypedValue typedValue = new TypedValue(); - Resources.Theme theme = getContext().getTheme(); - theme.resolveAttribute(android.R.attr.background, typedValue, true); - BACKGROUND_COLOR = typedValue.data; - theme.resolveAttribute(android.R.attr.textColor, typedValue, true); - LEGEND_TEXT_COLOR = DESCRIPTION_COLOR = typedValue.data; - + BACKGROUND_COLOR = GBApplication.getBackgroundColor(getContext()); + LEGEND_TEXT_COLOR = DESCRIPTION_COLOR = GBApplication.getTextColor(getContext()); CHART_TEXT_COLOR = getResources().getColor(R.color.secondarytext); HEARTRATE_COLOR = getResources().getColor(R.color.chart_heartrate); HEARTRATE_FILL_COLOR = getResources().getColor(R.color.chart_heartrate_fill); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBAlarmListAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBAlarmListAdapter.java index fec4c9290..5a5b7b3e5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBAlarmListAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBAlarmListAdapter.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Set; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms; import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm; @@ -152,7 +153,7 @@ public class GBAlarmListAdapter extends ArrayAdapter { if (isOn) { view.setTextColor(Color.BLUE); } else { - view.setTextColor(Color.BLACK); + view.setTextColor(GBApplication.getTextColor(mContext)); } } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/contentprovider/PebbleContentProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/contentprovider/PebbleContentProvider.java index c20a552dd..d02355211 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/contentprovider/PebbleContentProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/contentprovider/PebbleContentProvider.java @@ -6,16 +6,16 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.database.Cursor; import android.database.MatrixCursor; import android.net.Uri; -import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.v4.content.LocalBroadcastManager; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class PebbleContentProvider extends ContentProvider { @@ -59,8 +59,8 @@ public class PebbleContentProvider extends ContentProvider { MatrixCursor mc = new MatrixCursor(columnNames); int connected = 0; int appMessage = 0; - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this.getContext()); - if (sharedPrefs.getBoolean("pebble_enable_pebblekit", false)) { + Prefs prefs = GBApplication.getPrefs(); + if (prefs.getBoolean("pebble_enable_pebblekit", false)) { appMessage = 1; } if (mGBDevice != null && mGBDevice.getType() == DeviceType.PEBBLE && mGBDevice.isInitialized()) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java index 511de9ddd..6853b3714 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandConst.java @@ -1,10 +1,10 @@ package nodomain.freeyourgadget.gadgetbridge.devices.miband; -import android.content.SharedPreferences; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; + public final class MiBandConst { private static final Logger LOG = LoggerFactory.getLogger(MiBandConst.class); @@ -27,19 +27,12 @@ public final class MiBandConst { public static final String MI_1A = "1A"; public static final String MI_1S = "1S"; - public static int getNotificationPrefIntValue(String pref, String origin, SharedPreferences prefs, int defaultValue) { + public static int getNotificationPrefIntValue(String pref, String origin, Prefs prefs, int defaultValue) { String key = getNotificationPrefKey(pref, origin); - String value = null; - try { - value = prefs.getString(key, String.valueOf(defaultValue)); - return Integer.valueOf(value); - } catch (NumberFormatException ex) { - LOG.error("Error converting preference value to int: " + key + ": " + value); - return defaultValue; - } + return prefs.getInt(key, defaultValue); } - public static String getNotificationPrefStringValue(String pref, String origin, SharedPreferences prefs, String defaultValue) { + public static String getNotificationPrefStringValue(String pref, String origin, Prefs prefs, String defaultValue) { String key = getNotificationPrefKey(pref, origin); return prefs.getString(key, defaultValue); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java index 86ea93303..a669412eb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java @@ -2,9 +2,7 @@ package nodomain.freeyourgadget.gadgetbridge.devices.miband; import android.app.Activity; import android.content.Context; -import android.content.SharedPreferences; import android.net.Uri; -import android.preference.PreferenceManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,6 +16,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate; import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class MiBandCoordinator extends AbstractDeviceCoordinator { private static final Logger LOG = LoggerFactory.getLogger(MiBandCoordinator.class); @@ -112,7 +111,7 @@ public class MiBandCoordinator extends AbstractDeviceCoordinator { */ public static UserInfo getConfiguredUserInfo(String miBandAddress) throws IllegalArgumentException { ActivityUser activityUser = new ActivityUser(); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); + Prefs prefs = GBApplication.getPrefs(); UserInfo info = UserInfo.create( miBandAddress, @@ -128,7 +127,7 @@ public class MiBandCoordinator extends AbstractDeviceCoordinator { public static int getWearLocation(String miBandAddress) throws IllegalArgumentException { int location = 0; //left hand - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); + Prefs prefs = GBApplication.getPrefs(); if ("right".equals(prefs.getString(MiBandConst.PREF_MIBAND_WEARSIDE, "left"))) { location = 1; // right hand } @@ -136,17 +135,17 @@ public class MiBandCoordinator extends AbstractDeviceCoordinator { } public static boolean getHeartrateSleepSupport(String miBandAddress) throws IllegalArgumentException { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); + Prefs prefs = GBApplication.getPrefs(); return prefs.getBoolean(MiBandConst.PREF_MIBAND_USE_HR_FOR_SLEEP_DETECTION, false); } public static int getFitnessGoal(String miBandAddress) throws IllegalArgumentException { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); - return Integer.parseInt(prefs.getString(MiBandConst.PREF_MIBAND_FITNESS_GOAL, "10000")); + Prefs prefs = GBApplication.getPrefs(); + return prefs.getInt(MiBandConst.PREF_MIBAND_FITNESS_GOAL, 10000); } public static int getReservedAlarmSlots(String miBandAddress) throws IllegalArgumentException { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); - return Integer.parseInt(prefs.getString(MiBandConst.PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR, "0")); + Prefs prefs = GBApplication.getPrefs(); + return prefs.getInt(MiBandConst.PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR, 0); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java index 9a2b9fac3..12d886836 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java @@ -7,11 +7,9 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.os.Looper; -import android.preference.PreferenceManager; import android.support.v4.content.LocalBroadcastManager; import android.widget.TextView; import android.widget.Toast; @@ -26,6 +24,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.DiscoveryActivity; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.util.GB; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class MiBandPairingActivity extends Activity { private static final Logger LOG = LoggerFactory.getLogger(MiBandPairingActivity.class); @@ -170,8 +169,8 @@ public class MiBandPairingActivity extends Activity { unregisterReceiver(mBondingReceiver); if (pairedSuccessfully) { - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); - sharedPrefs.edit().putString(MiBandConst.PREF_MIBAND_ADDRESS, macAddress).apply(); + Prefs prefs = GBApplication.getPrefs(); + prefs.getPreferences().edit().putString(MiBandConst.PREF_MIBAND_ADDRESS, macAddress).apply(); } Intent intent = new Intent(this, ControlCenter.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleCoordinator.java index f7017d7b1..d76e71269 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleCoordinator.java @@ -2,9 +2,7 @@ package nodomain.freeyourgadget.gadgetbridge.devices.pebble; import android.app.Activity; import android.content.Context; -import android.content.SharedPreferences; import android.net.Uri; -import android.preference.PreferenceManager; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.activities.AppManagerActivity; @@ -14,6 +12,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class PebbleCoordinator extends AbstractDeviceCoordinator { public PebbleCoordinator() { @@ -45,8 +44,8 @@ public class PebbleCoordinator extends AbstractDeviceCoordinator { @Override public SampleProvider getSampleProvider() { - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); - int activityTracker = Integer.parseInt(sharedPrefs.getString("pebble_activitytracker", Integer.toString(SampleProvider.PROVIDER_PEBBLE_HEALTH))); + Prefs prefs = GBApplication.getPrefs(); + int activityTracker = prefs.getInt("pebble_activitytracker", SampleProvider.PROVIDER_PEBBLE_HEALTH); switch (activityTracker) { case SampleProvider.PROVIDER_PEBBLE_HEALTH: return new HealthSampleProvider(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java index 74a3d2dcf..73d26d0d4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java @@ -4,12 +4,11 @@ import android.bluetooth.BluetoothAdapter; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; import android.support.v4.content.LocalBroadcastManager; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenter; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class BluetoothStateChangeReceiver extends BroadcastReceiver { @Override @@ -22,8 +21,8 @@ public class BluetoothStateChangeReceiver extends BroadcastReceiver { Intent refreshIntent = new Intent(ControlCenter.ACTION_REFRESH_DEVICELIST); LocalBroadcastManager.getInstance(context).sendBroadcast(refreshIntent); - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); - if (!sharedPrefs.getBoolean("general_autoconnectonbluetooth", false)) { + Prefs prefs = GBApplication.getPrefs(); + if (!prefs.getBoolean("general_autoconnectonbluetooth", false)) { return; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java index 1b615d24b..899ee0c6a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java @@ -3,11 +3,9 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.database.Cursor; import android.net.Uri; import android.os.PowerManager; -import android.preference.PreferenceManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,6 +13,7 @@ import org.slf4j.LoggerFactory; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class K9Receiver extends BroadcastReceiver { @@ -24,11 +23,11 @@ public class K9Receiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); - if ("never".equals(sharedPrefs.getString("notification_mode_k9mail", "when_screen_off"))) { + Prefs prefs = GBApplication.getPrefs(); + if ("never".equals(prefs.getString("notification_mode_k9mail", "when_screen_off"))) { return; } - if ("when_screen_off".equals(sharedPrefs.getString("notification_mode_k9mail", "when_screen_off"))) { + if ("when_screen_off".equals(prefs.getString("notification_mode_k9mail", "when_screen_off"))) { PowerManager powermanager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); if (powermanager.isScreenOn()) { return; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index 124c0b99d..9f93618b2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -8,12 +8,10 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.PowerManager; -import android.preference.PreferenceManager; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.support.v4.app.NotificationCompat; @@ -30,6 +28,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class NotificationListener extends NotificationListenerService { @@ -161,8 +160,8 @@ public class NotificationListener extends NotificationListenerService { return; } - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); - if (!sharedPrefs.getBoolean("notifications_generic_whenscreenon", false)) { + Prefs prefs = GBApplication.getPrefs(); + if (!prefs.getBoolean("notifications_generic_whenscreenon", false)) { PowerManager powermanager = (PowerManager) getSystemService(POWER_SERVICE); if (powermanager.isScreenOn()) { return; @@ -189,13 +188,13 @@ public class NotificationListener extends NotificationListenerService { } if (source.equals("eu.siacs.conversations")) { - if (!"never".equals(sharedPrefs.getString("notification_mode_pebblemsg", "when_screen_off"))) { + if (!"never".equals(prefs.getString("notification_mode_pebblemsg", "when_screen_off"))) { return; } } if (source.equals("com.fsck.k9")) { - if (!"never".equals(sharedPrefs.getString("notification_mode_k9mail", "when_screen_off"))) { + if (!"never".equals(prefs.getString("notification_mode_k9mail", "when_screen_off"))) { return; } } @@ -205,7 +204,7 @@ public class NotificationListener extends NotificationListenerService { source.equals("com.sonyericsson.conversations") || source.equals("com.android.messaging") || source.equals("org.smssecure.smssecure")) { - if (!"never".equals(sharedPrefs.getString("notification_mode_sms", "when_screen_off"))) { + if (!"never".equals(prefs.getString("notification_mode_sms", "when_screen_off"))) { return; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java index 01dab88f6..801c151bb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java @@ -3,9 +3,7 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.os.PowerManager; -import android.preference.PreferenceManager; import org.json.JSONArray; import org.json.JSONException; @@ -15,6 +13,7 @@ import org.slf4j.LoggerFactory; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class PebbleReceiver extends BroadcastReceiver { @@ -23,11 +22,11 @@ public class PebbleReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); - if ("never".equals(sharedPrefs.getString("notification_mode_pebblemsg", "when_screen_off"))) { + Prefs prefs = GBApplication.getPrefs(); + if ("never".equals(prefs.getString("notification_mode_pebblemsg", "when_screen_off"))) { return; } - if ("when_screen_off".equals(sharedPrefs.getString("notification_mode_pebblemsg", "when_screen_off"))) { + if ("when_screen_off".equals(prefs.getString("notification_mode_pebblemsg", "when_screen_off"))) { PowerManager powermanager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); if (powermanager.isScreenOn()) { return; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java index 010b5fb82..496872db3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java @@ -3,12 +3,11 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; import android.telephony.TelephonyManager; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class PhoneCallReceiver extends BroadcastReceiver { @@ -64,8 +63,8 @@ public class PhoneCallReceiver extends BroadcastReceiver { break; } if (callCommand != CallSpec.CALL_UNDEFINED) { - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); - if ("never".equals(sharedPrefs.getString("notification_mode_calls", "always"))) { + Prefs prefs = GBApplication.getPrefs(); + if ("never".equals(prefs.getString("notification_mode_calls", "always"))) { return; } CallSpec callSpec = new CallSpec(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java index a2dd09a32..0404cbc22 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java @@ -3,26 +3,24 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.os.Bundle; import android.os.PowerManager; -import android.preference.PreferenceManager; import android.telephony.SmsMessage; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class SMSReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); - if ("never".equals(sharedPrefs.getString("notification_mode_sms", "when_screen_off"))) { + Prefs prefs = GBApplication.getPrefs(); + if ("never".equals(prefs.getString("notification_mode_sms", "when_screen_off"))) { return; } - if ("when_screen_off".equals(sharedPrefs.getString("notification_mode_sms", "when_screen_off"))) { + if ("when_screen_off".equals(prefs.getString("notification_mode_sms", "when_screen_off"))) { PowerManager powermanager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); if (powermanager.isScreenOn()) { return; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/TimeChangeReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/TimeChangeReceiver.java index 82f0836b2..0f58c21ff 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/TimeChangeReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/TimeChangeReceiver.java @@ -3,8 +3,6 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,6 +12,7 @@ import java.util.GregorianCalendar; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class TimeChangeReceiver extends BroadcastReceiver { @@ -22,10 +21,10 @@ public class TimeChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); + Prefs prefs = GBApplication.getPrefs(); final String action = intent.getAction(); - if (sharedPrefs.getBoolean("datetime_synconconnect", true) && (action.equals(Intent.ACTION_TIME_CHANGED) || action.equals(Intent.ACTION_TIMEZONE_CHANGED))) { + if (prefs.getBoolean("datetime_synconconnect", true) && (action.equals(Intent.ACTION_TIME_CHANGED) || action.equals(Intent.ACTION_TIMEZONE_CHANGED))) { Date newTime = GregorianCalendar.getInstance().getTime(); LOG.info("Time or Timezone changed, syncing with device: " + DateTimeUtils.formatDate(newTime) + " (" + newTime.toGMTString() + "), " + intent.getAction()); GBApplication.deviceService().onSetTime(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBAlarm.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBAlarm.java index d0178e4cf..546bcee22 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBAlarm.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBAlarm.java @@ -1,8 +1,6 @@ package nodomain.freeyourgadget.gadgetbridge.impl; -import android.content.SharedPreferences; import android.os.Parcel; -import android.preference.PreferenceManager; import android.support.annotation.NonNull; import java.util.Calendar; @@ -12,6 +10,7 @@ import java.util.Set; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_ALARMS; @@ -187,8 +186,8 @@ public class GBAlarm implements Alarm { } public void store() { - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); - Set preferencesAlarmListSet = sharedPrefs.getStringSet(PREF_MIBAND_ALARMS, new HashSet()); + Prefs prefs = GBApplication.getPrefs(); + Set preferencesAlarmListSet = prefs.getStringSet(PREF_MIBAND_ALARMS, new HashSet()); //the old Set cannot be updated in place see http://developer.android.com/reference/android/content/SharedPreferences.html#getStringSet%28java.lang.String,%20java.util.Set%3Cjava.lang.String%3E%29 Set newPrefs = new HashSet<>(preferencesAlarmListSet); @@ -202,7 +201,7 @@ public class GBAlarm implements Alarm { } } newPrefs.add(this.toPreferences()); - sharedPrefs.edit().putStringSet(PREF_MIBAND_ALARMS, newPrefs).apply(); + prefs.getPreferences().edit().putStringSet(PREF_MIBAND_ALARMS, newPrefs).apply(); } public static final Creator CREATOR = new Creator() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityUser.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityUser.java index c0a436a68..358c4a8ea 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityUser.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityUser.java @@ -1,11 +1,9 @@ package nodomain.freeyourgadget.gadgetbridge.model; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; - import java.util.Calendar; import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; /** * Class holding the common user information needed by most activity trackers @@ -86,11 +84,11 @@ public class ActivityUser { } private void fetchPreferences() { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); - activityUserGender = Integer.parseInt(prefs.getString(PREF_USER_GENDER, Integer.toString(defaultUserGender))); - activityUserHeightCm = Integer.parseInt(prefs.getString(PREF_USER_HEIGHT_CM, Integer.toString(defaultUserHeightCm))); - activityUserWeightKg = Integer.parseInt(prefs.getString(PREF_USER_WEIGHT_KG, Integer.toString(defaultUserWeightKg))); - activityUserYearOfBirth = Integer.parseInt(prefs.getString(PREF_USER_YEAR_OF_BIRTH, Integer.toString(defaultUserYearOfBirth))); - activityUserSleepDuration = Integer.parseInt(prefs.getString(PREF_USER_SLEEP_DURATION, Integer.toString(defaultUserSleepDuration))); + Prefs prefs = GBApplication.getPrefs(); + activityUserGender = prefs.getInt(PREF_USER_GENDER, defaultUserGender); + activityUserHeightCm = prefs.getInt(PREF_USER_HEIGHT_CM, defaultUserHeightCm); + activityUserWeightKg = prefs.getInt(PREF_USER_WEIGHT_KG, defaultUserWeightKg); + activityUserYearOfBirth = prefs.getInt(PREF_USER_YEAR_OF_BIRTH, defaultUserYearOfBirth); + activityUserSleepDuration = prefs.getInt(PREF_USER_SLEEP_DURATION, defaultUserSleepDuration); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java index d103011ab..21d7965b9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java @@ -6,11 +6,9 @@ import android.app.PendingIntent; import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; -import android.preference.PreferenceManager; import android.support.v4.content.LocalBroadcastManager; import android.telephony.SmsManager; @@ -44,6 +42,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.BatteryState; import nodomain.freeyourgadget.gadgetbridge.service.receivers.GBCallControlReceiver; import nodomain.freeyourgadget.gadgetbridge.service.receivers.GBMusicControlReceiver; import nodomain.freeyourgadget.gadgetbridge.util.GB; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; // TODO: support option for a single reminder notification when notifications could not be delivered? // conditions: app was running and received notifications, but device was not connected. @@ -60,6 +59,7 @@ public abstract class AbstractDeviceSupport implements DeviceSupport { protected GBDevice gbDevice; private BluetoothAdapter btAdapter; private Context context; + private boolean autoReconnect; public void setContext(GBDevice gbDevice, BluetoothAdapter btAdapter, Context context) { this.gbDevice = gbDevice; @@ -82,6 +82,16 @@ public abstract class AbstractDeviceSupport implements DeviceSupport { return gbDevice.isInitialized(); } + @Override + public void setAutoReconnect(boolean enable) { + autoReconnect = enable; + } + + @Override + public boolean getAutoReconnect() { + return autoReconnect; + } + @Override public GBDevice getDevice() { return gbDevice; @@ -247,8 +257,8 @@ public abstract class AbstractDeviceSupport implements DeviceSupport { Intent notificationListenerIntent = new Intent(action); notificationListenerIntent.putExtra("handle", deviceEvent.handle); if (deviceEvent.reply != null) { - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); - String suffix = sharedPrefs.getString("canned_reply_suffix", null); + Prefs prefs = GBApplication.getPrefs(); + String suffix = prefs.getString("canned_reply_suffix", null); if (suffix != null && !Objects.equals(suffix, "")) { deviceEvent.reply += suffix; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java index c26cb1b86..7738f40c7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -10,7 +10,6 @@ import android.content.SharedPreferences; import android.database.Cursor; import android.net.Uri; import android.os.IBinder; -import android.preference.PreferenceManager; import android.provider.ContactsContract; import android.support.annotation.Nullable; import android.support.v4.content.LocalBroadcastManager; @@ -39,6 +38,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; import nodomain.freeyourgadget.gadgetbridge.util.GB; +import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_APP_CONFIGURE; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CALLSTATE; @@ -89,7 +90,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOT import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_PERFORM_PAIR; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_URI; -public class DeviceCommunicationService extends Service { +public class DeviceCommunicationService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener { private static final Logger LOG = LoggerFactory.getLogger(DeviceCommunicationService.class); private boolean mStarted = false; @@ -131,6 +132,10 @@ public class DeviceCommunicationService extends Service { super.onCreate(); LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, new IntentFilter(GBDevice.ACTION_DEVICE_CHANGED)); mFactory = new DeviceSupportFactory(this); + + if (hasPrefs()) { + getPrefs().getPreferences().registerOnSharedPreferenceChangeListener(this); + } } @Override @@ -170,7 +175,7 @@ public class DeviceCommunicationService extends Service { // when we get past this, we should have valid mDeviceSupport and mGBDevice instances - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); + Prefs prefs = getPrefs(); switch (action) { case ACTION_START: start(); @@ -181,8 +186,8 @@ public class DeviceCommunicationService extends Service { String btDeviceAddress = null; if (gbDevice == null) { btDeviceAddress = intent.getStringExtra(EXTRA_DEVICE_ADDRESS); - if (btDeviceAddress == null && sharedPrefs != null) { // may be null in test cases - btDeviceAddress = sharedPrefs.getString("last_device_address", null); + if (btDeviceAddress == null && prefs != null) { // may be null in test cases + btDeviceAddress = prefs.getString("last_device_address", null); } if (btDeviceAddress != null) { gbDevice = DeviceHelper.getInstance().findAvailableDevice(btDeviceAddress, this); @@ -191,8 +196,10 @@ public class DeviceCommunicationService extends Service { btDeviceAddress = gbDevice.getAddress(); } - if (sharedPrefs != null) { - sharedPrefs.edit().putString("last_device_address", btDeviceAddress).apply(); + boolean autoReconnect = GBPrefs.AUTO_RECONNECT_DEFAULT; + if (prefs != null && prefs.getPreferences() != null) { + prefs.getPreferences().edit().putString("last_device_address", btDeviceAddress).apply(); + autoReconnect = getGBPrefs().getAutoReconnect(); } if (gbDevice != null && !isConnecting() && !isConnected()) { @@ -204,6 +211,7 @@ public class DeviceCommunicationService extends Service { if (pair) { deviceSupport.pair(); } else { + deviceSupport.setAutoReconnect(autoReconnect); deviceSupport.connect(); } } else { @@ -241,12 +249,12 @@ public class DeviceCommunicationService extends Service { if (((notificationSpec.flags & NotificationSpec.FLAG_WEARABLE_REPLY) > 0) || (notificationSpec.type == NotificationType.SMS && notificationSpec.phoneNumber != null)) { // NOTE: maybe not where it belongs - if (sharedPrefs.getBoolean("pebble_force_untested", false)) { + if (prefs.getBoolean("pebble_force_untested", false)) { // I would rather like to save that as an array in ShadredPreferences // this would work but I dont know how to do the same in the Settings Activity's xml ArrayList replies = new ArrayList<>(); for (int i = 1; i <= 16; i++) { - String reply = sharedPrefs.getString("canned_reply_" + i, null); + String reply = prefs.getString("canned_reply_" + i, null); if (reply != null && !reply.equals("")) { replies.add(reply); } @@ -479,6 +487,10 @@ public class DeviceCommunicationService extends Service { @Override public void onDestroy() { + if (hasPrefs()) { + getPrefs().getPreferences().unregisterOnSharedPreferenceChangeListener(this); + } + LOG.debug("DeviceCommunicationService is being destroyed"); super.onDestroy(); @@ -515,4 +527,26 @@ public class DeviceCommunicationService extends Service { return name; } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (GBPrefs.AUTO_RECONNECT.equals(key)) { + boolean autoReconnect = getGBPrefs().getAutoReconnect(); + if (mDeviceSupport != null) { + mDeviceSupport.setAutoReconnect(autoReconnect); + } + } + } + + protected boolean hasPrefs() { + return getPrefs().getPreferences() != null; + } + + public Prefs getPrefs() { + return GBApplication.getPrefs(); + } + + public GBPrefs getGBPrefs() { + return GBApplication.getGBPrefs(); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupport.java index bce4e64b7..61646c54a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupport.java @@ -62,6 +62,20 @@ public interface DeviceSupport extends EventHandler { */ boolean useAutoConnect(); + /** + * Configures this instance to automatically attempt to reconnect after a connection loss. + * How, how long, or how often is up to the implementation. + * Note that tome implementations may not support automatic reconnection at all. + * @param enable + */ + void setAutoReconnect(boolean enable); + + /** + * Returns whether this instance to configured to automatically attempt to reconnect after a + * connection loss. + */ + boolean getAutoReconnect(); + /** * Attempts to pair and connect this device with the gadget device. Success * will be reported via a device change Intent. diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java index 2a0de20ef..8047aad60 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java @@ -56,6 +56,16 @@ public class ServiceDeviceSupport implements DeviceSupport { return delegate.connect(); } + @Override + public void setAutoReconnect(boolean enable) { + delegate.setAutoReconnect(enable); + } + + @Override + public boolean getAutoReconnect() { + return delegate.getAutoReconnect(); + } + @Override public void dispose() { delegate.dispose(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java index 6361431a9..04179458c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java @@ -42,10 +42,19 @@ public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport im public boolean connect() { if (mQueue == null) { mQueue = new BtLEQueue(getBluetoothAdapter(), getDevice(), this, getContext()); + mQueue.setAutoReconnect(getAutoReconnect()); } return mQueue.connect(); } + @Override + public void setAutoReconnect(boolean enable) { + super.setAutoReconnect(enable); + if (mQueue != null) { + mQueue.setAutoReconnect(enable); + } + } + /** * Subclasses should populate the given builder to initialize the device (if necessary). * diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java index 71d1beaf9..f60094356 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java @@ -34,12 +34,6 @@ public final class BtLEQueue { private final GBDevice mGbDevice; private final BluetoothAdapter mBluetoothAdapter; private BluetoothGatt mBluetoothGatt; - /** - * When an automatic reconnect was attempted after a connection breakdown (error) - */ - private long lastReconnectTime = System.currentTimeMillis(); - - private static final long MIN_MILLIS_BEFORE_RECONNECT = 1000 * 60 * 5; // 5 minutes private final BlockingQueue mTransactions = new LinkedBlockingQueue<>(); private volatile boolean mDisposed; @@ -51,6 +45,7 @@ public final class BtLEQueue { private CountDownLatch mConnectionLatch; private BluetoothGattCharacteristic mWaitCharacteristic; private final InternalGattCallback internalGattCallback; + private boolean mAutoReconnect; private Thread dispatchThread = new Thread("GadgetBridge GATT Dispatcher") { @@ -130,6 +125,10 @@ public final class BtLEQueue { dispatchThread.start(); } + public void setAutoReconnect(boolean enable) { + mAutoReconnect = enable; + } + protected boolean isConnected() { return mGbDevice.isConnected(); } @@ -222,11 +221,9 @@ public final class BtLEQueue { * @return true if a reconnection attempt was made, or false otherwise */ private boolean maybeReconnect() { - long currentTime = System.currentTimeMillis(); - if (currentTime - lastReconnectTime >= MIN_MILLIS_BEFORE_RECONNECT) { - LOG.info("Automatic reconnection attempt..."); - lastReconnectTime = currentTime; - return connect(); + if (mAutoReconnect && mBluetoothGatt != null) { + LOG.info("Enabling automatic ble reconnect..."); + return mBluetoothGatt.connect(); } return false; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java index 97357ccf2..2d97818d7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java @@ -3,9 +3,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.miband; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.content.Intent; -import android.content.SharedPreferences; import android.net.Uri; -import android.preference.PreferenceManager; import android.support.v4.content.LocalBroadcastManager; import android.widget.Toast; @@ -21,6 +19,7 @@ import java.util.GregorianCalendar; import java.util.List; import java.util.UUID; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; @@ -52,6 +51,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.Fe import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.UpdateFirmwareOperation; import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.DEFAULT_VALUE_FLASH_COLOUR; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.DEFAULT_VALUE_FLASH_COUNT; @@ -422,7 +422,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { private void performPreferredNotification(String task, String notificationOrigin, BtLEAction extraAction) { try { TransactionBuilder builder = performInitialized(task); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); + Prefs prefs = GBApplication.getPrefs(); int vibrateDuration = getPreferredVibrateDuration(notificationOrigin, prefs); int vibratePause = getPreferredVibratePause(notificationOrigin, prefs); short vibrateTimes = getPreferredVibrateCount(notificationOrigin, prefs); @@ -441,35 +441,35 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } } - private int getPreferredFlashDuration(String notificationOrigin, SharedPreferences prefs) { + private int getPreferredFlashDuration(String notificationOrigin, Prefs prefs) { return getNotificationPrefIntValue(FLASH_DURATION, notificationOrigin, prefs, DEFAULT_VALUE_FLASH_DURATION); } - private int getPreferredOriginalColour(String notificationOrigin, SharedPreferences prefs) { + private int getPreferredOriginalColour(String notificationOrigin, Prefs prefs) { return getNotificationPrefIntValue(FLASH_ORIGINAL_COLOUR, notificationOrigin, prefs, DEFAULT_VALUE_FLASH_ORIGINAL_COLOUR); } - private int getPreferredFlashColour(String notificationOrigin, SharedPreferences prefs) { + private int getPreferredFlashColour(String notificationOrigin, Prefs prefs) { return getNotificationPrefIntValue(FLASH_COLOUR, notificationOrigin, prefs, DEFAULT_VALUE_FLASH_COLOUR); } - private int getPreferredFlashCount(String notificationOrigin, SharedPreferences prefs) { + private int getPreferredFlashCount(String notificationOrigin, Prefs prefs) { return getNotificationPrefIntValue(FLASH_COUNT, notificationOrigin, prefs, DEFAULT_VALUE_FLASH_COUNT); } - private int getPreferredVibratePause(String notificationOrigin, SharedPreferences prefs) { + private int getPreferredVibratePause(String notificationOrigin, Prefs prefs) { return getNotificationPrefIntValue(VIBRATION_PAUSE, notificationOrigin, prefs, DEFAULT_VALUE_VIBRATION_PAUSE); } - private short getPreferredVibrateCount(String notificationOrigin, SharedPreferences prefs) { + private short getPreferredVibrateCount(String notificationOrigin, Prefs prefs) { return (short) Math.min(Short.MAX_VALUE, getNotificationPrefIntValue(VIBRATION_COUNT, notificationOrigin, prefs, DEFAULT_VALUE_VIBRATION_COUNT)); } - private int getPreferredVibrateDuration(String notificationOrigin, SharedPreferences prefs) { + private int getPreferredVibrateDuration(String notificationOrigin, Prefs prefs) { return getNotificationPrefIntValue(VIBRATION_DURATION, notificationOrigin, prefs, DEFAULT_VALUE_VIBRATION_DURATION); } - private VibrationProfile getPreferredVibrateProfile(String notificationOrigin, SharedPreferences prefs, short repeat) { + private VibrationProfile getPreferredVibrateProfile(String notificationOrigin, Prefs prefs, short repeat) { String profileId = getNotificationPrefStringValue(VIBRATION_PROFILE, notificationOrigin, prefs, DEFAULT_VALUE_VIBRATION_PROFILE); return VibrationProfile.getProfile(profileId, repeat); } @@ -1031,8 +1031,8 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { TransactionBuilder builder = performInitialized("Send upcoming events"); BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); - int availableSlots = Integer.parseInt(prefs.getString(MiBandConst.PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR, "0")); + Prefs prefs = GBApplication.getPrefs(); + int availableSlots = prefs.getInt(MiBandConst.PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR, 0); if (availableSlots > 0) { CalendarEvents upcomingEvents = new CalendarEvents(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/FetchActivityOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/FetchActivityOperation.java index ea4dd0690..183999f3d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/FetchActivityOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/FetchActivityOperation.java @@ -2,9 +2,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; -import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; -import android.preference.PreferenceManager; import android.widget.Toast; import org.slf4j.Logger; @@ -32,6 +30,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceBusyAc import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.MiBandSupport; import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; //import java.util.concurrent.Executors; //import java.util.concurrent.ScheduledExecutorService; @@ -365,7 +364,7 @@ public class FetchActivityOperation extends AbstractMiBandOperation { */ private void sendAckDataTransfer(Calendar time, int bytesTransferred) { byte[] ackTime = MiBandDateConverter.calendarToRawBytes(time); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); + Prefs prefs = GBApplication.getPrefs(); byte[] ackChecksum = new byte[]{ (byte) (bytesTransferred & 0xff), diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index b2a42630a..d22650273 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -8,10 +8,8 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.net.Uri; import android.os.ParcelUuid; -import android.preference.PreferenceManager; import org.json.JSONArray; import org.json.JSONException; @@ -29,6 +27,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.UUID; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo; @@ -44,6 +43,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.PebbleUtils; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class PebbleIoThread extends GBDeviceIoThread { private static final Logger LOG = LoggerFactory.getLogger(PebbleIoThread.class); @@ -62,7 +62,7 @@ public class PebbleIoThread extends GBDeviceIoThread { public static final String PEBBLEKIT_ACTION_APP_START = "com.getpebble.action.app.START"; public static final String PEBBLEKIT_ACTION_APP_STOP = "com.getpebble.action.app.STOP"; - final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); + final Prefs prefs = GBApplication.getPrefs(); private final PebbleProtocol mPebbleProtocol; private final PebbleSupport mPebbleSupport; @@ -160,7 +160,7 @@ public class PebbleIoThread extends GBDeviceIoThread { mPebbleProtocol = (PebbleProtocol) gbDeviceProtocol; mBtAdapter = btAdapter; mPebbleSupport = pebbleSupport; - mEnablePebblekit = sharedPrefs.getBoolean("pebble_enable_pebblekit", false); + mEnablePebblekit = prefs.getBoolean("pebble_enable_pebblekit", false); } @Override @@ -199,7 +199,7 @@ public class PebbleIoThread extends GBDeviceIoThread { return false; } - mPebbleProtocol.setForceProtocol(sharedPrefs.getBoolean("pebble_force_protocol", false)); + mPebbleProtocol.setForceProtocol(prefs.getBoolean("pebble_force_protocol", false)); mIsConnected = true; if (originalState == GBDevice.State.WAITING_FOR_RECONNECT) { @@ -364,8 +364,8 @@ public class PebbleIoThread extends GBDeviceIoThread { if (e.getMessage().contains("socket closed")) { //FIXME: this does not feel right LOG.info(e.getMessage()); mIsConnected = false; - int reconnectAttempts = Integer.valueOf(sharedPrefs.getString("pebble_reconnect_attempts", "10")); - if (reconnectAttempts > 0) { + int reconnectAttempts = prefs.getInt("pebble_reconnect_attempts", 10); + if (GBApplication.getGBPrefs().getAutoReconnect() && reconnectAttempts > 0) { gbDevice.setState(GBDevice.State.CONNECTING); gbDevice.sendDeviceUpdateIntent(getContext()); int delaySeconds = 1; @@ -480,7 +480,7 @@ public class PebbleIoThread extends GBDeviceIoThread { private boolean evaluateGBDeviceEventPebble(GBDeviceEvent deviceEvent) { if (deviceEvent instanceof GBDeviceEventVersionInfo) { - if (sharedPrefs.getBoolean("datetime_synconconnect", true)) { + if (prefs.getBoolean("datetime_synconconnect", true)) { LOG.info("syncing time"); write(mPebbleProtocol.encodeSetTime()); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/GBMusicControlReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/GBMusicControlReceiver.java index fce017656..459d3c15d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/GBMusicControlReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/GBMusicControlReceiver.java @@ -3,16 +3,16 @@ package nodomain.freeyourgadget.gadgetbridge.service.receivers; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.media.AudioManager; import android.os.SystemClock; -import android.preference.PreferenceManager; import android.view.KeyEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class GBMusicControlReceiver extends BroadcastReceiver { private static final Logger LOG = LoggerFactory.getLogger(GBMusicControlReceiver.class); @@ -53,8 +53,8 @@ public class GBMusicControlReceiver extends BroadcastReceiver { } if (keyCode != -1) { - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); - String audioPlayer = sharedPrefs.getString("audio_player", "default"); + Prefs prefs = GBApplication.getPrefs(); + String audioPlayer = prefs.getString("audio_player", "default"); long eventtime = SystemClock.uptimeMillis(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java index b3aad4b79..05a629768 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java @@ -3,8 +3,6 @@ package nodomain.freeyourgadget.gadgetbridge.util; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; import android.widget.Toast; import java.util.ArrayList; @@ -12,6 +10,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.UnknownDeviceCoordinator; @@ -75,8 +74,8 @@ public class DeviceHelper { } } - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); - String miAddr = sharedPrefs.getString(MiBandConst.PREF_MIBAND_ADDRESS, ""); + Prefs prefs = GBApplication.getPrefs(); + String miAddr = prefs.getString(MiBandConst.PREF_MIBAND_ADDRESS, ""); if (miAddr.length() > 0) { GBDevice miDevice = new GBDevice(miAddr, "MI", DeviceType.MIBAND); if (!availableDevices.contains(miDevice)) { @@ -84,8 +83,8 @@ public class DeviceHelper { } } - String pebbleEmuAddr = sharedPrefs.getString("pebble_emu_addr", ""); - String pebbleEmuPort = sharedPrefs.getString("pebble_emu_port", ""); + String pebbleEmuAddr = prefs.getString("pebble_emu_addr", ""); + String pebbleEmuPort = prefs.getString("pebble_emu_port", ""); if (pebbleEmuAddr.length() >= 7 && pebbleEmuPort.length() > 0) { GBDevice pebbleEmuDevice = new GBDevice(pebbleEmuAddr + ":" + pebbleEmuPort, "Pebble qemu", DeviceType.PEBBLE); availableDevices.add(pebbleEmuDevice); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GBPrefs.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GBPrefs.java new file mode 100644 index 000000000..e895919d3 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GBPrefs.java @@ -0,0 +1,16 @@ +package nodomain.freeyourgadget.gadgetbridge.util; + +public class GBPrefs { + + public static final String AUTO_RECONNECT = "general_autocreconnect"; + public static boolean AUTO_RECONNECT_DEFAULT = true; + private final Prefs mPrefs; + + public GBPrefs(Prefs prefs) { + mPrefs = prefs; + } + + public boolean getAutoReconnect() { + return mPrefs.getBoolean(AUTO_RECONNECT, AUTO_RECONNECT_DEFAULT); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/Prefs.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/Prefs.java new file mode 100644 index 000000000..2b4fcdb62 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/Prefs.java @@ -0,0 +1,149 @@ +package nodomain.freeyourgadget.gadgetbridge.util; + +import android.content.SharedPreferences; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Set; + +/** + * Wraps SharedPreferences to avoid ClassCastExceptions and others. + */ +public class Prefs { + private static final Logger LOG = LoggerFactory.getLogger(Prefs.class); + + private final SharedPreferences preferences; + + public Prefs(SharedPreferences preferences) { + this.preferences = preferences; + } + + public String getString(String key, String defaultValue) { + String value = preferences.getString(key, defaultValue); + if (value == null || "".equals(value)) { + return defaultValue; + } + return value; + } + + public Set getStringSet(String key, Set defaultValue) { + Set value = preferences.getStringSet(key, defaultValue); + if (value == null || value.isEmpty()) { + return defaultValue; + } + return value; + } + + /** + * Returns the preference saved under the given key as an integer value. + * Note that it is irrelevant whether the preference value was actually + * saved as an integer value or a string value. + * @param key the preference key + * @param defaultValue the default value to return if the preference value is unset + * @return the saved preference value or the given defaultValue + */ + public int getInt(String key, int defaultValue) { + try { + return preferences.getInt(key, defaultValue); + } catch (Exception ex) { + try { + String value = preferences.getString(key, String.valueOf(defaultValue)); + if ("".equals(value)) { + return defaultValue; + } + return Integer.parseInt(value); + } catch (Exception ex2) { + logReadError(key, ex); + return defaultValue; + } + } + } + + /** + * Returns the preference saved under the given key as a long value. + * Note that it is irrelevant whether the preference value was actually + * saved as a long value or a string value. + * @param key the preference key + * @param defaultValue the default value to return if the preference value is unset + * @return the saved preference value or the given defaultValue + */ + public long getLong(String key, long defaultValue) { + try { + return preferences.getLong(key, defaultValue); + } catch (Exception ex) { + try { + String value = preferences.getString(key, String.valueOf(defaultValue)); + if ("".equals(value)) { + return defaultValue; + } + return Long.parseLong(value); + } catch (Exception ex2) { + logReadError(key, ex); + return defaultValue; + } + } + } + + /** + * Returns the preference saved under the given key as a float value. + * Note that it is irrelevant whether the preference value was actually + * saved as a float value or a string value. + * @param key the preference key + * @param defaultValue the default value to return if the preference value is unset + * @return the saved preference value or the given defaultValue + */ + public float getFloat(String key, float defaultValue) { + try { + return preferences.getFloat(key, defaultValue); + } catch (Exception ex) { + try { + String value = preferences.getString(key, String.valueOf(defaultValue)); + if ("".equals(value)) { + return defaultValue; + } + return Float.parseFloat(value); + } catch (Exception ex2) { + logReadError(key, ex); + return defaultValue; + } + } + } + + /** + * Returns the preference saved under the given key as a boolean value. + * Note that it is irrelevant whether the preference value was actually + * saved as a boolean value or a string value. + * @param key the preference key + * @param defaultValue the default value to return if the preference value is unset + * @return the saved preference value or the given defaultValue + */ + public boolean getBoolean(String key, boolean defaultValue) { + try { + return preferences.getBoolean(key, defaultValue); + } catch (Exception ex) { + try { + String value = preferences.getString(key, String.valueOf(defaultValue)); + if ("".equals(value)) { + return defaultValue; + } + return Boolean.parseBoolean(value); + } catch (Exception ex2) { + logReadError(key, ex); + return defaultValue; + } + } + } + + private void logReadError(String key, Exception ex) { + LOG.error("Error reading preference value: " + key + "; returning default value", ex); // log the first exception + } + + /** + * Access to the underlying SharedPreferences, typically only used for editing values. + * @return the underlying SharedPreferences object. + */ + public SharedPreferences getPreferences() { + return preferences; + } +} diff --git a/app/src/main/res/drawable/ic_add_white.png b/app/src/main/res/drawable/ic_add_white.png new file mode 100644 index 000000000..3705a5578 Binary files /dev/null and b/app/src/main/res/drawable/ic_add_white.png differ diff --git a/app/src/main/res/layout/activity_controlcenter.xml b/app/src/main/res/layout/activity_controlcenter.xml index 7bdcc89fa..1be7d667c 100644 --- a/app/src/main/res/layout/activity_controlcenter.xml +++ b/app/src/main/res/layout/activity_controlcenter.xml @@ -41,7 +41,7 @@ android:layout_alignParentBottom="true" android:layout_alignParentEnd="true" android:layout_gravity="bottom|end" - android:src="@drawable/ic_add_black" + android:src="@drawable/ic_add_white" app:elevation="6dp" app:pressedTranslationZ="12dp" android:layout_marginBottom="10dp" diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f9665cef9..7dfeb3f71 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -70,7 +70,7 @@ Dies ist eine Test Benachrichtigung von Gadgetbridge Bluetooth wird nicht unterstützt. Bluetooth ist abgeschaltet. - berühre das verbundene Gerät, um den App Mananger zu starten + berühre das verbundene Gerät, um den App Manager zu starten berühre ein Gerät zum Verbinden Verbindung kann nicht aufgebaut werden. BT Adresse ungültig? Gadgetbridge läuft @@ -102,13 +102,13 @@ Keine gültigen Benutzerinformationen angegeben, verwende Dummy-Daten für\'s Erste. Wenn Dein Mi Band vibriert und blinkt, tippe ein paar Mal schnell hintereinander darauf. Installieren - Mach Dein Gerät auffindbar. Derzeit verbundene Geräte sind in der Regel nicht auffindbar. + Mach Dein Gerät auffindbar. Derzeit verbundene Geräte sind in der Regel nicht auffindbar. Wenn Dein Gerät nach zwei Minuten nicht angezeigt wird, versuche es nach einem Neustart Deines Telefons noch einmal. Tipp: Bild des Geräts Name/Alias Anzahl der Vibrationen Schlafmonitor - Log-Dateien schreiben (Neustart erforderlich) + Log-Dateien schreiben initialisiere Hole Aktivitätsdaten Von %1$s bis %2$s diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index f4e480546..6dc1e3cc2 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -107,7 +107,7 @@ Nombre/Apodo Número de vibraciones Monitor de sueño - Guardar logs (requiere reiniciar) + Guardar logs iniciando Recuperando datos de actividad Desde %1$s a %2$s diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 0d578e24f..4324f1f65 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -71,7 +71,7 @@ Le Bluetooth n\'est pas supporté. Le Bluetooth est désactivé. Cliquez sur l\'appareil pour le connecter au gestionnaire d\'application - Cliquez sur l\'appareil pour le connecter + Tapotter sur le périphérique pour le connecter. Connexion impossible. L’adresse Bluetooth est-elle invalide? Gadgetbridge est en fonctionnement Installation du binaire %1$d/%2$d @@ -102,13 +102,12 @@ Aucune donnée utilisateur valide fournie, utilisation de données fictives pour le moment Quand votre Mi Band vibre et clignote, appuyez dessus plusieurs fois d\'affilée. Installer - Rendez votre appareil découvrable. Les appareils déjà connectés ne seront pas découverts. + Rendre votre montre découvrable. Pour l\'instant les appareils connectés ne seront probablement pas découvert. Si votre montre n’apparaît pas après 2 minutes, essayer à nouveau après avoir redémarré. Note: Image de l\'appareil Nom/Pseudo Nombre de vibrations Moniteur de sommeil - Écrire les fichiers journaux (redémarrage requis) Initialisation Récupération des données d\'activité De %1$s à %2$s @@ -197,6 +196,7 @@ Micrologiciel non compatible Ce micrologiciel n\'est pas compatible avec l\'appareil Alarmes à réserver pour événements futurs + Utiliser le capteur cardiaque pour améliorer la précision du sommeil en attente de reconnexion Réinstaller A propos de vous @@ -211,4 +211,14 @@ Configurer ZzZz Ajouter un widget + Préférer le mode heure pendant le sommeil + Une alarme a été enregistré pour %1$02d:%2$02d + Modèle: %1$s + Micrologiciel: %1$s + Erreur à la création de votre fichier log : %1$s + HR: + Le firmware se met à jour + Échec lors de l\'écriture du micrologiciel + Rythme cardiaque + Rythme cardiaque diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index fa3cd0d7b..14f87afb0 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -108,7 +108,7 @@ Nome / Soprannome Numero vibrazioni Monitoraggio del sonno - Salva il log su file (richiede riavvio) + Salva il log su file inizializzazione in corso Recupero dati attività Da %1$s a %2$s diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 6cf3ba015..5018b7d20 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -32,6 +32,9 @@ 日付と時刻 時間を合わせる 接続したとき、Androidで時間またはタイムゾーンを変更したときに、デバイスに時間を同期 + テーマ + ライト + ダーク 通知 繰り返し 電話通知 @@ -108,7 +111,7 @@ 名前/別名 バイブレーション回数 睡眠観測 - ログファイルを出力 (再起動が必要) + ログファイルを出力 初期化中 活動データを取得中 %1$sから%2$sまで @@ -220,4 +223,6 @@ HR: ファームウェアを更新しています ファームウェアを送信しませんでした + 心拍数 + 心拍数 diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 407990cdc..ddce42bca 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -19,6 +19,7 @@ 펌웨어/앱 설치 지금 기존의 Mi Band 펌웨어 대신 %s 펌웨어를 설치하려고 합니다. + 지금 Mi Band의 기존 펌웨어 대신 %1$s와 %2$s 펌웨어를 설치하려고 합니다. 이 펌웨어는 테스트를 거쳤고 가젯브릿지와 호환됩니다. 이 펌웨어는 테스트를 거치지 않았고 가젯브릿지와 호환되지 않을 수 있습니다.\n\n Mi Band에 설치하지 않는 것이 좋습니다. 여전히 계속 진행하기를 원하고 이후에도 정상적으로 작동하기를 원한다면, %s 화이트리스트 펌웨어 버전을 가젯브릿지 개발자들에게 알려주세요. @@ -31,6 +32,9 @@ 날짜와 시간 시간 동기화 시간이 바뀌거나, 시간대가 바뀌거나, 접속을 할 때 기기와 시간을 동기화 + 테마 + 밝음 + 어두움 알림 반복 전화 @@ -48,6 +52,7 @@ 개발자 옵션 Mi Band 주소 Pebble 설정 + 선호하는 액티비티 트래커 제3자 안드로이드 앱 접근을 허용 PebbleKit을 사용하는 안드로이드 앱을 실험적으로 지원 강제 알림 프로토콜 @@ -99,13 +104,13 @@ 올바르지 않은 사용자 정보입니다. 일단 임시 사용자 정보를 사용합니다. Mi Band가 진동하고 깜빡일 때, 연달아 몇 번 두드리세요. 설치 - 기기를 발견 가능하도록 설정하세요. 현재 연결된 기기들은 발견될 수 없습니다. + 기기를 발견 가능하도록 설정하세요. 현재 연결된 기기들은 발견될 수 없습니다. 2분이 지나도 기기가 나타나지 않는다면 재부팅 후 다시 시도해보세요. 알림: 기기 이미지 이름/별명 진동 횟수 수면 측정계 - 기록 파일 작성 (재시작 필요) + 기록 파일 작성 초기화 중 활동 데이터 가져오는 중 %1$s에서 %2$s(으)로 @@ -194,6 +199,7 @@ 호환되지 않는 펌웨어 이 펌웨어는 기기와 호환되지 않습니다 다가오는 이벤트를 위해 예약할 알람 + 수면 측정을 향상시키기 위해 심박 센서 사용 재접속을 기다리는 중 재설치 당신에 대해 @@ -201,4 +207,21 @@ 성별 키 (cm) 몸무게 (kg) + 활성화 + 비활성화 + 인증 중 + 인증 필요 + 설정 + Zzz + 위젯 추가 + 선호하는 수면 시간 + %1$02d:%2$02d 알람이 설정되었습니다 + 하드웨어: %1$s + 펌웨어: %1$s + 기록 파일을 저장할 디렉토리 생성 오류: %1$s + 심박수: + 펌웨어 업데이트 진행 중 + 펌웨어가 전송되지 않음 + 심박수 + 심박수 diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 1047a9824..f17487481 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -105,7 +105,7 @@ Nazwisko/Pseudonim Liczba wibracji Monitor snu - Zapisuj logi (wymaga restartu) + Zapisuj logi Uruchamianie Pobieranie danych aktywności Od %1$s do %2$s diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 6b444aecf..5039e880b 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -12,7 +12,7 @@ Отключиться Отладка - App Mananger + App Manager Удалить Заблокированные уведомления @@ -68,7 +68,7 @@ Это тестовое уведомление от Gadgetbridge Bluetooth не поддерживается. Bluetooth отключён. - нажмите на подключённое устройство для App Mananger + нажмите на подключённое устройство для App Manager нажмите на устройство для соединения Не удалось соединиться. Неверен адрес BT? Gadgetbridge запущен @@ -106,7 +106,7 @@ Имя/псевдоним Количество вибраций Анализ сна - Записывать файлы журнала (нужен перезапуск) + Записывать файлы журнала Инициализация Получение данных активности От %1$s до %2$s diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 3e58a5bf7..58421a74c 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -102,7 +102,7 @@ Titreşim adedi Uyku Monitörü - Kütük dosyalarını yaz (yeniden başlatmak gerekir) + Kütük dosyalarını yaz başlatılıyor Aktivite verisi alınıyor diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index d0aac7a86..f0d6f36a4 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -67,7 +67,7 @@ Це тестове сповіщення від Gadgetbridge Bluetooth не підтримується. Bluetooth вимкнуто. - натисніть на під\'єднаний пристрій для App Mananger + натисніть на під\'єднаний пристрій для App Manager натисніть на пристрій для з\'єднання Не вдалося з\'єднатися. Можливо помилкова адреса BT? Gadgetbridge запущено @@ -105,7 +105,7 @@ Ім\'я/нік Кількість вібрацій Аналіз сну - Записувати файли звіту (потрібен перезапуск) + Записувати файли звіту Ініціалізація… Отримання даних активності Від %1$s до %2$s diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 9d059902d..af3de63c3 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -83,7 +83,7 @@ Ảnh thiết bị Tên/Bí danh Trình giám sát giấc ngủ - Ghi tập tin nhật ký (cần khởi động lại) + Ghi tập tin nhật ký đang khởi chạy Từ %1$s đến %2$s Đeo bên trái hay phải? diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5f43f7648..1ec538ecd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -126,7 +126,7 @@ Vibration Count Sleep Monitor - Write Log Files (needs restart) + Write Log Files initializing Fetching Activity Data From %1$s to %2$s @@ -244,5 +244,6 @@ Firmware not sent Heart Rate Heart Rate + Reconnect automatically diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml index b9dbba008..ab86fe0d9 100644 --- a/app/src/main/res/xml/changelog_master.xml +++ b/app/src/main/res/xml/changelog_master.xml @@ -1,5 +1,22 @@ + + Again some UI/theme improvements + New preference to reconnect after connection loss (defaults to true) + Fix crash when dealing with certain old preference values + Mi Band: automatically reconnect when back in range after connection loss + Mi Band 1S: display heart rate value again when invoked via the Debug view + + + Several UI Improvements + Easier First-time setup by using a FAB + Optional Dark Theme + Notification App Blacklist is now sorted + Gadgetbridge Icon in the notification bar displays connection state + Logging is now configurable without restart + Mi Band 1S: Initial live heartrate tracking + Fix certain crash in charts activity on slower devices (#277) + Fix crash in charts activities when changing the date, quickly (#277) Pebble: support pebble health datalog messages of firmware 3.11 (this adds support for deep sleep!) diff --git a/app/src/main/res/xml/miband_preferences.xml b/app/src/main/res/xml/miband_preferences.xml index c544d2544..bccb1348a 100644 --- a/app/src/main/res/xml/miband_preferences.xml +++ b/app/src/main/res/xml/miband_preferences.xml @@ -79,7 +79,7 @@ android:defaultValue="60" android:inputType="number" android:key="mi_vibration_count_incoming_call" - android:maxLength="1" + android:maxLength="2" android:title="@string/pref_title_notifications_repetitions" /> diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index dad3bc0bd..4def8d019 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -7,6 +7,10 @@ android:defaultValue="false" android:key="general_autoconnectonbluetooth" android:title="@string/pref_title_general_autoconnectonbluetooth" /> + { private final Class mServiceClass; private T mServiceInstance; private Context mContext; - private Application mApplication; + private GBMockApplication mApplication; private boolean wasStarted; private PackageManager mPackageManager; private NotificationManager mNotificationManager; @@ -41,6 +43,10 @@ public abstract class AbstractServiceTestCase { return mServiceInstance; } + protected MockHelper getmMockHelper() { + return mMockHelper; + } + @Before public void setUp() throws Exception { mMockHelper = new MockHelper(); @@ -69,7 +75,7 @@ public abstract class AbstractServiceTestCase { mServiceInstance = null; } - protected Application createApplication(PackageManager packageManager) { + protected GBMockApplication createApplication(PackageManager packageManager) { return new GBMockApplication(packageManager); } @@ -85,9 +91,9 @@ public abstract class AbstractServiceTestCase { return new GBMockContext(application); } - private T createService(Class serviceClass, Application application, NotificationManager notificationManager) throws Exception { + protected T createService(Class serviceClass, GBMockApplication application, NotificationManager notificationManager) throws Exception { T service = mMockHelper.createService(serviceClass, application); - mMockHelper.addSystemServiceTo(service, Context.NOTIFICATION_SERVICE, getNotificationService()); + mMockHelper.addSystemServiceTo(service, Context.NOTIFICATION_SERVICE, notificationManager); return service; } diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationServiceTestCase.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationServiceTestCase.java index e4d1fe5b5..8fa5ea5f7 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationServiceTestCase.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationServiceTestCase.java @@ -1,5 +1,7 @@ package nodomain.freeyourgadget.gadgetbridge.service; +import android.app.Application; +import android.app.NotificationManager; import android.content.Context; import org.junit.Before; @@ -11,6 +13,7 @@ import org.mockito.Mockito; import nodomain.freeyourgadget.gadgetbridge.GBException; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; +import nodomain.freeyourgadget.gadgetbridge.test.GBMockApplication; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -41,6 +44,14 @@ public class DeviceCommunicationServiceTestCase extends AbstractServiceTestCase< super(DeviceCommunicationService.class); } + @Override + protected DeviceCommunicationService createService(Class serviceClass, GBMockApplication application, NotificationManager notificationManager) throws Exception { + DeviceCommunicationService service = getmMockHelper().createDeviceCommunicationService(serviceClass, application); + getmMockHelper().addSystemServiceTo(service, Context.NOTIFICATION_SERVICE, notificationManager); + return service; + } + + @Before public void setUp() throws Exception { super.setUp(); diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/GBMockApplication.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/GBMockApplication.java index 805716fa7..2fb2ffbff 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/GBMockApplication.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/GBMockApplication.java @@ -1,18 +1,27 @@ package nodomain.freeyourgadget.gadgetbridge.test; import android.content.Context; +import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.preference.PreferenceManager; import android.test.mock.MockApplication; import nodomain.freeyourgadget.gadgetbridge.GBEnvironment; import nodomain.freeyourgadget.gadgetbridge.util.GB; +import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs; +import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class GBMockApplication extends MockApplication { + private static final String PREF_NAME = "testprefs"; private final PackageManager mPackageManager; + private Prefs prefs; + private GBPrefs gbPrefs; public GBMockApplication(PackageManager packageManager) { GB.environment = GBEnvironment.createDeviceEnvironment().createLocalTestEnvironment(); mPackageManager = packageManager; + prefs = new Prefs(PreferenceManager.getDefaultSharedPreferences(this)); + gbPrefs = new GBPrefs(prefs); } @Override @@ -25,4 +34,10 @@ public class GBMockApplication extends MockApplication { return mPackageManager; } + public Prefs getPrefs() { + return prefs; + } + public GBPrefs getGBPrefs() { + return gbPrefs; + } } diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/MockHelper.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/MockHelper.java index 9461cab1d..00947b989 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/MockHelper.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/MockHelper.java @@ -11,6 +11,8 @@ import org.mockito.Mockito; import java.lang.reflect.Constructor; +import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; + public class MockHelper { public NotificationManager createNotificationManager(Context mContext) throws Exception { Constructor[] constructors = NotificationManager.class.getDeclaredConstructors(); @@ -29,6 +31,13 @@ public class MockHelper { return mockedService; } + public T createDeviceCommunicationService(Class serviceClass, GBMockApplication application) throws Exception { + T mockedService = createService(serviceClass, application); + Mockito.when(mockedService.getPrefs()).thenReturn(application.getPrefs()); + Mockito.when(mockedService.getGBPrefs()).thenReturn(application.getGBPrefs()); + return mockedService; + } + public void addSystemServiceTo(Context context, String serviceName, Object service) { Mockito.when(context.getSystemService(serviceName)).thenReturn(service); } diff --git a/build.gradle b/build.gradle index cce938648..819874a7d 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.0.0' + classpath 'com.android.tools.build:gradle:2.1.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files