diff --git a/app/build.gradle b/app/build.gradle index d72600d2..aa9c5660 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ tasks.withType(Test) { systemProperty 'MiFirmwareDir', System.getProperty('MiFir android { compileSdkVersion 23 - buildToolsVersion "23.0.2" + buildToolsVersion "23.0.3" defaultConfig { applicationId "nodomain.freeyourgadget.gadgetbridge" @@ -46,12 +46,12 @@ dependencies { testCompile "org.mockito:mockito-core:1.9.5" compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:23.1.1' - compile 'com.android.support:support-v4:23.1.1' + compile 'com.android.support:appcompat-v7:23.3.0' + compile 'com.android.support:support-v4:23.3.0' compile 'com.android.support:design:23.3.0' compile 'com.github.tony19:logback-android-classic:1.1.1-4' compile 'org.slf4j:slf4j-api:1.7.7' - compile 'com.github.PhilJay:MPAndroidChart:v2.2.3' + compile 'com.github.PhilJay:MPAndroidChart:v2.2.4' compile 'com.github.pfichtner:durationformatter:0.1.1' compile 'de.cketti.library.changelog:ckchangelog:1.2.2' compile 'de.greenrobot:greendao:2.1.0' diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index 20e79bed..f292133a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -196,10 +196,6 @@ public class GBApplication extends Application { dbLock.unlock(); } - public static boolean isRunningOnKitkatOrLater() { - return VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; - } - public static boolean isRunningLollipopOrLater() { return VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; } @@ -299,10 +295,14 @@ public class GBApplication extends Application { editor.putString(PREFS_VERSION, Integer.toString(CURRENT_PREFS_VERSION)); break; } - editor.commit(); + editor.apply(); } public static LimitedQueue getIDSenderLookup() { return mIDSenderLookup; } + + 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)); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java index b76e50c3..ba2e5a7f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java @@ -1,7 +1,6 @@ package nodomain.freeyourgadget.gadgetbridge.activities; import android.os.Bundle; -import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; @@ -18,7 +17,7 @@ import android.support.v4.app.FragmentPagerAdapter; * * @see AbstractGBFragment */ -public abstract class AbstractGBFragmentActivity extends FragmentActivity { +public abstract class AbstractGBFragmentActivity extends GBActivity { /** * The {@link android.support.v4.view.PagerAdapter} that will provide * fragments for each of the sections. We use a 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 d9a3b1c3..2d62ce04 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java @@ -20,6 +20,9 @@ import android.view.ViewGroup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.R; + /** * A settings activity with support for preferences directly displaying their value. * If you combine such preferences with a custom OnPreferenceChangeListener, you have @@ -86,6 +89,11 @@ public abstract class AbstractSettingsActivity extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) { + if (GBApplication.isDarkThemeEnabled()) { + setTheme(R.style.GadgetbridgeThemeDark); + } else { + setTheme(R.style.GadgetbridgeTheme); + } getDelegate().installViewFactory(); getDelegate().onCreate(savedInstanceState); super.onCreate(savedInstanceState); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java index 9bfe1295..7b3342ae 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java @@ -2,7 +2,6 @@ package nodomain.freeyourgadget.gadgetbridge.activities; import android.os.Bundle; import android.os.Parcelable; -import android.support.v7.app.AppCompatActivity; import android.text.format.DateFormat; import android.view.MenuItem; import android.widget.CheckBox; @@ -12,7 +11,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm; -public class AlarmDetails extends AppCompatActivity { +public class AlarmDetails extends GBActivity { private GBAlarm alarm; private TimePicker timePicker; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AndroidPairingActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AndroidPairingActivity.java index f85d3ca0..e7900e44 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AndroidPairingActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AndroidPairingActivity.java @@ -1,11 +1,10 @@ package nodomain.freeyourgadget.gadgetbridge.activities; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; import nodomain.freeyourgadget.gadgetbridge.R; -public class AndroidPairingActivity extends AppCompatActivity { +public class AndroidPairingActivity extends GBActivity { @Override protected void onCreate(Bundle savedInstanceState) { 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 06021c08..adf33ddc 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java @@ -11,7 +11,6 @@ import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.NavUtils; import android.support.v4.content.LocalBroadcastManager; -import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; @@ -28,13 +27,14 @@ import org.slf4j.LoggerFactory; import java.util.Collections; import java.util.Comparator; +import java.util.IdentityHashMap; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; -public class AppBlacklistActivity extends AppCompatActivity { +public class AppBlacklistActivity extends GBActivity { private static final Logger LOG = LoggerFactory.getLogger(AppBlacklistActivity.class); private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @@ -60,6 +60,29 @@ public class AppBlacklistActivity extends AppCompatActivity { final List packageList = pm.getInstalledApplications(PackageManager.GET_META_DATA); ListView appListView = (ListView) findViewById(R.id.appListView); + // sort the package list by label and blacklist status + final IdentityHashMap nameMap = new IdentityHashMap<>(packageList.size()); + for (ApplicationInfo ai : packageList) { + CharSequence name = pm.getApplicationLabel(ai); + if (name == null) { + name = ai.packageName; + } + if (GBApplication.blacklist.contains(ai.packageName)) { + // sort blacklisted first by prefixing with a '!' + name = "!" + name; + } + nameMap.put(ai, name.toString()); + } + + Collections.sort(packageList, new Comparator() { + @Override + public int compare(ApplicationInfo ai1, ApplicationInfo ai2) { + final String s1 = nameMap.get(ai1); + final String s2 = nameMap.get(ai2); + return s1.compareTo(s2); + } + }); + final ArrayAdapter adapter = new ArrayAdapter(this, R.layout.item_with_checkbox, packageList) { @Override public View getView(int position, View view, ViewGroup parent) { @@ -80,22 +103,6 @@ public class AppBlacklistActivity extends AppCompatActivity { checkbox.setChecked(GBApplication.blacklist.contains(appInfo.packageName)); - Collections.sort(packageList, new Comparator() { - @Override - public int compare(ApplicationInfo ai1, ApplicationInfo ai2) { - boolean blacklisted1 = GBApplication.blacklist.contains(ai1.packageName); - boolean blacklisted2 = GBApplication.blacklist.contains(ai2.packageName); - - if ((blacklisted1 && blacklisted2) || (!blacklisted1 && !blacklisted2)) { - // both blacklisted or both not blacklisted = sort by alphabet - return ai1.packageName.compareTo(ai2.packageName); - } else if (blacklisted1) { - return -1; - } else { - return 1; - } - } - }); return view; } }; 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 f5182ee3..5be4f6f0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java @@ -10,7 +10,6 @@ import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.NavUtils; import android.support.v4.content.LocalBroadcastManager; -import android.support.v7.app.AppCompatActivity; import android.view.ContextMenu; import android.view.MenuItem; import android.view.View; @@ -37,7 +36,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.PebbleUtils; -public class AppManagerActivity extends AppCompatActivity { +public class AppManagerActivity extends GBActivity { public static final String ACTION_REFRESH_APPLIST = "nodomain.freeyourgadget.gadgetbridge.appmanager.action.refresh_applist"; private static final Logger LOG = LoggerFactory.getLogger(AppManagerActivity.class); 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 d04338cc..49f8e7a7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java @@ -4,7 +4,6 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; -import android.support.v7.app.AppCompatActivity; import android.view.MenuItem; import android.widget.ListView; @@ -21,7 +20,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_ALARMS; -public class ConfigureAlarms extends AppCompatActivity { +public class ConfigureAlarms extends GBActivity { private static final int REQ_CONFIGURE_ALARM = 1; 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 cb188ba4..b9ad4d98 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java @@ -20,7 +20,6 @@ import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v4.content.LocalBroadcastManager; import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v7.app.AppCompatActivity; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; @@ -48,7 +47,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; import nodomain.freeyourgadget.gadgetbridge.util.GB; -public class ControlCenter extends AppCompatActivity { +public class ControlCenter extends GBActivity { private static final Logger LOG = LoggerFactory.getLogger(ControlCenter.class); 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 524522e2..a6eee775 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java @@ -13,7 +13,6 @@ 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.v7.app.AppCompatActivity; import android.view.MenuItem; import android.view.View; import android.widget.Button; @@ -37,7 +36,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; -public class DebugActivity extends AppCompatActivity { +public class DebugActivity extends GBActivity { private static final Logger LOG = LoggerFactory.getLogger(DebugActivity.class); private static final String EXTRA_REPLY = "reply"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java index 82f2c7e5..f2ab531b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java @@ -12,7 +12,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Parcelable; -import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.AdapterView; import android.widget.Button; @@ -33,7 +32,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate; import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; import nodomain.freeyourgadget.gadgetbridge.util.GB; -public class DiscoveryActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { +public class DiscoveryActivity extends GBActivity implements AdapterView.OnItemClickListener { private static final Logger LOG = LoggerFactory.getLogger(DiscoveryActivity.class); private static final long SCAN_DURATION = 60000; // 60s diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ExternalPebbleJSActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ExternalPebbleJSActivity.java index 4c18bb90..7dba008b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ExternalPebbleJSActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ExternalPebbleJSActivity.java @@ -4,7 +4,6 @@ import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.NavUtils; -import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.MenuItem; import android.webkit.ConsoleMessage; @@ -32,7 +31,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.PebbleUtils; -public class ExternalPebbleJSActivity extends AppCompatActivity { +public class ExternalPebbleJSActivity extends GBActivity { private static final Logger LOG = LoggerFactory.getLogger(ExternalPebbleJSActivity.class); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java index be79ea0a..90390a1a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java @@ -8,7 +8,6 @@ import android.net.Uri; import android.os.Bundle; import android.support.v4.app.NavUtils; import android.support.v4.content.LocalBroadcastManager; -import android.support.v7.app.AppCompatActivity; import android.view.MenuItem; import android.view.View; import android.widget.Button; @@ -35,7 +34,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; import nodomain.freeyourgadget.gadgetbridge.util.GB; -public class FwAppInstallerActivity extends AppCompatActivity implements InstallActivity { +public class FwAppInstallerActivity extends GBActivity implements InstallActivity { private static final Logger LOG = LoggerFactory.getLogger(FwAppInstallerActivity.class); private static final String ITEM_DETAILS = "details"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/GBActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/GBActivity.java new file mode 100644 index 00000000..39c972ea --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/GBActivity.java @@ -0,0 +1,22 @@ +package nodomain.freeyourgadget.gadgetbridge.activities; + + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.R; + + +public class GBActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + if (GBApplication.isDarkThemeEnabled()) { + setTheme(R.style.GadgetbridgeThemeDark); + } else { + setTheme(R.style.GadgetbridgeTheme); + } + + super.onCreate(savedInstanceState); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/HeartRateUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/HeartRateUtils.java new file mode 100644 index 00000000..a4d39925 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/HeartRateUtils.java @@ -0,0 +1,14 @@ +package nodomain.freeyourgadget.gadgetbridge.activities; + +public class HeartRateUtils { + public static final int MAX_HEART_RATE_VALUE = 250; + public static final int MIN_HEART_RATE_VALUE = 0; + /** + * The maxiumum gap between two hr measurements in which + * we interpolate between the measurements. Otherwise, two + * distinct measurements will be shown. + * + * Value is in minutes + */ + public static final int MAX_HR_MEASUREMENTS_GAP_MINUTES = 10; +} 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 34942ef2..d541af9c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java @@ -133,11 +133,6 @@ public class SettingsActivity extends AbstractSettingsActivity { @Override protected String[] getPreferenceKeysWithSummary() { return new String[]{ - "audio_player", - "notification_mode_calls", - "notification_mode_sms", - "notification_mode_k9mail", - "pebble_activitytracker", "pebble_emu_addr", "pebble_emu_port", "pebble_reconnect_attempts", @@ -159,7 +154,6 @@ public class SettingsActivity extends AbstractSettingsActivity { "canned_reply_15", "canned_reply_16", PREF_USER_YEAR_OF_BIRTH, - PREF_USER_GENDER, PREF_USER_HEIGHT_CM, PREF_USER_WEIGHT_KG, PREF_USER_SLEEP_DURATION, 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 f163ba65..41c61114 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,11 +4,13 @@ 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 +41,7 @@ import java.util.Set; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBFragment; +import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils; import nodomain.freeyourgadget.gadgetbridge.database.DBAccess; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; @@ -116,6 +119,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { protected int CHART_TEXT_COLOR; protected int LEGEND_TEXT_COLOR; protected int HEARTRATE_COLOR; + protected int HEARTRATE_FILL_COLOR; protected int AK_ACTIVITY_COLOR; protected int AK_DEEP_SLEEP_COLOR; protected int AK_LIGHT_SLEEP_COLOR; @@ -147,11 +151,16 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } protected void init() { - BACKGROUND_COLOR = getResources().getColor(R.color.background_material_light); - DESCRIPTION_COLOR = getResources().getColor(R.color.primarytext); + 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; + CHART_TEXT_COLOR = getResources().getColor(R.color.secondarytext); - LEGEND_TEXT_COLOR = getResources().getColor(R.color.primarytext); HEARTRATE_COLOR = getResources().getColor(R.color.chart_heartrate); + HEARTRATE_FILL_COLOR = getResources().getColor(R.color.chart_heartrate_fill); AK_ACTIVITY_COLOR = getResources().getColor(R.color.chart_activity_light); AK_DEEP_SLEEP_COLOR = getResources().getColor(R.color.chart_light_sleep_light); AK_LIGHT_SLEEP_COLOR = getResources().getColor(R.color.chart_deep_sleep_light); @@ -335,6 +344,8 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } protected void configureChartDefaults(Chart chart) { + chart.setDescription(""); + // if enabled, the chart will always start at zero on the y-axis chart.setNoDataText(getString(R.string.chart_no_data_synchronize)); @@ -343,6 +354,8 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { // enable touch gestures chart.setTouchEnabled(true); + + setupLegend(chart); } protected void configureBarLineChartDefaults(BarLineChartBase chart) { @@ -380,9 +393,9 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { /** * This method reads the data from the database, analyzes and prepares it for * the charts. This will be called from a background task, so there must not be - * any UI access. #renderCharts will be automatically called after this method. + * any UI access. #updateChartsInUIThread and #renderCharts will be automatically called after this method. */ - protected abstract void refreshInBackground(DBHandler db, GBDevice device); + protected abstract ChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device); /** * Triggers the actual (re-) rendering of the chart. @@ -390,7 +403,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { */ protected abstract void renderCharts(); - protected void refresh(GBDevice gbDevice, BarLineChartBase chart, List samples) { + protected DefaultChartsData refresh(GBDevice gbDevice, List samples) { Calendar cal = GregorianCalendar.getInstance(); cal.clear(); Date date; @@ -398,6 +411,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { String dateStringTo = ""; LOG.info("" + getTitle() + ": number of samples:" + samples.size()); + CombinedData combinedData; if (samples.size() > 1) { boolean annotate = true; boolean use_steps_as_movement; @@ -413,6 +427,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { boolean hr = supportsHeartrate(); List heartrateEntries = hr ? new ArrayList(numEntries) : null; List colors = new ArrayList<>(numEntries); // this is kinda inefficient... + int lastHrSampleIndex = -1; for (int i = 0; i < numEntries; i++) { ActivitySample sample = samples.get(i); @@ -455,7 +470,13 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } activityEntries.add(createBarEntry(value, i)); if (hr && isValidHeartRateValue(sample.getCustomValue())) { + if (lastHrSampleIndex > -1 && i - lastHrSampleIndex > HeartRateUtils.MAX_HR_MEASUREMENTS_GAP_MINUTES) { + heartrateEntries.add(createLineEntry(0, lastHrSampleIndex + 1)); + heartrateEntries.add(createLineEntry(0, i - 1)); + } + heartrateEntries.add(createLineEntry(sample.getCustomValue(), i)); + lastHrSampleIndex = i; } String xLabel = ""; @@ -486,11 +507,11 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { xLabels.add(xLabel); } - chart.getXAxis().setValues(xLabels); +// chart.getXAxis().setValues(xLabels); BarDataSet activitySet = createActivitySet(activityEntries, colors, "Activity"); // create a data object with the datasets - CombinedData combinedData = new CombinedData(xLabels); + combinedData = new CombinedData(xLabels); List list = new ArrayList<>(); list.add(activitySet); BarData barData = new BarData(xLabels, list); @@ -503,21 +524,17 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { combinedData.setData(lineData); } - chart.setDescription(""); // chart.setDescription(getString(R.string.sleep_activity_date_range, dateStringFrom, dateStringTo)); // chart.setDescriptionPosition(?, ?); - - setupLegend(chart); - - chart.setData(combinedData); } else { - CombinedData data = new CombinedData(Collections.emptyList()); - chart.setData(data); + combinedData = new CombinedData(Collections.emptyList()); } + + return new DefaultChartsData(combinedData); } protected boolean isValidHeartRateValue(int value) { - return value > 0 && value < 255; + return value > HeartRateUtils.MIN_HEART_RATE_VALUE && value < HeartRateUtils.MAX_HEART_RATE_VALUE; } /** @@ -561,23 +578,19 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { protected LineDataSet createHeartrateSet(List values, String label) { LineDataSet set1 = new LineDataSet(values, label); + set1.setLineWidth(0.8f); set1.setColor(HEARTRATE_COLOR); -// set1.setColors(colors); set1.setDrawCubic(true); set1.setCubicIntensity(0.1f); -// //set1.setDrawFilled(true); -// set1.setDrawCircles(false); -// set1.setLineWidth(2f); - set1.setDrawCircles(false); // set1.setCircleRadius(2f); // set1.setDrawFilled(true); - - set1.setLineWidth(0.8f); +// set1.setColor(getResources().getColor(android.R.color.background_light)); +// set1.setCircleColor(HEARTRATE_COLOR); // set1.setFillColor(ColorTemplate.getHoloBlue()); - set1.setDrawValues(true); // set1.setHighLightColor(Color.rgb(128, 0, 255)); // set1.setColor(Color.rgb(89, 178, 44)); + set1.setDrawValues(true); set1.setValueTextColor(CHART_TEXT_COLOR); set1.setAxisDependency(YAxis.AxisDependency.RIGHT); return set1; @@ -622,6 +635,8 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } public class RefreshTask extends DBAccess { + private ChartsData chartsData; + public RefreshTask(String task, Context context) { super(task, context); } @@ -630,7 +645,9 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { protected void doInBackground(DBHandler db) { ChartsHost chartsHost = getChartsHost(); if (chartsHost != null) { - refreshInBackground(db, chartsHost.getDevice()); + chartsData = refreshInBackground(chartsHost, db, chartsHost.getDevice()); + } else { + cancel(true); } } @@ -639,6 +656,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { super.onPostExecute(o); FragmentActivity activity = getActivity(); if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) { + updateChartsnUIThread(chartsData); renderCharts(); } else { LOG.info("Not rendering charts because activity is not available anymore"); @@ -646,6 +664,8 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { } } + protected abstract void updateChartsnUIThread(ChartsData chartsData); + /** * Returns true if the date was successfully shifted, and false if the shift * was ignored, e.g. when the to-value is in the future. @@ -689,4 +709,16 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { private int toTimestamp(Date date) { return (int) ((date.getTime() / 1000)); } + + public static class DefaultChartsData extends ChartsData { + private final CombinedData combinedData; + + public DefaultChartsData(CombinedData combinedData) { + this.combinedData = combinedData; + } + + public CombinedData getCombinedData() { + return combinedData; + } + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java index cd45452d..7260a205 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; @@ -83,8 +84,8 @@ public class ActivitySleepChartFragment extends AbstractChartFragment { yAxisRight.setDrawLabels(true); yAxisRight.setDrawTopYLabelEntry(true); yAxisRight.setTextColor(CHART_TEXT_COLOR); - yAxisRight.setAxisMaxValue(250); - yAxisRight.setAxisMinValue(0); + yAxisRight.setAxisMaxValue(HeartRateUtils.MAX_HEART_RATE_VALUE); + yAxisRight.setAxisMinValue(HeartRateUtils.MIN_HEART_RATE_VALUE); // refresh immediately instead of use refreshIfVisible(), for perceived performance refresh(); @@ -106,11 +107,16 @@ public class ActivitySleepChartFragment extends AbstractChartFragment { } @Override - protected void refreshInBackground(DBHandler db, GBDevice device) { + protected ChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) { List samples = getSamples(db, device); - refresh(device, mChart, samples); + return refresh(device, samples); + } + @Override + protected void updateChartsnUIThread(ChartsData chartsData) { + DefaultChartsData dcd = (DefaultChartsData) chartsData; mChart.getLegend().setTextColor(LEGEND_TEXT_COLOR); + mChart.setData(dcd.getCombinedData()); } protected void renderCharts() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsData.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsData.java new file mode 100644 index 00000000..4285951f --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsData.java @@ -0,0 +1,4 @@ +package nodomain.freeyourgadget.gadgetbridge.activities.charts; + +public abstract class ChartsData { +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java index d7b2ca24..7b201372 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java @@ -23,6 +23,7 @@ import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.data.BarData; import com.github.mikephil.charting.data.BarDataSet; import com.github.mikephil.charting.data.BarEntry; +import com.github.mikephil.charting.data.ChartData; import com.github.mikephil.charting.data.Entry; import com.github.mikephil.charting.data.LineData; import com.github.mikephil.charting.data.LineDataSet; @@ -39,10 +40,12 @@ import java.util.concurrent.TimeUnit; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; +import nodomain.freeyourgadget.gadgetbridge.model.Measurement; import nodomain.freeyourgadget.gadgetbridge.util.GB; public class LiveActivityFragment extends AbstractChartFragment { @@ -63,6 +66,9 @@ public class LiveActivityFragment extends AbstractChartFragment { private final Steps mSteps = new Steps(); private ScheduledExecutorService pulseScheduler; private int maxStepsResetCounter; + private List heartRateValues; + private LineDataSet mHeartRateSet; + private int mHeartRate; private class Steps { private int initialSteps; @@ -145,16 +151,36 @@ public class LiveActivityFragment extends AbstractChartFragment { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); switch (action) { - case DeviceService.ACTION_REALTIME_STEPS: + case DeviceService.ACTION_REALTIME_STEPS: { int steps = intent.getIntExtra(DeviceService.EXTRA_REALTIME_STEPS, 0); long timestamp = intent.getLongExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis()); - refreshCurrentSteps(steps, timestamp); + addEntries(steps, timestamp); break; + } + case DeviceService.ACTION_HEARTRATE_MEASUREMENT: { + int heartRate = intent.getIntExtra(DeviceService.EXTRA_HEART_RATE_VALUE, 0); + long timestamp = intent.getLongExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis()); + if (isValidHeartRateValue(heartRate)) { + setCurrentHeartRate(heartRate, timestamp); + } + break; + } } } }; - private void refreshCurrentSteps(int steps, long timestamp) { + private void setCurrentHeartRate(int heartRate, long timestamp) { + addHistoryDataSet(true); + mHeartRate = heartRate; + } + + private int getCurrentHeartRate() { + int result = mHeartRate; + mHeartRate = -1; + return result; + } + + private void addEntries(int steps, long timestamp) { mSteps.updateCurrentSteps(steps, timestamp); if (++maxStepsResetCounter > RESET_COUNT) { maxStepsResetCounter = 0; @@ -163,10 +189,10 @@ public class LiveActivityFragment extends AbstractChartFragment { // Or: count down the steps until goal reached? And then flash GOAL REACHED -> Set stretch goal LOG.info("Steps: " + steps + ", total: " + mSteps.getTotalSteps() + ", current: " + mSteps.getStepsPerMinute(false)); -// refreshCurrentSteps(); +// addEntries(); } - private void refreshCurrentSteps() { + private void addEntries() { mTotalStepsChart.setSingleEntryYValue(mSteps.getTotalSteps()); YAxis stepsPerMinuteCurrentYAxis = mStepsPerMinuteCurrentChart.getAxisLeft(); int maxStepsPerMinute = mSteps.getMaxStepsPerMinute(); @@ -180,24 +206,36 @@ public class LiveActivityFragment extends AbstractChartFragment { int stepsPerMinute = mSteps.getStepsPerMinute(true); mStepsPerMinuteCurrentChart.setSingleEntryYValue(stepsPerMinute); - if (mStepsPerMinuteHistoryChart.getData() == null) { - if (mSteps.getTotalSteps() == 0) { - return; // ignore the first default value to keep the "no-data-description" visible - } - LineData data = new LineData(); - mStepsPerMinuteHistoryChart.setData(data); - data.addDataSet(mHistorySet); + if (!addHistoryDataSet(false)) { + return; } - LineData historyData = (LineData) mStepsPerMinuteHistoryChart.getData(); - historyData.addXValue(""); - historyData.addEntry(new Entry(stepsPerMinute, mHistorySet.getEntryCount()), 0); + ChartData data = mStepsPerMinuteHistoryChart.getData(); + data.addXValue(""); + if (stepsPerMinute < 0) { + stepsPerMinute = 0; + } + mHistorySet.addEntry(new Entry(stepsPerMinute, data.getXValCount() - 1)); + int hr = getCurrentHeartRate(); + if (hr < 0) { + hr = 0; + } + mHeartRateSet.addEntry(new Entry(hr, data.getXValCount() - 1)); + } - mTotalStepsData.notifyDataSetChanged(); - mStepsPerMinuteData.notifyDataSetChanged(); - mStepsPerMinuteHistoryChart.notifyDataSetChanged(); - - renderCharts(); + private boolean addHistoryDataSet(boolean force) { + if (mStepsPerMinuteHistoryChart.getData() == null) { + // ignore the first default value to keep the "no-data-description" visible + if (force || mSteps.getTotalSteps() > 0) { + LineData data = new LineData(); + data.addDataSet(mHistorySet); + data.addDataSet(mHeartRateSet); + mStepsPerMinuteHistoryChart.setData(data); + return true; + } + return false; + } + return true; } @Nullable @@ -205,6 +243,8 @@ public class LiveActivityFragment extends AbstractChartFragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { IntentFilter filterLocal = new IntentFilter(); filterLocal.addAction(DeviceService.ACTION_REALTIME_STEPS); + filterLocal.addAction(DeviceService.ACTION_HEARTRATE_MEASUREMENT); + heartRateValues = new ArrayList<>(); View rootView = inflater.inflate(R.layout.fragment_live_activity, container, false); @@ -227,16 +267,12 @@ public class LiveActivityFragment extends AbstractChartFragment { @Override public void onPause() { super.onPause(); - if (pulseScheduler != null) { - pulseScheduler.shutdownNow(); - pulseScheduler = null; - } + stopActivityPulse(); } @Override public void onResume() { super.onResume(); - pulseScheduler = startActivityPulse(); } private ScheduledExecutorService startActivityPulse() { @@ -258,11 +294,33 @@ public class LiveActivityFragment extends AbstractChartFragment { return service; } + private void stopActivityPulse() { + if (pulseScheduler != null) { + pulseScheduler.shutdownNow(); + pulseScheduler = null; + } + } + /** * Called in the UI thread. */ private void pulse() { - refreshCurrentSteps(); + addEntries(); + + LineData historyData = (LineData) mStepsPerMinuteHistoryChart.getData(); + if (historyData == null) { + return; + } + + historyData.notifyDataChanged(); + mTotalStepsData.notifyDataSetChanged(); + mStepsPerMinuteData.notifyDataSetChanged(); + mStepsPerMinuteHistoryChart.notifyDataSetChanged(); + + renderCharts(); + + // have to enable it again and again to keep it measureing + GBApplication.deviceService().onEnableRealtimeHeartRateMeasurement(true); } private long getPulseIntervalMillis() { @@ -272,15 +330,19 @@ public class LiveActivityFragment extends AbstractChartFragment { @Override protected void onMadeVisibleInActivity() { GBApplication.deviceService().onEnableRealtimeSteps(true); + GBApplication.deviceService().onEnableRealtimeHeartRateMeasurement(true); super.onMadeVisibleInActivity(); if (getActivity() != null) { getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } + pulseScheduler = startActivityPulse(); } @Override protected void onMadeInvisibleInActivity() { + stopActivityPulse(); GBApplication.deviceService().onEnableRealtimeSteps(false); + GBApplication.deviceService().onEnableRealtimeHeartRateMeasurement(false); if (getActivity() != null) { getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } @@ -346,6 +408,7 @@ public class LiveActivityFragment extends AbstractChartFragment { private void setupHistoryChart(BarLineChartBase chart) { configureBarLineChartDefaults(chart); + chart.setTouchEnabled(false); // no zooming or anything, because it's updated all the time chart.setBackgroundColor(BACKGROUND_COLOR); chart.setDescriptionColor(DESCRIPTION_COLOR); chart.setDescription(getString(R.string.live_activity_steps_per_minute_history)); @@ -367,22 +430,28 @@ public class LiveActivityFragment extends AbstractChartFragment { y.setDrawGridLines(false); y.setDrawTopYLabelEntry(false); y.setTextColor(CHART_TEXT_COLOR); - y.setEnabled(true); + y.setAxisMinValue(0); YAxis yAxisRight = chart.getAxisRight(); yAxisRight.setDrawGridLines(false); - yAxisRight.setEnabled(false); - yAxisRight.setDrawLabels(false); + yAxisRight.setEnabled(true); + yAxisRight.setDrawLabels(true); yAxisRight.setDrawTopYLabelEntry(false); yAxisRight.setTextColor(CHART_TEXT_COLOR); + yAxisRight.setAxisMaxValue(HeartRateUtils.MAX_HEART_RATE_VALUE); + yAxisRight.setAxisMinValue(HeartRateUtils.MIN_HEART_RATE_VALUE); mHistorySet = new LineDataSet(new ArrayList(), getString(R.string.live_activity_steps_history)); + mHistorySet.setAxisDependency(YAxis.AxisDependency.LEFT); mHistorySet.setColor(akActivity.color); mHistorySet.setDrawCircles(false); mHistorySet.setDrawCubic(true); mHistorySet.setDrawFilled(true); mHistorySet.setDrawValues(false); + + mHeartRateSet = createHeartrateSet(new ArrayList(), getString(R.string.live_activity_heart_rate)); + mHeartRateSet.setDrawValues(false); } @Override @@ -402,7 +471,13 @@ public class LiveActivityFragment extends AbstractChartFragment { } @Override - protected void refreshInBackground(DBHandler db, GBDevice device) { + protected ChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) { + throw new UnsupportedOperationException(); + } + + @Override + protected void updateChartsnUIThread(ChartsData chartsData) { + throw new UnsupportedOperationException(); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java index b0836eeb..48ff18f8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivityAmount; @@ -48,14 +49,16 @@ public class SleepChartFragment extends AbstractChartFragment { private int mSmartAlarmGoneOff = -1; @Override - protected void refreshInBackground(DBHandler db, GBDevice device) { + protected ChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) { List samples = getSamples(db, device); - refresh(device, mActivityChart, samples); - refreshSleepAmounts(device, mSleepAmountChart, samples); + MySleepChartsData mySleepChartsData = refreshSleepAmounts(device, samples); + DefaultChartsData chartsData = refresh(device, samples); + + return new MyChartsData(mySleepChartsData, chartsData); } - private void refreshSleepAmounts(GBDevice mGBDevice, PieChart pieChart, List samples) { + private MySleepChartsData refreshSleepAmounts(GBDevice mGBDevice, List samples) { ActivityAnalysis analysis = new ActivityAnalysis(); ActivityAmounts amounts = analysis.calculateActivityAmounts(samples); PieData data = new PieData(); @@ -73,7 +76,6 @@ public class SleepChartFragment extends AbstractChartFragment { } } String totalSleep = DateTimeUtils.formatDurationHoursMinutes(totalSeconds, TimeUnit.SECONDS); - pieChart.setCenterText(totalSleep); PieDataSet set = new PieDataSet(entries, ""); set.setValueFormatter(new ValueFormatter() { @Override @@ -83,10 +85,18 @@ public class SleepChartFragment extends AbstractChartFragment { }); set.setColors(colors); data.setDataSet(set); - pieChart.setData(data); - pieChart.getLegend().setEnabled(false); //setupLegend(pieChart); + return new MySleepChartsData(totalSleep, data); + } + + @Override + protected void updateChartsnUIThread(ChartsData chartsData) { + MyChartsData mcd = (MyChartsData) chartsData; + mSleepAmountChart.setCenterText(mcd.getPieData().getTotalSleep()); + mSleepAmountChart.setData(mcd.getPieData().getPieData()); + + mActivityChart.setData(mcd.getChartsData().getCombinedData()); } @Override @@ -132,6 +142,7 @@ public class SleepChartFragment extends AbstractChartFragment { mSleepAmountChart.setDescription(""); mSleepAmountChart.setNoDataTextDescription(""); mSleepAmountChart.setNoDataText(""); + mSleepAmountChart.getLegend().setEnabled(false); } private void setupActivityChart() { @@ -164,8 +175,8 @@ public class SleepChartFragment extends AbstractChartFragment { yAxisRight.setDrawLabels(true); yAxisRight.setDrawTopYLabelEntry(true); yAxisRight.setTextColor(CHART_TEXT_COLOR); - yAxisRight.setAxisMaxValue(250); - yAxisRight.setAxisMinValue(0); + yAxisRight.setAxisMaxValue(HeartRateUtils.MAX_HEART_RATE_VALUE); + yAxisRight.setAxisMinValue(HeartRateUtils.MIN_HEART_RATE_VALUE); } protected void setupLegend(Chart chart) { @@ -194,4 +205,40 @@ public class SleepChartFragment extends AbstractChartFragment { mActivityChart.animateX(ANIM_TIME, Easing.EasingOption.EaseInOutQuart); mSleepAmountChart.invalidate(); } + + private static class MySleepChartsData extends ChartsData { + private String totalSleep; + private final PieData pieData; + + public MySleepChartsData(String totalSleep, PieData pieData) { + this.totalSleep = totalSleep; + this.pieData = pieData; + } + + public PieData getPieData() { + return pieData; + } + + public CharSequence getTotalSleep() { + return totalSleep; + } + } + + private static class MyChartsData extends ChartsData { + private final DefaultChartsData chartsData; + private final MySleepChartsData pieData; + + public MyChartsData(MySleepChartsData pieData, DefaultChartsData chartsData) { + this.pieData = pieData; + this.chartsData = chartsData; + } + + public MySleepChartsData getPieData() { + return pieData; + } + + public DefaultChartsData getChartsData() { + return chartsData; + } + } } \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java index 927a499b..2e271f28 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java @@ -42,19 +42,30 @@ public class WeekStepsChartFragment extends AbstractChartFragment { private Locale mLocale; private int mTargetSteps = 10000; - private CombinedChart mWeekStepsChart; private PieChart mTodayStepsChart; + private CombinedChart mWeekStepsChart; @Override - protected void refreshInBackground(DBHandler db, GBDevice device) { - ChartsHost chartsHost = getChartsHost(); - if (chartsHost != null) { - Calendar day = Calendar.getInstance(); - day.setTime(chartsHost.getEndDate()); - //NB: we could have omitted the day, but this way we can move things to the past easily - refreshDaySteps(db, mTodayStepsChart, day, device); - refreshWeekBeforeSteps(db, mWeekStepsChart, day, device); - } + protected ChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) { + Calendar day = Calendar.getInstance(); + day.setTime(chartsHost.getEndDate()); + //NB: we could have omitted the day, but this way we can move things to the past easily + DaySteps daySteps = refreshDaySteps(db, day, device); + DefaultChartsData weekBeforeStepsData = refreshWeekBeforeSteps(db, mWeekStepsChart, day, device); + + return new MyChartsData(daySteps, weekBeforeStepsData); + } + + @Override + protected void updateChartsnUIThread(ChartsData chartsData) { + MyChartsData mcd = (MyChartsData) chartsData; + +// setupLegend(mWeekStepsChart); + mTodayStepsChart.setCenterText(NumberFormat.getNumberInstance(mLocale).format(mcd.getDaySteps().totalSteps)); + mTodayStepsChart.setData(mcd.getDaySteps().data); + + mWeekStepsChart.setData(mcd.getWeekBeforeStepsData().getCombinedData()); + mWeekStepsChart.getLegend().setEnabled(false); } @Override @@ -63,7 +74,7 @@ public class WeekStepsChartFragment extends AbstractChartFragment { mTodayStepsChart.invalidate(); } - private void refreshWeekBeforeSteps(DBHandler db, CombinedChart combinedChart, Calendar day, GBDevice device) { + private DefaultChartsData refreshWeekBeforeSteps(DBHandler db, CombinedChart combinedChart, Calendar day, GBDevice device) { ActivityAnalysis analysis = new ActivityAnalysis(); @@ -90,18 +101,16 @@ public class WeekStepsChartFragment extends AbstractChartFragment { CombinedData combinedData = new CombinedData(labels); combinedData.setData(barData); - - setupLegend(combinedChart); - combinedChart.setData(combinedData); - combinedChart.getLegend().setEnabled(false); + return new DefaultChartsData(combinedData); } - private void refreshDaySteps(DBHandler db, PieChart pieChart, Calendar day, GBDevice device) { + + + private DaySteps refreshDaySteps(DBHandler db, Calendar day, GBDevice device) { ActivityAnalysis analysis = new ActivityAnalysis(); int totalSteps = analysis.calculateTotalSteps(getSamplesOfDay(db, day, device)); - pieChart.setCenterText(NumberFormat.getNumberInstance(mLocale).format(totalSteps)); PieData data = new PieData(); List entries = new ArrayList<>(); List colors = new ArrayList<>(); @@ -123,9 +132,8 @@ public class WeekStepsChartFragment extends AbstractChartFragment { data.setDataSet(set); //this hides the values (numeric) added to the set. These would be shown aside the strings set with addXValue above data.setDrawValues(false); - pieChart.setData(data); - pieChart.getLegend().setEnabled(false); + return new DaySteps(data, totalSteps); } @Override @@ -164,6 +172,8 @@ public class WeekStepsChartFragment extends AbstractChartFragment { mTodayStepsChart.setDescription(getContext().getString(R.string.weeksteps_today_steps_description, mTargetSteps)); mTodayStepsChart.setNoDataTextDescription(""); mTodayStepsChart.setNoDataText(""); + mTodayStepsChart.getLegend().setEnabled(false); +// setupLegend(mTodayStepsChart); } private void setupWeekStepsChart() { @@ -196,12 +206,12 @@ public class WeekStepsChartFragment extends AbstractChartFragment { } protected void setupLegend(Chart chart) { - List legendColors = new ArrayList<>(1); - List legendLabels = new ArrayList<>(1); - legendColors.add(akActivity.color); - legendLabels.add(getContext().getString(R.string.chart_steps)); - chart.getLegend().setCustom(legendColors, legendLabels); - chart.getLegend().setTextColor(LEGEND_TEXT_COLOR); +// List legendColors = new ArrayList<>(1); +// List legendLabels = new ArrayList<>(1); +// legendColors.add(akActivity.color); +// legendLabels.add(getContext().getString(R.string.chart_steps)); +// chart.getLegend().setCustom(legendColors, legendLabels); +// chart.getLegend().setTextColor(LEGEND_TEXT_COLOR); } private List getSamplesOfDay(DBHandler db, Calendar day, GBDevice device) { @@ -226,4 +236,32 @@ public class WeekStepsChartFragment extends AbstractChartFragment { protected List getSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) { return super.getAllSamples(db, device, tsFrom, tsTo); } + + private static class DaySteps { + private final PieData data; + private final int totalSteps; + + public DaySteps(PieData data, int totalSteps) { + this.data = data; + this.totalSteps = totalSteps; + } + } + + private static class MyChartsData extends ChartsData { + private final DefaultChartsData weekBeforeStepsData; + private final DaySteps daySteps; + + public MyChartsData(DaySteps daySteps, DefaultChartsData weekBeforeStepsData) { + this.daySteps = daySteps; + this.weekBeforeStepsData = weekBeforeStepsData; + } + + public DaySteps getDaySteps() { + return daySteps; + } + + public DefaultChartsData getWeekBeforeStepsData() { + return weekBeforeStepsData; + } + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java index 5ddad49e..a6dd21bf 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java @@ -44,6 +44,8 @@ public interface EventHandler { void onHeartRateTest(); + void onEnableRealtimeHeartRateMeasurement(boolean enable); + void onFindDevice(boolean start); void onScreenshotReq(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java index 7ef19b80..919e7d2c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java @@ -59,20 +59,14 @@ public class MiBandPreferencesActivity extends AbstractSettingsActivity { protected String[] getPreferenceKeysWithSummary() { return new String[]{ PREF_USER_ALIAS, - PREF_MIBAND_WEARSIDE, PREF_MIBAND_ADDRESS, PREF_MIBAND_FITNESS_GOAL, PREF_MIBAND_DONT_ACK_TRANSFER, PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR, - getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_SMS), getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_SMS), - getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_INCOMING_CALL), getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_INCOMING_CALL), - getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_K9MAIL), getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_K9MAIL), - getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_PEBBLEMSG), getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_PEBBLEMSG), - getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_GENERIC), getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_GENERIC), }; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java index add9f676..61af3fcb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java @@ -216,4 +216,11 @@ public class GBDeviceService implements DeviceService { .putExtra(EXTRA_BOOLEAN_ENABLE, enable); invokeService(intent); } + + @Override + public void onEnableRealtimeHeartRateMeasurement(boolean enable) { + Intent intent = createIntent().setAction(ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT) + .putExtra(EXTRA_BOOLEAN_ENABLE, enable); + invokeService(intent); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java index 7c38088f..2cf979cd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java @@ -33,7 +33,9 @@ public interface DeviceService extends EventHandler { String ACTION_SET_ALARMS = PREFIX + ".action.set_alarms"; String ACTION_ENABLE_REALTIME_STEPS = PREFIX + ".action.enable_realtime_steps"; String ACTION_REALTIME_STEPS = PREFIX + ".action.realtime_steps"; + String ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT = PREFIX + ".action.realtime_hr_measurement"; String ACTION_ENABLE_HEARTRATE_SLEEP_SUPPORT = PREFIX + ".action.enable_heartrate_sleep_support"; + String ACTION_HEARTRATE_MEASUREMENT = PREFIX + ".action.hr_measurement"; String EXTRA_DEVICE_ADDRESS = "device_address"; String EXTRA_NOTIFICATION_BODY = "notification_body"; String EXTRA_NOTIFICATION_FLAGS = "notification_flags"; @@ -62,6 +64,7 @@ public interface DeviceService extends EventHandler { String EXTRA_BOOLEAN_ENABLE = "enable_realtime_steps"; String EXTRA_REALTIME_STEPS = "realtime_steps"; String EXTRA_TIMESTAMP = "timestamp"; + String EXTRA_HEART_RATE_VALUE = "hr_value"; void start(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Measurement.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Measurement.java new file mode 100644 index 00000000..f841da00 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Measurement.java @@ -0,0 +1,33 @@ +package nodomain.freeyourgadget.gadgetbridge.model; + +public class Measurement { + private final int value; + private final long timestamp; + + public Measurement(int value, long timestamp) { + this.value = value; + this.timestamp = timestamp; + } + + public int getValue() { + return value; + } + + public long getTimestamp() { + return timestamp; + } + + @Override + public int hashCode() { + return (int) (71 ^ value ^ timestamp); + } + + @Override + public boolean equals(Object o) { + if (o instanceof Measurement) { + Measurement m = (Measurement) o; + return timestamp == m.timestamp && value == m.value; + } + return super.equals(o); + } +} 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 6ade401d..85e3ceb7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -46,6 +46,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CO import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DELETEAPP; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DISCONNECT; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_ENABLE_HEARTRATE_SLEEP_SUPPORT; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_ENABLE_REALTIME_STEPS; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_FETCH_ACTIVITY_DATA; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_FIND_DEVICE; @@ -349,6 +350,11 @@ public class DeviceCommunicationService extends Service { mDeviceSupport.onEnableHeartRateSleepSupport(enable); break; } + case ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT: { + boolean enable = intent.getBooleanExtra(EXTRA_BOOLEAN_ENABLE, false); + mDeviceSupport.onEnableRealtimeHeartRateMeasurement(enable); + break; + } } return START_STICKY; 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 e54e61bd..2a0de20e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java @@ -250,4 +250,12 @@ public class ServiceDeviceSupport implements DeviceSupport { } delegate.onEnableHeartRateSleepSupport(enable); } + + @Override + public void onEnableRealtimeHeartRateMeasurement(boolean enable) { + if (checkBusy("enable realtime heart rate measurement: " + enable)) { + return; + } + delegate.onEnableRealtimeHeartRateMeasurement(enable); + } } 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 37b22591..97357ccf 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 @@ -603,7 +603,6 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { TransactionBuilder builder = performInitialized("HeartRateTest"); builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementContinuous); builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementManual); - builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementSleep); builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), startHeartMeasurementManual); builder.queue(getQueue()); } catch (IOException ex) { @@ -614,6 +613,24 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } } + @Override + public void onEnableRealtimeHeartRateMeasurement(boolean enable) { + if (supportsHeartRate()) { + try { + TransactionBuilder builder = performInitialized("EnableRealtimeHeartRateMeasurement"); + if (enable) { + builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementManual); + builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), startHeartMeasurementContinuous); + } else { + builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementContinuous); + } + builder.queue(getQueue()); + } catch (IOException ex) { + LOG.error("Unable to enable realtime heart rate measurement in MI1S", ex); + } + } + } + public boolean supportsHeartRate() { return getDeviceInfo() != null && getDeviceInfo().supportsHeartrate(); } @@ -745,7 +762,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } else if (MiBandService.UUID_CHARACTERISTIC_REALTIME_STEPS.equals(characteristicUUID)) { handleRealtimeSteps(characteristic.getValue()); } else if (MiBandService.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT.equals(characteristicUUID)) { - logHeartrate(characteristic.getValue()); + handleHeartrate(characteristic.getValue()); } else { LOG.info("Unhandled characteristic changed: " + characteristicUUID); logMessageContent(characteristic.getValue()); @@ -814,6 +831,15 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } } + private void handleHeartrate(byte[] value) { + if (value.length == 2 && value[0] == 6) { + int hrValue = (value[1] & 0xff); + Intent intent = new Intent(DeviceService.ACTION_HEARTRATE_MEASUREMENT) + .putExtra(DeviceService.EXTRA_HEART_RATE_VALUE, hrValue) + .putExtra(DeviceService.EXTRA_TIMESTAMP, System.currentTimeMillis()); + LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent); + } + } private void handleRealtimeSteps(byte[] value) { int steps = 0xff & value[0] | (0xff & value[1]) << 8; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java index aa78a393..5dfa8b2a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java @@ -181,4 +181,10 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport byte[] bytes = gbDeviceProtocol.encodeEnableHeartRateSleepSupport(enable); sendToDevice(bytes); } + + @Override + public void onEnableRealtimeHeartRateMeasurement(boolean enable) { + byte[] bytes = gbDeviceProtocol.encodeEnableRealtimeHeartRateMeasurement(enable); + sendToDevice(bytes); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java index 2aa1fb66..bdf1b101 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java @@ -63,6 +63,8 @@ public abstract class GBDeviceProtocol { return null; } + public byte[] encodeEnableRealtimeHeartRateMeasurement(boolean enable) { return null; } + public GBDeviceEvent[] decodeResponse(byte[] responseData) { return null; } diff --git a/app/src/main/res/drawable-hdpi/ic_device_miband_disabled.png b/app/src/main/res/drawable-hdpi/ic_device_miband_disabled.png index 43cabe9b..f9f7be9c 100644 Binary files a/app/src/main/res/drawable-hdpi/ic_device_miband_disabled.png and b/app/src/main/res/drawable-hdpi/ic_device_miband_disabled.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_device_pebble_disabled.png b/app/src/main/res/drawable-hdpi/ic_device_pebble_disabled.png index c5772510..8eb1835a 100644 Binary files a/app/src/main/res/drawable-hdpi/ic_device_pebble_disabled.png and b/app/src/main/res/drawable-hdpi/ic_device_pebble_disabled.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_device_miband_disabled.png b/app/src/main/res/drawable-mdpi/ic_device_miband_disabled.png index c1d9e92a..9d9f007a 100644 Binary files a/app/src/main/res/drawable-mdpi/ic_device_miband_disabled.png and b/app/src/main/res/drawable-mdpi/ic_device_miband_disabled.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_device_pebble_disabled.png b/app/src/main/res/drawable-mdpi/ic_device_pebble_disabled.png index 675a26a7..924fcb58 100644 Binary files a/app/src/main/res/drawable-mdpi/ic_device_pebble_disabled.png and b/app/src/main/res/drawable-mdpi/ic_device_pebble_disabled.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_device_miband_disabled.png b/app/src/main/res/drawable-xhdpi/ic_device_miband_disabled.png index e86b4071..401e1750 100644 Binary files a/app/src/main/res/drawable-xhdpi/ic_device_miband_disabled.png and b/app/src/main/res/drawable-xhdpi/ic_device_miband_disabled.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_device_pebble_disabled.png b/app/src/main/res/drawable-xhdpi/ic_device_pebble_disabled.png index 705aad25..f231da8e 100644 Binary files a/app/src/main/res/drawable-xhdpi/ic_device_pebble_disabled.png and b/app/src/main/res/drawable-xhdpi/ic_device_pebble_disabled.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_device_miband_disabled.png b/app/src/main/res/drawable-xxhdpi/ic_device_miband_disabled.png index db5603a2..94dd2c12 100644 Binary files a/app/src/main/res/drawable-xxhdpi/ic_device_miband_disabled.png and b/app/src/main/res/drawable-xxhdpi/ic_device_miband_disabled.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_device_pebble_disabled.png b/app/src/main/res/drawable-xxhdpi/ic_device_pebble_disabled.png index c1eebfd5..24c8f2f5 100644 Binary files a/app/src/main/res/drawable-xxhdpi/ic_device_pebble_disabled.png and b/app/src/main/res/drawable-xxhdpi/ic_device_pebble_disabled.png differ diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml deleted file mode 100644 index 80bee978..00000000 --- a/app/src/main/res/values-v21/styles.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 1f5cfa29..937c29f2 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -1,5 +1,16 @@ + + @string/pref_theme_light + @string/pref_theme_dark + + + @string/pref_theme_value_light + @string/pref_theme_value_dark + + light + dark + @string/always @string/when_screen_off diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 82744a0c..ac484db2 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,11 +7,13 @@ #f0f03000 #0091ea - #ff000000 + #000000 + #ffffff #ff808080 #1f000000 #ffab40 + #fadab1 #0071b7 #4c5aff diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index beac2a5d..5f43f764 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -39,6 +39,9 @@ Date and Time Sync time Sync time to device when connecting and when time or timezone changes on Android + Theme + Light + Dark Notifications Repetitions @@ -240,5 +243,6 @@ Firmware update in progress Firmware not sent Heart Rate + Heart Rate diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 31de7354..5d6ea28d 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,25 +1,29 @@ + - - - - diff --git a/app/src/main/res/xml/miband_preferences.xml b/app/src/main/res/xml/miband_preferences.xml index 042cd8e1..c544d254 100644 --- a/app/src/main/res/xml/miband_preferences.xml +++ b/app/src/main/res/xml/miband_preferences.xml @@ -14,7 +14,8 @@ android:entries="@array/wearside" android:entryValues="@array/wearside_values" android:key="mi_wearside" - android:title="@string/miband_prefs_wearside" /> + android:title="@string/miband_prefs_wearside" + android:summary="%s" /> + android:title="@string/miband_prefs_vibration" + android:summary="%s" /> + android:title="@string/miband_prefs_vibration" + android:summary="%s" /> + android:title="@string/miband_prefs_vibration" + android:summary="%s" /> + android:title="@string/miband_prefs_vibration" + android:summary="%s" /> + android:title="@string/miband_prefs_vibration" + android:summary="%s" /> + android:title="@string/pref_title_audo_player" + android:summary="%s" /> + + android:title="@string/pref_title_notifications_call" + android:summary="%s" /> + android:title="@string/pref_title_notifications_sms" + android:summary="%s" /> + android:title="@string/pref_title_notifications_k9mail" + android:summary="%s" /> + android:title="@string/activity_prefs_gender" + android:summary="%s" /> + android:title="@string/pref_title_pebble_activitytracker" + android:summary="%s" />