diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3bfaf57c5..5725e3bcc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,14 @@
### Changelog
+#### Version 0.21.1
+* Initial support for EXRIZU K8 (HPLus variant)
+* Amazfit Bip: fix long messages not being displayed at all
+* Mi Band 2: Support multiple button actions
+* NO.1 F1: Fetch sleep data
+* NO.1 F1: Heart rate support
+* Pebble: Support controlling the current active media playback application
+* Fix suspended activities coming to front when rotating the screen
+
#### Version 0.21.0
* Initial NO.1 F1 support
* Initial Teclast H30 support
diff --git a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java
index b4ad0dc7f..1f9c7bdbc 100644
--- a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java
+++ b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java
@@ -42,7 +42,7 @@ public class GBDaoGenerator {
public static void main(String[] args) throws Exception {
- Schema schema = new Schema(16, MAIN_PACKAGE + ".entities");
+ Schema schema = new Schema(17, MAIN_PACKAGE + ".entities");
Entity userAttributes = addUserAttributes(schema);
Entity user = addUserInfo(schema, userAttributes);
@@ -265,6 +265,7 @@ public class GBDaoGenerator {
activitySample.addIntProperty(SAMPLE_STEPS).notNull().codeBeforeGetterAndSetter(OVERRIDE);
activitySample.addIntProperty(SAMPLE_RAW_KIND).notNull().codeBeforeGetterAndSetter(OVERRIDE);
activitySample.addIntProperty(SAMPLE_RAW_INTENSITY).notNull().codeBeforeGetterAndSetter(OVERRIDE);
+ addHeartRateProperties(activitySample);
return activitySample;
}
diff --git a/app/build.gradle b/app/build.gradle
index a9dff3d8a..c0e7d68c2 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -26,8 +26,8 @@ android {
targetSdkVersion 25
// note: always bump BOTH versionCode and versionName!
- versionName "0.21.0"
- versionCode 101
+ versionName "0.21.1"
+ versionCode 102
vectorDrawables.useSupportLibrary = true
}
buildTypes {
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBActivity.java
index 475031e23..c0d5a0092 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBActivity.java
@@ -33,6 +33,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils;
public abstract class AbstractGBActivity extends AppCompatActivity implements GBActivity {
+ private boolean isLanguageInvalid = false;
public static final int NONE = 0;
public static final int NO_ACTIONBAR = 1;
@@ -52,8 +53,11 @@ public abstract class AbstractGBActivity extends AppCompatActivity implements GB
}
};
- public void setLanguage(Locale language, boolean recreate) {
- AndroidUtils.setLanguage(this, language, recreate);
+ public void setLanguage(Locale language, boolean invalidateLanguage) {
+ if (invalidateLanguage) {
+ isLanguageInvalid = true;
+ }
+ AndroidUtils.setLanguage(this, language);
}
public static void init(GBActivity activity) {
@@ -88,6 +92,15 @@ public abstract class AbstractGBActivity extends AppCompatActivity implements GB
super.onCreate(savedInstanceState);
}
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (isLanguageInvalid) {
+ isLanguageInvalid = false;
+ recreate();
+ }
+ }
+
@Override
protected void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
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 a1ca99131..1cdb0a158 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractSettingsActivity.java
@@ -49,6 +49,8 @@ public abstract class AbstractSettingsActivity extends AppCompatPreferenceActivi
private static final Logger LOG = LoggerFactory.getLogger(AbstractSettingsActivity.class);
+ private boolean isLanguageInvalid = false;
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -152,6 +154,15 @@ public abstract class AbstractSettingsActivity extends AppCompatPreferenceActivi
}
}
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (isLanguageInvalid) {
+ isLanguageInvalid = false;
+ recreate();
+ }
+ }
+
@Override
protected void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
@@ -210,7 +221,10 @@ public abstract class AbstractSettingsActivity extends AppCompatPreferenceActivi
return super.onOptionsItemSelected(item);
}
- public void setLanguage(Locale language, boolean recreate) {
- AndroidUtils.setLanguage(this, language, recreate);
+ public void setLanguage(Locale language, boolean invalidateLanguage) {
+ if (invalidateLanguage) {
+ isLanguageInvalid = true;
+ }
+ AndroidUtils.setLanguage(this, language);
}
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/CalBlacklistActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/CalBlacklistActivity.java
index 54e4ae15e..88a6b2a20 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/CalBlacklistActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/CalBlacklistActivity.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2017 Daniele Gobbetti
+/* Copyright (C) 2017 Carsten Pfeiffer, Daniele Gobbetti
This file is part of Gadgetbridge.
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java
index 377663d83..171ee0159 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenterv2.java
@@ -78,6 +78,8 @@ public class ControlCenterv2 extends AppCompatActivity
private GBDeviceAdapterv2 mGBDeviceAdapter;
private RecyclerView deviceListView;
+ private boolean isLanguageInvalid = false;
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -206,6 +208,15 @@ public class ControlCenterv2 extends AppCompatActivity
}
}
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (isLanguageInvalid) {
+ isLanguageInvalid = false;
+ recreate();
+ }
+ }
+
@Override
protected void onDestroy() {
unregisterForContextMenu(deviceListView);
@@ -311,7 +322,10 @@ public class ControlCenterv2 extends AppCompatActivity
ActivityCompat.requestPermissions(this, wantedPermissions.toArray(new String[wantedPermissions.size()]), 0);
}
- public void setLanguage(Locale language, boolean recreate) {
- AndroidUtils.setLanguage(this, language, recreate);
+ public void setLanguage(Locale language, boolean invalidateLanguage) {
+ if (invalidateLanguage) {
+ isLanguageInvalid = true;
+ }
+ AndroidUtils.setLanguage(this, language);
}
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/GBActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/GBActivity.java
index 7600c8f66..13a5d640c 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/GBActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/GBActivity.java
@@ -1,9 +1,25 @@
+/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Lem Dulfo
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.activities;
import java.util.Locale;
public interface GBActivity {
- void setLanguage(Locale language, boolean recreate);
+ void setLanguage(Locale language, boolean invalidateLanguage);
void setTheme(int themeId);
}
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 94419a15b..16cfe61e0 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java
@@ -159,6 +159,7 @@ public class SettingsActivity extends AbstractSettingsActivity {
String newLang = newVal.toString();
try {
GBApplication.setLanguage(newLang);
+ recreate();
} catch (Exception ex) {
GB.toast(getApplicationContext(),
"Error setting language: " + ex.getLocalizedMessage(),
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_17.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_17.java
new file mode 100644
index 000000000..04c948539
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_17.java
@@ -0,0 +1,38 @@
+/* Copyright (C) 2017 protomors
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.database.schema;
+
+import android.database.sqlite.SQLiteDatabase;
+
+import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
+import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript;
+import nodomain.freeyourgadget.gadgetbridge.entities.No1F1ActivitySampleDao;
+
+public class GadgetbridgeUpdate_17 implements DBUpdateScript {
+ @Override
+ public void upgradeSchema(SQLiteDatabase db) {
+ if (!DBHelper.existsColumn(No1F1ActivitySampleDao.TABLENAME, No1F1ActivitySampleDao.Properties.HeartRate.columnName, db)) {
+ String ADD_COLUMN_HEART_RATE = "ALTER TABLE " + No1F1ActivitySampleDao.TABLENAME + " ADD COLUMN "
+ + No1F1ActivitySampleDao.Properties.HeartRate.columnName + " INTEGER NOT NULL DEFAULT 0;";
+ db.execSQL(ADD_COLUMN_HEART_RATE);
+ }
+ }
+
+ @Override
+ public void downgradeSchema(SQLiteDatabase db) {
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/EXRIZUK8Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/EXRIZUK8Coordinator.java
new file mode 100644
index 000000000..a630bb92e
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/hplus/EXRIZUK8Coordinator.java
@@ -0,0 +1,55 @@
+/* Copyright (C) 2017 João Paulo Barraca, Quallenauge
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.devices.hplus;
+
+/*
+* @author Quallenauge <Hamsi2k@freenet.de>
+*/
+
+
+import android.support.annotation.NonNull;
+
+import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
+import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
+
+/**
+ * Pseudo Coordinator for the EXRIZU K8, a sub type of the HPLUS devices
+ */
+public class EXRIZUK8Coordinator extends HPlusCoordinator {
+
+ @NonNull
+ @Override
+ public DeviceType getSupportedType(GBDeviceCandidate candidate) {
+ String name = candidate.getDevice().getName();
+ if(name != null && name.startsWith("iRun ")){
+ return DeviceType.EXRIZUK8;
+ }
+
+ return DeviceType.UNKNOWN;
+ }
+
+ @Override
+ public DeviceType getDeviceType() {
+ return DeviceType.EXRIZUK8;
+ }
+
+ @Override
+ public String getManufacturer() {
+ return "EXRIZU";
+ }
+
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/jyou/JYouConstants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/jyou/JYouConstants.java
index 1d87f181e..8476fba57 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/jyou/JYouConstants.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/jyou/JYouConstants.java
@@ -1,3 +1,19 @@
+/* Copyright (C) 2017 Sami Alaoui
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.devices.jyou;
import java.util.UUID;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/jyou/TeclastH30Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/jyou/TeclastH30Coordinator.java
index e170b64c2..993f425e6 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/jyou/TeclastH30Coordinator.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/jyou/TeclastH30Coordinator.java
@@ -1,3 +1,20 @@
+/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
+ Gobbetti, protomors, Sami Alaoui
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.devices.jyou;
import android.annotation.TargetApi;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java
index 6fc1ce244..3c4561c4f 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBand2Service.java
@@ -207,6 +207,8 @@ public class MiBand2Service {
public static final byte SUCCESS = 0x01;
public static final byte COMMAND_ACTIVITY_DATA_START_DATE = 0x01;
+ public static final byte COMMAND_ACTIVITY_DATA_TYPE_ACTIVTY = 0x01;
+ public static final byte COMMAND_ACTIVITY_DATA_TYPE_UNKNOWN_2 = 0x02;
public static final byte COMMAND_ACTIVITY_DATA_XXX_DATE = 0x02; // issued on first connect, followd by COMMAND_XXXX_ACTIVITY_DATA instead of COMMAND_FETCH_ACTIVITY_DATA
public static final byte COMMAND_FIRMWARE_INIT = 0x01; // to UUID_CHARACTERISTIC_FIRMWARE, followed by fw file size in bytes
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 bc0078d8a..077814665 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,5 +1,5 @@
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Christian
- Fischer, Daniele Gobbetti, José Rebelo, Szymon Tomasz Stefanek
+ Fischer, Daniele Gobbetti, José Rebelo, Michal Novotny, Szymon Tomasz Stefanek
This file is part of Gadgetbridge.
@@ -36,6 +36,7 @@ public final class MiBandConst {
public static final String PREF_MIBAND_BUTTON_ACTION_VIBRATE = "mi2_button_action_vibrate";
public static final String PREF_MIBAND_BUTTON_PRESS_COUNT = "mi_button_press_count";
public static final String PREF_MIBAND_BUTTON_PRESS_MAX_DELAY = "mi_button_press_count_max_delay";
+ public static final String PREF_MIBAND_BUTTON_ACTION_DELAY = "mi_button_press_count_match_delay";
public static final String PREF_MIBAND_BUTTON_PRESS_BROADCAST = "mi_button_press_broadcast";
public static final String PREF_MIBAND_USE_HR_FOR_SLEEP_DETECTION = "mi_hr_sleep_detection";
public static final String PREF_MIBAND_DEVICE_TIME_OFFSET_HOURS = "mi_device_time_offset_hours";
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/no1f1/No1F1Constants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/no1f1/No1F1Constants.java
index 651fdcb48..05049a2b5 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/no1f1/No1F1Constants.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/no1f1/No1F1Constants.java
@@ -1,3 +1,19 @@
+/* Copyright (C) 2017 protomors
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.devices.no1f1;
import java.util.UUID;
@@ -18,6 +34,8 @@ public final class No1F1Constants {
public static final byte CMD_REALTIME_STEPS = (byte) 0xb1;
public static final byte CMD_FETCH_STEPS = (byte) 0xb2;
public static final byte CMD_FETCH_SLEEP = (byte) 0xb3;
+ public static final byte CMD_REALTIME_HEARTRATE = (byte) 0xe5;
+ public static final byte CMD_FETCH_HEARTRATE = (byte) 0xe6;
public static final byte CMD_NOTIFICATION = (byte) 0xc1;
public static final byte CMD_ICON = (byte) 0xc3;
public static final byte CMD_DEVICE_SETTINGS = (byte) 0xd3;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/no1f1/No1F1Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/no1f1/No1F1Coordinator.java
index 4cd9dcb54..3ff03d642 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/no1f1/No1F1Coordinator.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/no1f1/No1F1Coordinator.java
@@ -1,3 +1,20 @@
+/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
+ Gobbetti, protomors
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.devices.no1f1;
import android.annotation.TargetApi;
@@ -108,7 +125,7 @@ public class No1F1Coordinator extends AbstractDeviceCoordinator {
@Override
public boolean supportsHeartRateMeasurement(GBDevice device) {
- return false;
+ return true;
}
@Override
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/no1f1/No1F1SampleProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/no1f1/No1F1SampleProvider.java
index e7a615fdb..2b7b1e5db 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/no1f1/No1F1SampleProvider.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/no1f1/No1F1SampleProvider.java
@@ -1,3 +1,19 @@
+/* Copyright (C) 2017 protomors
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.devices.no1f1;
import android.support.annotation.NonNull;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/AppNotificationType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/AppNotificationType.java
index 349fac0c0..7e0d7b805 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/AppNotificationType.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/AppNotificationType.java
@@ -1,4 +1,5 @@
-/* Copyright (C) 2016-2017 Andreas Shimokawa, Daniele Gobbetti, Kevin Richter
+/* Copyright (C) 2016-2017 Andreas Shimokawa, AnthonyDiGirolamo, Daniele
+ Gobbetti, Kevin Richter
This file is part of Gadgetbridge.
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java
index e55c1065d..eca9e1691 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java
@@ -1,5 +1,5 @@
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
- Gobbetti, João Paulo Barraca
+ Gobbetti, João Paulo Barraca, protomors, Quallenauge, Sami Alaoui
This file is part of Gadgetbridge.
@@ -37,6 +37,7 @@ public enum DeviceType {
LIVEVIEW(30, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled),
HPLUS(40, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled),
MAKIBESF68(41, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled),
+ EXRIZUK8(42, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled),
NO1F1(50, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled),
TECLASTH30(60, R.drawable.ic_device_h30_h10, R.drawable.ic_device_h30_h10_disabled),
TEST(1000, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled);
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationType.java
index 837dec1a9..228de8650 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationType.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationType.java
@@ -1,5 +1,5 @@
-/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Julien
- Pivotto, Kevin Richter
+/* Copyright (C) 2015-2017 Andreas Shimokawa, AnthonyDiGirolamo, Carsten
+ Pfeiffer, Julien Pivotto, Kevin Richter
This file is part of Gadgetbridge.
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java
index d085de772..07b1f3b1a 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java
@@ -1,5 +1,6 @@
/* Copyright (C) 2015-2017 0nse, Andreas Shimokawa, Carsten Pfeiffer,
- Daniele Gobbetti, João Paulo Barraca, Sergey Trofimov
+ Daniele Gobbetti, João Paulo Barraca, protomors, Quallenauge, Sami Alaoui,
+ Sergey Trofimov
This file is part of Gadgetbridge.
@@ -127,6 +128,9 @@ public class DeviceSupportFactory {
case MAKIBESF68:
deviceSupport = new ServiceDeviceSupport(new HPlusSupport(DeviceType.MAKIBESF68), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
break;
+ case EXRIZUK8:
+ deviceSupport = new ServiceDeviceSupport(new HPlusSupport(DeviceType.EXRIZUK8), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
+ break;
case NO1F1:
deviceSupport = new ServiceDeviceSupport(new No1F1Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
break;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/GattCallback.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/GattCallback.java
index da5fe2dd5..107af38da 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/GattCallback.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/GattCallback.java
@@ -1,19 +1,3 @@
-/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
-
- This file is part of Gadgetbridge.
-
- Gadgetbridge is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Gadgetbridge is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see . */
/*
* Copyright (C) 2013 The Android Open Source Project
*
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/deviceinfo/DeviceInfoProfile.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/deviceinfo/DeviceInfoProfile.java
index 587c8da71..92514d71a 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/deviceinfo/DeviceInfoProfile.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/deviceinfo/DeviceInfoProfile.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2017 Carsten Pfeiffer
+/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer
This file is part of Gadgetbridge.
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipFirmwareInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipFirmwareInfo.java
index c9dc6fa4d..aec1c2bee 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipFirmwareInfo.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipFirmwareInfo.java
@@ -45,9 +45,11 @@ public class AmazfitBipFirmwareInfo extends Mi2FirmwareInfo {
static {
// firmware
crcToVersion.put(25257, "0.0.8.74");
+ crcToVersion.put(57724, "0.0.8.88");
// resources
crcToVersion.put(12586, "RES 0.0.8.74");
+ crcToVersion.put(34068, "RES 0.0.8.88");
// gps
crcToVersion.put(61520, "GPS 9367,8f79a91,0,0,");
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipSupport.java
index 57fb1941e..af877879d 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipSupport.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/AmazfitBipSupport.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2017 Andreas Shimokawa
+/* Copyright (C) 2017 Andreas Shimokawa, Carsten Pfeiffer
This file is part of Gadgetbridge.
@@ -80,7 +80,7 @@ public class AmazfitBipSupport extends MiBand2Support {
try {
TransactionBuilder builder = performInitialized("new notification");
AlertNotificationProfile> profile = new AlertNotificationProfile(this);
- profile.setMaxLength(255); // TODO: find out real limit, certainly it is more than 18 which is default
+ profile.setMaxLength(230);
int customIconId = AmazfitBipIcon.mapToIconId(notificationSpec.type);
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/operations/AmazfitBipUpdateFirmwareOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/operations/AmazfitBipUpdateFirmwareOperation.java
index 48317d550..053c81097 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/operations/AmazfitBipUpdateFirmwareOperation.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/amazfitbip/operations/AmazfitBipUpdateFirmwareOperation.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2017 Andreas Shimokawa
+/* Copyright (C) 2017 Andreas Shimokawa, Carsten Pfeiffer
This file is part of Gadgetbridge.
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java
index dee5805a6..436efcf01 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/hplus/HPlusSupport.java
@@ -1,5 +1,5 @@
/* Copyright (C) 2016-2017 Alberto, Andreas Shimokawa, Carsten Pfeiffer,
- ivanovlev, João Paulo Barraca, Pavel Motyrev
+ ivanovlev, João Paulo Barraca, Pavel Motyrev, Quallenauge
This file is part of Gadgetbridge.
@@ -160,7 +160,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
private HPlusSupport syncPreferences(TransactionBuilder transaction) {
- if (deviceType == DeviceType.HPLUS) {
+ if (deviceType == DeviceType.HPLUS || deviceType == DeviceType.EXRIZUK8) {
setSIT(transaction); //Sync SIT Interval
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/jyou/TeclastH30Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/jyou/TeclastH30Support.java
index 8b1f09a84..f30d6bd5e 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/jyou/TeclastH30Support.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/jyou/TeclastH30Support.java
@@ -1,3 +1,19 @@
+/* Copyright (C) 2017 Sami Alaoui
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.service.devices.jyou;
import android.bluetooth.BluetoothGatt;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java
index d1ac3c331..e3c0d883a 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/MiBand2Support.java
@@ -1,6 +1,6 @@
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Christian
Fischer, Daniele Gobbetti, JohnnySun, José Rebelo, Julien Pivotto, Kasha,
- Sergey Trofimov, Steffen Liebergeld
+ Michal Novotny, Sergey Trofimov, Steffen Liebergeld
This file is part of Gadgetbridge.
@@ -24,9 +24,7 @@ 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.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager;
import android.text.format.DateFormat;
import android.widget.Toast;
@@ -42,6 +40,8 @@ import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@@ -126,8 +126,10 @@ import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ge
public class MiBand2Support extends AbstractBTLEDeviceSupport {
// We introduce key press counter for notification purposes
+ private static int currentButtonActionId = 0;
private static int currentButtonPressCount = 0;
private static long currentButtonPressTime = 0;
+ private static long currentButtonTimerActivationTime = 0;
private static final Logger LOG = LoggerFactory.getLogger(MiBand2Support.class);
private final DeviceInfoProfile deviceInfoProfile;
@@ -782,6 +784,80 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
// not supported
}
+ public void runButtonAction() {
+ Prefs prefs = GBApplication.getPrefs();
+
+ if (currentButtonTimerActivationTime != currentButtonPressTime) {
+ return;
+ }
+
+ String requiredButtonPressMessage = prefs.getString(MiBandConst.PREF_MIBAND_BUTTON_PRESS_BROADCAST,
+ this.getContext().getString(R.string.mi2_prefs_button_press_broadcast_default_value));
+
+ Intent in = new Intent();
+ in.setAction(requiredButtonPressMessage);
+ in.putExtra("button_id", currentButtonActionId);
+ LOG.info("Sending " + requiredButtonPressMessage + " with button_id " + currentButtonActionId);
+ this.getContext().getApplicationContext().sendBroadcast(in);
+ if (prefs.getBoolean(MiBandConst.PREF_MIBAND_BUTTON_ACTION_VIBRATE, false)) {
+ performPreferredNotification(null, null, null, MiBand2Service.ALERT_LEVEL_VIBRATE_ONLY, null);
+ }
+
+ currentButtonActionId = 0;
+
+ currentButtonPressCount = 0;
+ currentButtonPressTime = System.currentTimeMillis();
+ }
+
+ public void handleButtonPressed(byte[] value) {
+ LOG.info("Button pressed");
+ ///logMessageContent(value);
+
+ // If disabled we return from function immediately
+ Prefs prefs = GBApplication.getPrefs();
+ if (!prefs.getBoolean(MiBandConst.PREF_MIBAND_BUTTON_ACTION_ENABLE, false)) {
+ return;
+ }
+
+ int buttonPressMaxDelay = prefs.getInt(MiBandConst.PREF_MIBAND_BUTTON_PRESS_MAX_DELAY, 2000);
+ int buttonActionDelay = prefs.getInt(MiBandConst.PREF_MIBAND_BUTTON_ACTION_DELAY, 0);
+ int requiredButtonPressCount = prefs.getInt(MiBandConst.PREF_MIBAND_BUTTON_PRESS_COUNT, 0);
+
+ if (requiredButtonPressCount > 0) {
+ long timeSinceLastPress = System.currentTimeMillis() - currentButtonPressTime;
+
+ if ((currentButtonPressTime == 0) || (timeSinceLastPress < buttonPressMaxDelay)) {
+ currentButtonPressCount++;
+ }
+ else {
+ currentButtonPressCount = 1;
+ currentButtonActionId = 0;
+ }
+
+ currentButtonPressTime = System.currentTimeMillis();
+ if (currentButtonPressCount == requiredButtonPressCount) {
+ currentButtonTimerActivationTime = currentButtonPressTime;
+ if (buttonActionDelay > 0) {
+ LOG.info("Activating timer");
+ final Timer buttonActionTimer = new Timer("Mi Band Button Action Timer");
+ buttonActionTimer.scheduleAtFixedRate(new TimerTask() {
+ @Override
+ public void run() {
+ runButtonAction();
+ buttonActionTimer.cancel();
+ }
+ }, buttonActionDelay, buttonActionDelay);
+ }
+ else {
+ LOG.info("Activating button action");
+ runButtonAction();
+ }
+ currentButtonActionId++;
+ currentButtonPressCount = 0;
+ }
+ }
+ }
+
@Override
public boolean onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
@@ -811,54 +887,10 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
LOG.info("Unhandled characteristic changed: " + characteristicUUID);
logMessageContent(characteristic.getValue());
}
+
return false;
}
- public void handleButtonPressed(byte[] value) {
- SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this.getContext());
-
- LOG.info("Button pressed");
- logMessageContent(value);
-
- Prefs prefs = GBApplication.getPrefs();
-
- // If disabled we return from function immediately
- if (!prefs.getBoolean(MiBandConst.PREF_MIBAND_BUTTON_ACTION_ENABLE, false)) {
- return;
- }
-
- int buttonPressMaxDelay = prefs.getInt(MiBandConst.PREF_MIBAND_BUTTON_PRESS_MAX_DELAY, 2000);
- int requiredButtonPressCount = prefs.getInt(MiBandConst.PREF_MIBAND_BUTTON_PRESS_COUNT, 0);
-
- String requiredButtonPressMessage = prefs.getString(MiBandConst.PREF_MIBAND_BUTTON_PRESS_BROADCAST,
- this.getContext().getString(R.string.mi2_prefs_button_press_broadcast_default_value));
-
- if (requiredButtonPressCount > 0) {
- long timeSinceLastPress = System.currentTimeMillis() - currentButtonPressTime;
-
- if ((currentButtonPressTime == 0) || (timeSinceLastPress < buttonPressMaxDelay)) {
- currentButtonPressCount++;
- }
- else {
- currentButtonPressCount = 0;
- }
-
- currentButtonPressTime = System.currentTimeMillis();
- if (currentButtonPressCount >= requiredButtonPressCount) {
- Intent in = new Intent();
- in.setAction(requiredButtonPressMessage);
- this.getContext().getApplicationContext().sendBroadcast(in);
-
- currentButtonPressCount = 0;
- currentButtonPressTime = System.currentTimeMillis();
-
- if (prefs.getBoolean(MiBandConst.PREF_MIBAND_BUTTON_ACTION_VIBRATE, false)) {
- performPreferredNotification(null, null, null, MiBand2Service.ALERT_LEVEL_VIBRATE_ONLY, null);
- }
- }
- }
- }
-
private void handleUnknownCharacteristic(byte[] value) {
}
@@ -888,6 +920,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
LOG.info("Unhandled characteristic read: " + characteristicUUID);
logMessageContent(characteristic.getValue());
}
+
return false;
}
@@ -1063,6 +1096,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
// getContext().getString(R.string.DEVINFO_HR_VER),
// info.getSoftwareRevision()));
// }
+
LOG.warn("Device info: " + info);
versionCmd.hwVersion = info.getHardwareRevision();
// versionCmd.fwVersion = info.getFirmwareRevision(); // always null
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/operations/AbstractFetchOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/operations/AbstractFetchOperation.java
new file mode 100644
index 000000000..2c95d72f3
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/operations/AbstractFetchOperation.java
@@ -0,0 +1,193 @@
+/* Copyright (C) 2017 Carsten Pfeiffer
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations;
+
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.content.SharedPreferences;
+import android.support.annotation.CallSuper;
+import android.support.annotation.NonNull;
+import android.widget.Toast;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.UUID;
+
+import nodomain.freeyourgadget.gadgetbridge.GBApplication;
+import nodomain.freeyourgadget.gadgetbridge.Logging;
+import nodomain.freeyourgadget.gadgetbridge.R;
+import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Service;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceBusyAction;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.AbstractMiBand2Operation;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.MiBand2Support;
+import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils;
+import nodomain.freeyourgadget.gadgetbridge.util.GB;
+
+/**
+ * An operation that fetches activity data. For every fetch, a new operation must
+ * be created, i.e. an operation may not be reused for multiple fetches.
+ */
+public abstract class AbstractFetchOperation extends AbstractMiBand2Operation {
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractFetchOperation.class);
+
+ protected byte lastPacketCounter;
+ protected int fetchCount;
+ protected BluetoothGattCharacteristic characteristicActivityData;
+ protected BluetoothGattCharacteristic characteristicFetch;
+ protected Calendar startTimestamp;
+
+ public AbstractFetchOperation(MiBand2Support support) {
+ super(support);
+ }
+
+ @Override
+ protected void enableNeededNotifications(TransactionBuilder builder, boolean enable) {
+ if (!enable) {
+ // dynamically enabled, but always disabled on finish
+ builder.notify(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_5_ACTIVITY_DATA), enable);
+ }
+ }
+
+ @Override
+ protected void doPerform() throws IOException {
+ startFetching();
+ }
+
+ protected void startFetching() throws IOException {
+ lastPacketCounter = -1;
+
+ TransactionBuilder builder = performInitialized("fetching activity data");
+ getSupport().setLowLatency(builder);
+ if (fetchCount == 0) {
+ builder.add(new SetDeviceBusyAction(getDevice(), getContext().getString(R.string.busy_task_fetch_activity_data), getContext()));
+ }
+ fetchCount++;
+
+ characteristicActivityData = getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_5_ACTIVITY_DATA);
+ builder.notify(characteristicActivityData, false);
+
+ characteristicFetch = getCharacteristic(MiBand2Service.UUID_UNKNOWN_CHARACTERISTIC4);
+ builder.notify(characteristicFetch, true);
+
+ startFetching(builder);
+ builder.queue(getQueue());
+ }
+
+ protected abstract void startFetching(TransactionBuilder builder);
+
+ protected abstract String getLastSyncTimeKey();
+
+ @Override
+ public boolean onCharacteristicChanged(BluetoothGatt gatt,
+ BluetoothGattCharacteristic characteristic) {
+ UUID characteristicUUID = characteristic.getUuid();
+ if (MiBand2Service.UUID_CHARACTERISTIC_5_ACTIVITY_DATA.equals(characteristicUUID)) {
+ handleActivityNotif(characteristic.getValue());
+ return true;
+ } else if (MiBand2Service.UUID_UNKNOWN_CHARACTERISTIC4.equals(characteristicUUID)) {
+ handleActivityMetadata(characteristic.getValue());
+ return true;
+ } else {
+ return super.onCharacteristicChanged(gatt, characteristic);
+ }
+ }
+
+ @CallSuper
+ protected void handleActivityFetchFinish() {
+ operationFinished();
+ unsetBusy();
+ }
+
+ /**
+ * Method to handle the incoming activity data.
+ * There are two kind of messages we currently know:
+ * - the first one is 11 bytes long and contains metadata (how many bytes to expect, when the data starts, etc.)
+ * - the second one is 20 bytes long and contains the actual activity data
+ *
+ * The first message type is parsed by this method, for every other length of the value param, bufferActivityData is called.
+ *
+ * @param value
+ */
+ protected abstract void handleActivityNotif(byte[] value);
+
+ /**
+ * Creates samples from the given 17-length array
+ * @param value
+ */
+ protected abstract void bufferActivityData(byte[] value);
+
+ protected void handleActivityMetadata(byte[] value) {
+ if (value.length == 15) {
+ // first two bytes are whether our request was accepted
+ if (ArrayUtils.equals(value, MiBand2Service.RESPONSE_ACTIVITY_DATA_START_DATE_SUCCESS, 0)) {
+ // the third byte (0x01 on success) = ?
+ // the 4th - 7th bytes probably somehow represent the number of bytes/packets to expect
+
+ // last 8 bytes are the start date
+ Calendar startTimestamp = getSupport().fromTimeBytes(org.apache.commons.lang3.ArrayUtils.subarray(value, 7, value.length));
+ setStartTimestamp(startTimestamp);
+
+ GB.toast(getContext().getString(R.string.FetchActivityOperation_about_to_transfer_since,
+ DateFormat.getDateTimeInstance().format(startTimestamp.getTime())), Toast.LENGTH_LONG, GB.INFO);
+ } else {
+ LOG.warn("Unexpected activity metadata: " + Logging.formatBytes(value));
+ handleActivityFetchFinish();
+ }
+ } else if (value.length == 3) {
+ if (Arrays.equals(MiBand2Service.RESPONSE_FINISH_SUCCESS, value)) {
+ handleActivityFetchFinish();
+ } else {
+ LOG.warn("Unexpected activity metadata: " + Logging.formatBytes(value));
+ handleActivityFetchFinish();
+ }
+ } else {
+ LOG.warn("Unexpected activity metadata: " + Logging.formatBytes(value));
+ handleActivityFetchFinish();
+ }
+ }
+
+ protected void setStartTimestamp(Calendar startTimestamp) {
+ this.startTimestamp = startTimestamp;
+ }
+
+ protected void saveLastSyncTimestamp(@NonNull GregorianCalendar timestamp) {
+ SharedPreferences.Editor editor = GBApplication.getPrefs().getPreferences().edit();
+ editor.putLong(getLastSyncTimeKey(), timestamp.getTimeInMillis());
+ editor.apply();
+ }
+
+
+ protected GregorianCalendar getLastSuccessfulSyncTime() {
+ long timeStampMillis = GBApplication.getPrefs().getLong(getLastSyncTimeKey(), 0);
+ if (timeStampMillis != 0) {
+ GregorianCalendar calendar = BLETypeConversions.createCalendar();
+ calendar.setTimeInMillis(timeStampMillis);
+ return calendar;
+ }
+ GregorianCalendar calendar = BLETypeConversions.createCalendar();
+ calendar.add(Calendar.DAY_OF_MONTH, -10);
+ return calendar;
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/operations/FetchActivityOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/operations/FetchActivityOperation.java
index 927af487f..36999acec 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/operations/FetchActivityOperation.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband2/operations/FetchActivityOperation.java
@@ -16,11 +16,6 @@
along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations;
-import android.bluetooth.BluetoothGatt;
-import android.bluetooth.BluetoothGattCharacteristic;
-import android.content.SharedPreferences;
-import android.support.annotation.NonNull;
-import android.support.v4.util.TimeUtils;
import android.text.format.DateUtils;
import android.widget.Toast;
@@ -28,18 +23,13 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
-import java.text.DateFormat;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
-import java.util.UUID;
import java.util.concurrent.TimeUnit;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
-import nodomain.freeyourgadget.gadgetbridge.Logging;
-import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
@@ -51,11 +41,8 @@ import nodomain.freeyourgadget.gadgetbridge.entities.MiBandActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.User;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
-import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceBusyAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.WaitAction;
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.MiBand2Support;
-import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.AbstractMiBand2Operation;
-import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils;
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
@@ -63,95 +50,31 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
* An operation that fetches activity data. For every fetch, a new operation must
* be created, i.e. an operation may not be reused for multiple fetches.
*/
-public class FetchActivityOperation extends AbstractMiBand2Operation {
+public class FetchActivityOperation extends AbstractFetchOperation {
private static final Logger LOG = LoggerFactory.getLogger(FetchActivityOperation.class);
private List samples = new ArrayList<>(60*24); // 1day per default
- private byte lastPacketCounter;
- private Calendar startTimestamp;
- private int fetchCount;
-
public FetchActivityOperation(MiBand2Support support) {
super(support);
}
@Override
- protected void enableNeededNotifications(TransactionBuilder builder, boolean enable) {
- if (!enable) {
- // dynamically enabled, but always disabled on finish
- builder.notify(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_5_ACTIVITY_DATA), enable);
- }
+ protected void startFetching() throws IOException {
+ samples.clear();
+ super.startFetching();
}
@Override
- protected void doPerform() throws IOException {
- startFetching();
- }
-
- private void startFetching() throws IOException {
- samples.clear();
- lastPacketCounter = -1;
-
- TransactionBuilder builder = performInitialized("fetching activity data");
- getSupport().setLowLatency(builder);
- if (fetchCount == 0) {
- builder.add(new SetDeviceBusyAction(getDevice(), getContext().getString(R.string.busy_task_fetch_activity_data), getContext()));
- }
- fetchCount++;
-
- BluetoothGattCharacteristic characteristicActivityData = getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_5_ACTIVITY_DATA);
- builder.notify(characteristicActivityData, false);
-
- BluetoothGattCharacteristic characteristicFetch = getCharacteristic(MiBand2Service.UUID_UNKNOWN_CHARACTERISTIC4);
- builder.notify(characteristicFetch, true);
-
+ protected void startFetching(TransactionBuilder builder) {
GregorianCalendar sinceWhen = getLastSuccessfulSyncTime();
- builder.write(characteristicFetch, BLETypeConversions.join(new byte[] { MiBand2Service.COMMAND_ACTIVITY_DATA_START_DATE, 0x01 }, getSupport().getTimeBytes(sinceWhen, TimeUnit.MINUTES)));
+ builder.write(characteristicFetch, BLETypeConversions.join(new byte[] { MiBand2Service.COMMAND_ACTIVITY_DATA_START_DATE, MiBand2Service.COMMAND_ACTIVITY_DATA_TYPE_ACTIVTY }, getSupport().getTimeBytes(sinceWhen, TimeUnit.MINUTES)));
builder.add(new WaitAction(1000)); // TODO: actually wait for the success-reply
builder.notify(characteristicActivityData, true);
builder.write(characteristicFetch, new byte[] { MiBand2Service.COMMAND_FETCH_ACTIVITY_DATA });
- builder.queue(getQueue());
}
- private GregorianCalendar getLastSuccessfulSyncTime() {
- long timeStampMillis = GBApplication.getPrefs().getLong(getLastSyncTimeKey(), 0);
- if (timeStampMillis != 0) {
- GregorianCalendar calendar = BLETypeConversions.createCalendar();
- calendar.setTimeInMillis(timeStampMillis);
- return calendar;
- }
- GregorianCalendar calendar = BLETypeConversions.createCalendar();
- calendar.add(Calendar.DAY_OF_MONTH, -10);
- return calendar;
- }
-
- private void saveLastSyncTimestamp(@NonNull GregorianCalendar timestamp) {
- SharedPreferences.Editor editor = GBApplication.getPrefs().getPreferences().edit();
- editor.putLong(getLastSyncTimeKey(), timestamp.getTimeInMillis());
- editor.apply();
- }
-
- private String getLastSyncTimeKey() {
- return getDevice().getAddress() + "_" + "lastSyncTimeMillis";
- }
-
- @Override
- public boolean onCharacteristicChanged(BluetoothGatt gatt,
- BluetoothGattCharacteristic characteristic) {
- UUID characteristicUUID = characteristic.getUuid();
- if (MiBand2Service.UUID_CHARACTERISTIC_5_ACTIVITY_DATA.equals(characteristicUUID)) {
- handleActivityNotif(characteristic.getValue());
- return true;
- } else if (MiBand2Service.UUID_UNKNOWN_CHARACTERISTIC4.equals(characteristicUUID)) {
- handleActivityMetadata(characteristic.getValue());
- return true;
- } else {
- return super.onCharacteristicChanged(gatt, characteristic);
- }
- }
-
- private void handleActivityFetchFinish() {
+ protected void handleActivityFetchFinish() {
LOG.info("Fetching activity data has finished round " + fetchCount);
GregorianCalendar lastSyncTimestamp = saveSamples();
if (lastSyncTimestamp != null && needsAnotherFetch(lastSyncTimestamp)) {
@@ -163,8 +86,7 @@ public class FetchActivityOperation extends AbstractMiBand2Operation {
}
}
- operationFinished();
- unsetBusy();
+ super.handleActivityFetchFinish();
}
private boolean needsAnotherFetch(GregorianCalendar lastSyncTimestamp) {
@@ -232,7 +154,7 @@ public class FetchActivityOperation extends AbstractMiBand2Operation {
*
* @param value
*/
- private void handleActivityNotif(byte[] value) {
+ protected void handleActivityNotif(byte[] value) {
if (!isOperationRunning()) {
LOG.error("ignoring activity data notification because operation is not running. Data length: " + value.length);
getSupport().logMessageContent(value);
@@ -257,7 +179,7 @@ public class FetchActivityOperation extends AbstractMiBand2Operation {
* Creates samples from the given 17-length array
* @param value
*/
- private void bufferActivityData(byte[] value) {
+ protected void bufferActivityData(byte[] value) {
int len = value.length;
if (len % 4 != 1) {
@@ -280,34 +202,8 @@ public class FetchActivityOperation extends AbstractMiBand2Operation {
return sample;
}
- private void handleActivityMetadata(byte[] value) {
- if (value.length == 15) {
- // first two bytes are whether our request was accepted
- if (ArrayUtils.equals(value, MiBand2Service.RESPONSE_ACTIVITY_DATA_START_DATE_SUCCESS, 0)) {
- // the third byte (0x01 on success) = ?
- // the 4th - 7th bytes probably somehow represent the number of bytes/packets to expect
-
- // last 8 bytes are the start date
- Calendar startTimestamp = getSupport().fromTimeBytes(org.apache.commons.lang3.ArrayUtils.subarray(value, 7, value.length));
- setStartTimestamp(startTimestamp);
-
- GB.toast(getContext().getString(R.string.FetchActivityOperation_about_to_transfer_since,
- DateFormat.getDateTimeInstance().format(startTimestamp.getTime())), Toast.LENGTH_LONG, GB.INFO);
- } else {
- LOG.warn("Unexpected activity metadata: " + Logging.formatBytes(value));
- handleActivityFetchFinish();
- }
- } else if (value.length == 3) {
- if (Arrays.equals(MiBand2Service.RESPONSE_FINISH_SUCCESS, value)) {
- handleActivityFetchFinish();
- } else {
- LOG.warn("Unexpected activity metadata: " + Logging.formatBytes(value));
- handleActivityFetchFinish();
- }
- }
- }
-
- private void setStartTimestamp(Calendar startTimestamp) {
- this.startTimestamp = startTimestamp;
+ @Override
+ protected String getLastSyncTimeKey() {
+ return getDevice().getAddress() + "_" + "lastSyncTimeMillis";
}
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/no1f1/No1F1Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/no1f1/No1F1Support.java
index 85c99041c..54a40c4e5 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/no1f1/No1F1Support.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/no1f1/No1F1Support.java
@@ -1,3 +1,19 @@
+/* Copyright (C) 2017 protomors
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.service.devices.no1f1;
import android.bluetooth.BluetoothGatt;
@@ -114,6 +130,15 @@ public class No1F1Support extends AbstractBTLEDeviceSupport {
case No1F1Constants.CMD_FETCH_STEPS:
handleStepData(data);
return true;
+ case No1F1Constants.CMD_FETCH_SLEEP:
+ handleSleepData(data);
+ return true;
+ case No1F1Constants.CMD_FETCH_HEARTRATE:
+ handleHeartRateData(data);
+ return true;
+ case No1F1Constants.CMD_REALTIME_HEARTRATE:
+ handleRealtimeHeartRateData(data);
+ return true;
case No1F1Constants.CMD_NOTIFICATION:
case No1F1Constants.CMD_ICON:
case No1F1Constants.CMD_DEVICE_SETTINGS:
@@ -237,7 +262,17 @@ public class No1F1Support extends AbstractBTLEDeviceSupport {
@Override
public void onHeartRateTest() {
-
+ try {
+ TransactionBuilder builder = performInitialized("heartRateTest");
+ byte[] msg = new byte[]{
+ No1F1Constants.CMD_REALTIME_HEARTRATE,
+ (byte) 0x11
+ };
+ builder.write(ctrlCharacteristic, msg);
+ performConnected(builder.getTransaction());
+ } catch (IOException e) {
+ GB.toast(getContext(), "Error starting heart rate measurement: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
+ }
}
@Override
@@ -470,10 +505,18 @@ public class No1F1Support extends AbstractBTLEDeviceSupport {
}
samples.clear();
LOG.info("Steps data saved");
- if (getDevice().isBusy()) {
- getDevice().unsetBusyTask();
- getDevice().sendDeviceUpdateIntent(getContext());
+ try {
+ TransactionBuilder builder = performInitialized("fetchSleep");
+ byte[] msg = new byte[]{
+ No1F1Constants.CMD_FETCH_SLEEP,
+ (byte) 0xfa
+ };
+ builder.write(ctrlCharacteristic, msg);
+ performConnected(builder.getTransaction());
+ } catch (IOException e) {
+ GB.toast(getContext(), "Error fetching activity data: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
}
+
} catch (Exception ex) {
GB.toast(getContext(), "Error saving step data: " + ex.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
}
@@ -498,4 +541,132 @@ public class No1F1Support extends AbstractBTLEDeviceSupport {
);
}
}
+
+ private void handleSleepData(byte[] data) {
+ if (data[1] == (byte) 0xfd) {
+ // TODO Check CRC
+ if (samples.size() > 0) {
+ try (DBHandler dbHandler = GBApplication.acquireDB()) {
+ Long userId = DBHelper.getUser(dbHandler.getDaoSession()).getId();
+ Long deviceId = DBHelper.getDevice(getDevice(), dbHandler.getDaoSession()).getId();
+ No1F1SampleProvider provider = new No1F1SampleProvider(getDevice(), dbHandler.getDaoSession());
+ for (int i = 0; i < samples.size(); i++) {
+ samples.get(i).setDeviceId(deviceId);
+ samples.get(i).setUserId(userId);
+ if (samples.get(i).getRawIntensity()<7)
+ samples.get(i).setRawKind(ActivityKind.TYPE_DEEP_SLEEP);
+ else
+ samples.get(i).setRawKind(ActivityKind.TYPE_LIGHT_SLEEP);
+ provider.addGBActivitySample(samples.get(i));
+ }
+ samples.clear();
+ LOG.info("Sleep data saved");
+ try {
+ TransactionBuilder builder = performInitialized("fetchHeartRate");
+ byte[] msg = new byte[]{
+ No1F1Constants.CMD_FETCH_HEARTRATE,
+ (byte) 0xfa
+ };
+ builder.write(ctrlCharacteristic, msg);
+ performConnected(builder.getTransaction());
+ } catch (IOException e) {
+ GB.toast(getContext(), "Error fetching heart rate data: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
+ }
+
+ } catch (Exception ex) {
+ GB.toast(getContext(), "Error saving sleep data: " + ex.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
+ }
+ }
+ } else {
+ No1F1ActivitySample sample = new No1F1ActivitySample();
+
+ Calendar timestamp = GregorianCalendar.getInstance();
+ timestamp.set(Calendar.YEAR, data[1] * 256 + (data[2] & 0xff));
+ timestamp.set(Calendar.MONTH, (data[3] - 1) & 0xff);
+ timestamp.set(Calendar.DAY_OF_MONTH, data[4] & 0xff);
+ timestamp.set(Calendar.HOUR_OF_DAY, data[5] & 0xff);
+ timestamp.set(Calendar.MINUTE, data[6] & 0xff);
+ timestamp.set(Calendar.SECOND, 0);
+
+ sample.setTimestamp((int) (timestamp.getTimeInMillis() / 1000L));
+ sample.setRawIntensity(data[7] * 256 + (data[8] & 0xff));
+
+ samples.add(sample);
+ LOG.info("Received sleep data for " + String.format("%1$TD %1$TT", timestamp) + ": " +
+ sample.getRawIntensity() + " rolls"
+ );
+ }
+ }
+
+ private void handleHeartRateData(byte[] data) {
+ if (data[1] == (byte) 0xfd) {
+ // TODO Check CRC
+ if (samples.size() > 0) {
+ try (DBHandler dbHandler = GBApplication.acquireDB()) {
+ Long userId = DBHelper.getUser(dbHandler.getDaoSession()).getId();
+ Long deviceId = DBHelper.getDevice(getDevice(), dbHandler.getDaoSession()).getId();
+ No1F1SampleProvider provider = new No1F1SampleProvider(getDevice(), dbHandler.getDaoSession());
+ for (int i = 0; i < samples.size(); i++) {
+ samples.get(i).setDeviceId(deviceId);
+ samples.get(i).setUserId(userId);
+ provider.addGBActivitySample(samples.get(i));
+ }
+ samples.clear();
+ LOG.info("Heart rate data saved");
+ if (getDevice().isBusy()) {
+ getDevice().unsetBusyTask();
+ getDevice().sendDeviceUpdateIntent(getContext());
+ }
+ } catch (Exception ex) {
+ GB.toast(getContext(), "Error saving heart rate data: " + ex.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
+ }
+ }
+ } else {
+ No1F1ActivitySample sample = new No1F1ActivitySample();
+
+ Calendar timestamp = GregorianCalendar.getInstance();
+ timestamp.set(Calendar.YEAR, data[1] * 256 + (data[2] & 0xff));
+ timestamp.set(Calendar.MONTH, (data[3] - 1) & 0xff);
+ timestamp.set(Calendar.DAY_OF_MONTH, data[4] & 0xff);
+ timestamp.set(Calendar.HOUR_OF_DAY, data[5] & 0xff);
+ timestamp.set(Calendar.MINUTE, data[6] & 0xff);
+ timestamp.set(Calendar.SECOND, 0);
+
+ sample.setTimestamp((int) (timestamp.getTimeInMillis() / 1000L));
+ sample.setHeartRate(data[7] & 0xff);
+
+ samples.add(sample);
+ LOG.info("Received heart rate data for " + String.format("%1$TD %1$TT", timestamp) + ": " +
+ sample.getHeartRate() + " BPM"
+ );
+ }
+ }
+
+ private void handleRealtimeHeartRateData(byte[] data) {
+ if (data.length==2)
+ {
+ if (data[1]==(byte) 0x11)
+ LOG.info("Heart rate measurement started.");
+ else
+ LOG.info("Heart rate measurement stopped.");
+ return;
+ }
+ // Check if data is valid. Otherwise ignore sample.
+ if (data[2]==0) {
+ No1F1ActivitySample sample = new No1F1ActivitySample();
+ sample.setTimestamp((int) (GregorianCalendar.getInstance().getTimeInMillis() / 1000L));
+ sample.setHeartRate(data[3] & 0xff);
+ LOG.info("Current heart rate is: " + sample.getHeartRate() + " BPM");
+ try (DBHandler dbHandler = GBApplication.acquireDB()) {
+ Long userId = DBHelper.getUser(dbHandler.getDaoSession()).getId();
+ Long deviceId = DBHelper.getDevice(getDevice(), dbHandler.getDaoSession()).getId();
+ No1F1SampleProvider provider = new No1F1SampleProvider(getDevice(), dbHandler.getDaoSession());
+ sample.setDeviceId(deviceId);
+ sample.setUserId(userId);
+ provider.addGBActivitySample(sample);
+ } catch (Exception ex) {
+ LOG.warn("Error saving current heart rate: " + ex.getLocalizedMessage());
+ }
+ }
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java
index ff0eb40d5..cc9cc995c 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java
@@ -36,6 +36,8 @@ import java.util.Random;
import java.util.SimpleTimeZone;
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;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagement;
@@ -591,9 +593,9 @@ public class PebbleProtocol extends GBDeviceProtocol {
byte actions_count;
short actions_length;
String dismiss_string;
- String open_string = "Open on phone";
- String mute_string = "Mute";
- String reply_string = "Reply";
+ String open_string = GBApplication.getContext().getString(R.string._pebble_watch_open_on_phone);
+ String mute_string = GBApplication.getContext().getString(R.string._pebble_watch_mute);
+ String reply_string = GBApplication.getContext().getString(R.string._pebble_watch_reply);
if (sourceName != null) {
mute_string += " " + sourceName;
}
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 379475ca6..e008a590e 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
@@ -1,5 +1,5 @@
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer, Daniele
- Gobbetti
+ Gobbetti, Gabe Schrecker
This file is part of Gadgetbridge.
@@ -18,17 +18,23 @@
package nodomain.freeyourgadget.gadgetbridge.service.receivers;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
+import android.media.session.MediaController;
+import android.media.session.MediaSessionManager;
import android.os.SystemClock;
import android.view.KeyEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.List;
+
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
+import nodomain.freeyourgadget.gadgetbridge.externalevents.NotificationListener;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class GBMusicControlReceiver extends BroadcastReceiver {
@@ -73,6 +79,22 @@ public class GBMusicControlReceiver extends BroadcastReceiver {
Prefs prefs = GBApplication.getPrefs();
String audioPlayer = prefs.getString("audio_player", "default");
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
+ MediaSessionManager mediaSessionManager =
+ (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
+
+ List controllers = mediaSessionManager.getActiveSessions(
+ new ComponentName(context, NotificationListener.class));
+ try {
+ MediaController controller = controllers.get(0);
+ audioPlayer = controller.getPackageName();
+ } catch (IndexOutOfBoundsException e) {
+ System.err.println("IndexOutOfBoundsException: " + e.getMessage());
+ }
+ }
+
+ LOG.debug("keypress: " + musicCmd.toString() + " sent to: " + audioPlayer);
+
long eventtime = SystemClock.uptimeMillis();
Intent downIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/AndroidUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/AndroidUtils.java
index 06bafd277..5b9f83671 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/AndroidUtils.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/AndroidUtils.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2017 Carsten Pfeiffer
+/* Copyright (C) 2016-2017 Andreas Shimokawa, Carsten Pfeiffer
This file is part of Gadgetbridge.
@@ -70,14 +70,6 @@ public class AndroidUtils {
}
}
- public static void setLanguage(Activity activity, Locale language, boolean recreate) {
- setLanguage(activity.getBaseContext(), language);
-
- if (recreate) {
- activity.recreate();
- }
- }
-
public static void setLanguage(Context context, Locale language) {
Configuration config = new Configuration();
config.setLocale(language);
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 ab5f8c812..4f1201cc3 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java
@@ -1,5 +1,5 @@
/* Copyright (C) 2015-2017 0nse, Andreas Shimokawa, Carsten Pfeiffer,
- Daniele Gobbetti, João Paulo Barraca
+ Daniele Gobbetti, João Paulo Barraca, protomors, Quallenauge, Sami Alaoui
This file is part of Gadgetbridge.
@@ -40,6 +40,7 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.UnknownDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.amazfitbip.AmazfitBipCooordinator;
+import nodomain.freeyourgadget.gadgetbridge.devices.hplus.EXRIZUK8Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.hplus.MakibesF68Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.jyou.TeclastH30Coordinator;
@@ -196,6 +197,7 @@ public class DeviceHelper {
result.add(new HPlusCoordinator());
result.add(new No1F1Coordinator());
result.add(new MakibesF68Coordinator());
+ result.add(new EXRIZUK8Coordinator());
result.add(new TeclastH30Coordinator());
return result;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/Version.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/Version.java
index 82a397f78..855241cf2 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/Version.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/Version.java
@@ -1,4 +1,4 @@
-/* Copyright (C) 2017 Carsten Pfeiffer
+/* Copyright (C) 2017 Andreas Shimokawa, Carsten Pfeiffer, Michal Novotny
This file is part of Gadgetbridge.
@@ -68,4 +68,4 @@ public class Version implements Comparable {
public int hashCode() {
return version.hashCode();
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 4d92f1c78..793f73286 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -413,13 +413,14 @@
Definujte počet stisknutí tlačítka k vyslání broadcast zprávy
Zpráva k vyslání (broadcast)
Zpráva k vyslání do systému pokud počtu stisknutí tlačítka (viz výše)
- nodomain.freeyourgadget.gadgetbridge.mibandButtonPressed
Povolit akci tlačítka
Povolit akci tlačítka na definovaný počet stisknutí
Povolit vibrace náramku
Povolit vibrace náramku při vyslání broadcast zprávy
Maximální prodleva mezi stisky
Maximální prodleva mezi stisky tlačítka v milisekundách
+ Prodleva před akcí
+ Prodleva před akcí tlačítka. Umožňuje více průchodů (v extra button_id u Intent) nebo 0 pro okamžitou akci
Chystáte se nainstalovat firmware %s namísto toho, který je aktuálně na vašem Amazfit Bipu.
\n
\nUjistěte se, že jste nainstalovali firmware .gps, pak soubor .res a nakonec soubor .fw. Hodiny se po instalaci souboru .fw restartují.
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index e4eafd3b6..d1b775493 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -289,7 +289,7 @@
Aktivitätsdaten verbleiben auf dem Mi Band, auch nach der Synchronisierung. Hilfreich, wenn das Mi Band mit weiteren Apps verwendet wird.
Benutze Modus mit niedriger Latenz für Firmware-Updates
Dies kann bei Geräten helfen, bei denen Firmwareupdates fehlschlagen
- Verlauf Schritte
+ Schritteverlauf
Akt. Schritte pro Minute
Schritte insgesamt
Verlauf Schritte pro Minute
@@ -385,7 +385,7 @@
Wecker
(%1$s)
Gefunden!
- Mi2: Uhrzeit-Format
+ Mi2: Uhrzeitformat
Installiere Version %1$s vor dem Installieren der Firmware!
Text Benachrichtigung
= 1.0.1.28 und installiertes Mili_pro.ft* benötigt.]]>
@@ -410,4 +410,19 @@
\nHinweis: Du musst die .res and .gps Dateien nicht installieren, falls diese genau die gleichen Dateien wie die sind, die Du schon mit einer vorigen .fw Datei zusammen installiert hattest.
\n
\nDIES IST EXPERIMENTELL, FAHRE AUF EIGENES RISIKO FORT
-
+ Amazfit Bip Firmware %1$s
+ Aktion bei Tastendruck
+ Bestimmte Aktion bei Tastendruck auf dem Mi Band 2
+ Anzahl der Tastendrücke, die einen Broadcast auslöst
+ Zu Sendende Broadcast-Nachricht
+ Aktiviere Tastenaktion
+ Aktiviere Aktion bei einer bestimmten Anzahl an Tastendrücken
+ Aktiviere Vibration
+ Vibriere, wenn die Tastenaktion ausgelöst wurde
+ Maximale Verzögerung zwischen den Tastendrücken
+ Maximale Verzögerung zwischen den Tastendrücken in Millisekunden
+ Verzögerung nach Tastenaktion
+ Auf dem Smartphone öffnen
+ Stummschalten
+ Antwort
+
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index ae1a4b1ee..68fd3c432 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -411,4 +411,22 @@
\n
\nEXPERIMENTAL, PROCEDE BAJO TU PROPIA RESPONSABILIDAD
Firmware Amazfit Bip %1$s
-
+ Acciones del botón
+ Especificar acción para pulsación del botón del Mi Band 2
+ Número de presiones
+ Número de presiones para activar el envío del mensaje
+ Mensaje para enviar
+ Enviar mensaje después de un número definido de pulsaciones
+ nodomain.freeyourgadget.gadgetbridge.mibandButtonPressed
+ Activar acción por botón
+ Activar acción por un número definido de pulsaciones
+ Activar la vibración de la pulsera
+ Activar vibración por acción
+ Retardo máximo entre pulsaciones
+ Retardo máximo entre pulsaciones en milisegundos
+ Retardo después de la acción del botón
+ Retardo después de una acción del botón (el número está en button_id intent extra) o bien 0 para efecto inmediato
+ Abrir en el teléfono
+ Silenciar
+ Responder
+
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 19e87a46e..cf284f61d 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -415,4 +415,22 @@ NOTE: la base de données sera bien évidement plus grande !
\n
\nEXPÉRIMENTAL, CONTINUEZ À VOS RISQUES
Firmware Amazfit Bip %1$s
-
+ Actions du bouton
+ Spécifier les actions par pression du bouton du Mi Band 2
+ Nombre de pressions du bouton
+ Nombre de pressions pour envoyer message
+ Message à envoyer
+ Envoyer message après nombre défini de pressions du bouton
+ nodomain.freeyourgadget.gadgetbridge.mibandButtonPressed
+ Activer action du bouton
+ Activer action après nombre spécifié de pressions
+ Activer la vibration du bracelet
+ Activer la vibration après déclenchement de l\'action
+ Délai maximum entre pressions
+ Délai maximum entre pressions en millisecondes
+ Délai après action du bouton
+ Délai après une pression de bouton (le nombre est dans button_id intent extra) ou 0 pour immédiatement
+ Ouvrir sur le téléphone
+ Silencieux
+ Répondre
+
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 281652d35..2b1cf3d2b 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -409,4 +409,17 @@
\n
\n実験的です。あなた自身の責任で行ってください
Amazfit Bip ファームウェア%1$s
+ ボタンの動作
+ Mi Band 2 ボタンを押した動作を指定します
+ ボタン押したカウント
+ ブロードキャスト メッセージをトリガーするボタンを押した数
+ 送信するブロードキャスト メッセージ
+ ボタンを押した数で定義された数に達したブロードキャスト メッセージ
+ nodomain.freeyourgadget.gadgetbridge.mibandButtonPressed
+ ボタンの動作を有効にする
+ 指定したボタンを押した数の動作を有効にします
+ band の振動を有効にする
+ ボタンの動作をトリガーに band の振動を有効にします
+ ボタンを押す間の最大遅延時間
+ ボタンを押す間隔の最大遅延時間 (ミリ秒単位)
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index 5256737b7..7e92403a0 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -7,7 +7,7 @@
종료
동기화
수면 측정계 (초기 버전)
- 잃어버린 기기 찾기...
+ 잃어버린 기기 찾기
스크린샷 찍기
연결 해제
디버그
@@ -46,7 +46,7 @@
SMS
Pebble 메세지
일반적인 알림 지원
- … 화면이 켜져있을 때도
+ …화면이 켜져있을 때도
항상
화면이 꺼져 있을 때
하지 않음
@@ -56,7 +56,7 @@
Mi Band 주소
Pebble 설정
선호하는 액티비티 트래커
- 제3자 안드로이드 앱 접근을 허용
+ 제 3자 안드로이드 앱 접근을 허용
PebbleKit을 사용하는 안드로이드 앱을 실험적으로 지원
강제 알림 프로토콜
이 옵션은 펌웨어 버전에 따라 최신 알림 프로토콜을 강제로 사용하도록 합니다. 자세한 내용을 알 경우에만 이 옵션을 사용하세요.
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 68d808fbb..c12fce176 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -92,7 +92,7 @@
Generic notification support
…also when screen is on
Do Not Disturb
- Stop unwanted Notifications from being sent based on the Do Not Disturb mode
+ Stop unwanted notifications from being sent based on the Do Not Disturb mode
Transliteration
Enable this if your device has no support for your language\'s font
@@ -158,7 +158,7 @@
Please enable network location
location acquired
- Force Notification Protocol
+ Force notification protocol
This option forces using the latest notification protocol depending on the firmware version. ENABLE ONLY IF YOU KNOW WHAT YOU ARE DOING!
Enable untested features
Enable features that are untested. ENABLE ONLY IF YOU KNOW WHAT YOU ARE DOING!
@@ -357,13 +357,15 @@
Number of button presses to trigger message broadcast
Broadcast message to send
Broadcast message on defined number of button presses reached
- nodomain.freeyourgadget.gadgetbridge.mibandButtonPressed
+ nodomain.freeyourgadget.gadgetbridge.mibandButtonPressed
Enable button action
Enable action on specified number of button presses
Enable band vibration
Enable band vibration on button action triggered
Maximum delay between presses
Maximum delay between button presses in milliseconds
+ Delay after button action
+ Delay after one button action match (number is in button_id intent extra) or 0 for immediately
Goal notification
The band will vibrate when the daily steps goal is reached
Display items
@@ -471,4 +473,9 @@
Select Pair to pair your devices. If this fails, try again without pairing.
Pair
Don\'t Pair
+
+
+ Open on phone
+ Mute
+ Reply
diff --git a/app/src/main/res/xml/changelog_master.xml b/app/src/main/res/xml/changelog_master.xml
index a6d9f3501..4cf3ec831 100644
--- a/app/src/main/res/xml/changelog_master.xml
+++ b/app/src/main/res/xml/changelog_master.xml
@@ -1,5 +1,14 @@
+
+ Initial support for EXRIZU K8 (HPLus variant)
+ Amazfit Bip: fix long messages not being displayed at all
+ Mi Band 2: Support multiple button actions
+ NO.1 F1: Fetch sleep data
+ NO.1 F1: Heart rate support
+ Pebble: Support controlling the current active media playback application
+ Fix suspended activities coming to front when rotating the screen
+
Initial NO.1 F1 support
Initial Teclast H30 support
diff --git a/app/src/main/res/xml/miband_preferences.xml b/app/src/main/res/xml/miband_preferences.xml
index 0dcc54924..3798c8f66 100644
--- a/app/src/main/res/xml/miband_preferences.xml
+++ b/app/src/main/res/xml/miband_preferences.xml
@@ -49,12 +49,14 @@
+
+