mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-06-05 21:49:48 +02:00
Merge branch 'master' of https://github.com/mamutcho/Gadgetbridge
This commit is contained in:
@@ -72,6 +72,8 @@ public class GBDaoGenerator {
|
|||||||
addXWatchActivitySample(schema, user, device);
|
addXWatchActivitySample(schema, user, device);
|
||||||
addZeTimeActivitySample(schema, user, device);
|
addZeTimeActivitySample(schema, user, device);
|
||||||
addID115ActivitySample(schema, user, device);
|
addID115ActivitySample(schema, user, device);
|
||||||
|
addWatchXPlusHealthActivitySample(schema, user, device);
|
||||||
|
addWatchXPlusHealthActivityKindOverlay(schema, user, device);
|
||||||
|
|
||||||
addCalendarSyncState(schema, device);
|
addCalendarSyncState(schema, device);
|
||||||
addAlarms(schema, user, device);
|
addAlarms(schema, user, device);
|
||||||
@@ -330,6 +332,36 @@ public class GBDaoGenerator {
|
|||||||
return activitySample;
|
return activitySample;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Entity addWatchXPlusHealthActivitySample(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity activitySample = addEntity(schema, "WatchXPlusActivitySample");
|
||||||
|
activitySample.implementsSerializable();
|
||||||
|
addCommonActivitySampleProperties("AbstractActivitySample", activitySample, user, device);
|
||||||
|
activitySample.addByteArrayProperty("rawWatchXPlusHealthData");
|
||||||
|
activitySample.addIntProperty(SAMPLE_RAW_KIND).notNull().primaryKey();
|
||||||
|
activitySample.addIntProperty(SAMPLE_RAW_INTENSITY).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
activitySample.addIntProperty(SAMPLE_STEPS).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
addHeartRateProperties(activitySample);
|
||||||
|
activitySample.addIntProperty("distance");
|
||||||
|
activitySample.addIntProperty("calories");
|
||||||
|
return activitySample;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity addWatchXPlusHealthActivityKindOverlay(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity activityOverlay = addEntity(schema, "WatchXPlusHealthActivityOverlay");
|
||||||
|
|
||||||
|
activityOverlay.addIntProperty(TIMESTAMP_FROM).notNull().primaryKey();
|
||||||
|
activityOverlay.addIntProperty(TIMESTAMP_TO).notNull().primaryKey();
|
||||||
|
activityOverlay.addIntProperty(SAMPLE_RAW_KIND).notNull().primaryKey();
|
||||||
|
Property deviceId = activityOverlay.addLongProperty("deviceId").primaryKey().notNull().getProperty();
|
||||||
|
activityOverlay.addToOne(device, deviceId);
|
||||||
|
|
||||||
|
Property userId = activityOverlay.addLongProperty("userId").notNull().getProperty();
|
||||||
|
activityOverlay.addToOne(user, userId);
|
||||||
|
activityOverlay.addByteArrayProperty("rawWatchXPlusHealthData");
|
||||||
|
|
||||||
|
return activityOverlay;
|
||||||
|
}
|
||||||
|
|
||||||
private static void addCommonActivitySampleProperties(String superClass, Entity activitySample, Entity user, Entity device) {
|
private static void addCommonActivitySampleProperties(String superClass, Entity activitySample, Entity user, Entity device) {
|
||||||
activitySample.setSuperclass(superClass);
|
activitySample.setSuperclass(superClass);
|
||||||
activitySample.addImport(MAIN_PACKAGE + ".devices.SampleProvider");
|
activitySample.addImport(MAIN_PACKAGE + ".devices.SampleProvider");
|
||||||
|
@@ -40,6 +40,7 @@ vendor's servers.
|
|||||||
* HPlus Devices (e.g. ZeBand) [Wiki](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/HPlus)
|
* HPlus Devices (e.g. ZeBand) [Wiki](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/HPlus)
|
||||||
* ID115
|
* ID115
|
||||||
* Lenovo Watch 9
|
* Lenovo Watch 9
|
||||||
|
* Lenovo Watch X Plus
|
||||||
* Liveview
|
* Liveview
|
||||||
* Makibes HR3
|
* Makibes HR3
|
||||||
* Mi Band, Mi Band 1A, Mi Band 1S [Wiki](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Mi-Band)
|
* Mi Band, Mi Band 1A, Mi Band 1S [Wiki](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Mi-Band)
|
||||||
@@ -75,6 +76,7 @@ Please see [FEATURES.md](https://codeberg.org/Freeyourgadget/Gadgetbridge/src/ma
|
|||||||
* Sebastian Kranz (ZeTime)
|
* Sebastian Kranz (ZeTime)
|
||||||
* Vadim Kaushan (ID115)
|
* Vadim Kaushan (ID115)
|
||||||
* "maxirnilian" (Lenovo Watch 9)
|
* "maxirnilian" (Lenovo Watch 9)
|
||||||
|
* "ksiwczynski", "mkusnierz", "mamutcho" (Lenovo Watch X Plus)
|
||||||
* Andreas Böhler (Casio GB-6900B)
|
* Andreas Böhler (Casio GB-6900B)
|
||||||
* Jean-François Greffier (Mi Scale 2)
|
* Jean-François Greffier (Mi Scale 2)
|
||||||
* Johannes Schmitt (BFH-16)
|
* Johannes Schmitt (BFH-16)
|
||||||
|
@@ -73,6 +73,10 @@
|
|||||||
android:name=".devices.zetime.ZeTimePreferenceActivity"
|
android:name=".devices.zetime.ZeTimePreferenceActivity"
|
||||||
android:label="@string/zetime_title_settings"
|
android:label="@string/zetime_title_settings"
|
||||||
android:parentActivityName=".activities.SettingsActivity" />
|
android:parentActivityName=".activities.SettingsActivity" />
|
||||||
|
<activity
|
||||||
|
android:name=".devices.lenovo.watchxplus.WatchXPlusPreferenceActivity"
|
||||||
|
android:label="@string/preferences_watchxplus_settings"
|
||||||
|
android:parentActivityName=".activities.SettingsActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.ActivitySummariesActivity"
|
android:name=".activities.ActivitySummariesActivity"
|
||||||
android:label="@string/activity_summaries"
|
android:label="@string/activity_summaries"
|
||||||
@@ -406,6 +410,12 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".devices.watch9.Watch9CalibrationActivity"
|
android:name=".devices.watch9.Watch9CalibrationActivity"
|
||||||
android:label="@string/title_activity_watch9_calibration" />
|
android:label="@string/title_activity_watch9_calibration" />
|
||||||
|
<activity
|
||||||
|
android:name=".devices.lenovo.LenovoWatchPairingActivity"
|
||||||
|
android:label="@string/title_activity_watch9_pairing" />
|
||||||
|
<activity
|
||||||
|
android:name=".devices.lenovo.LenovoWatchCalibrationActivity"
|
||||||
|
android:label="@string/title_activity_watchXplus_calibration" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.charts.ChartsActivity"
|
android:name=".activities.charts.ChartsActivity"
|
||||||
android:label="@string/title_activity_charts"
|
android:label="@string/title_activity_charts"
|
||||||
|
@@ -54,11 +54,14 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.database.PeriodicExporter;
|
import nodomain.freeyourgadget.gadgetbridge.database.PeriodicExporter;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
|
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lenovo.watchxplus.WatchXPlusConstants;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lenovo.watchxplus.WatchXPlusPreferenceActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandPreferencesActivity;
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandPreferencesActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.ConfigActivity;
|
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.ConfigActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.zetime.ZeTimePreferenceActivity;
|
import nodomain.freeyourgadget.gadgetbridge.devices.zetime.ZeTimePreferenceActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsPreferencesActivity;
|
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsPreferencesActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lenovo.watchxplus.WatchXPlusDeviceSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
@@ -135,6 +138,15 @@ public class SettingsActivity extends AbstractSettingsActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pref = findPreference("pref_key_watchxplus");
|
||||||
|
pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||||
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
Intent enableIntent = new Intent(SettingsActivity.this, WatchXPlusPreferenceActivity.class);
|
||||||
|
startActivity(enableIntent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
pref = findPreference("pref_key_blacklist");
|
pref = findPreference("pref_key_blacklist");
|
||||||
pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
@@ -58,7 +58,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsActivity;
|
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
|
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.watch9.Watch9CalibrationActivity;
|
import nodomain.freeyourgadget.gadgetbridge.devices.lenovo.LenovoWatchCalibrationActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
|
import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||||
@@ -320,11 +320,12 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
|||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
holder.calibrateDevice.setVisibility(device.isInitialized() && device.getType() == DeviceType.WATCH9 ? View.VISIBLE : View.GONE);
|
holder.calibrateDevice.setVisibility(device.isInitialized() && (device.getType() == DeviceType.WATCH9 || device.getType() == DeviceType.WATCHXPLUS) ? View.VISIBLE : View.GONE);
|
||||||
holder.calibrateDevice.setOnClickListener(new View.OnClickListener() {
|
holder.calibrateDevice.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent startIntent = new Intent(context, Watch9CalibrationActivity.class);
|
Intent startIntent;
|
||||||
|
startIntent = new Intent(context, LenovoWatchCalibrationActivity.class);
|
||||||
startIntent.putExtra(GBDevice.EXTRA_DEVICE, device);
|
startIntent.putExtra(GBDevice.EXTRA_DEVICE, device);
|
||||||
context.startActivity(startIntent);
|
context.startActivity(startIntent);
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,31 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lenovo;
|
||||||
|
|
||||||
|
public enum DataType {
|
||||||
|
STEPS(new byte[]{0x00, 0x00}),
|
||||||
|
SLEEP(new byte[]{0x00, 0x01}),
|
||||||
|
HEART_RATE(new byte[]{0x00, 0x02}),
|
||||||
|
BLOOD_PRESSURE(new byte[]{0x00, 0x06}),
|
||||||
|
INFRARED_TEMPERATURE(new byte[]{0x00, 0x08}),
|
||||||
|
ENVIRONMENT_TEMPERATURE(new byte[]{0x00, 0x09}),
|
||||||
|
AIR_PRESSURE(new byte[]{0x00, 0x0A});
|
||||||
|
|
||||||
|
private byte[] value;
|
||||||
|
|
||||||
|
DataType(byte[] value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataType getType(int value) {
|
||||||
|
for(DataType type : values()) {
|
||||||
|
int intVal = (type.getValue()[1] & 0xff) | ((type.getValue()[0] & 0xff) << 8);
|
||||||
|
if(intVal == value) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException("No value defined for " + value);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,123 @@
|
|||||||
|
/* Copyright (C) 2018-2019 Daniele Gobbetti, maxirnilian
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lenovo;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.NumberPicker;
|
||||||
|
|
||||||
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
|
||||||
|
public class LenovoWatchCalibrationActivity extends AbstractGBActivity {
|
||||||
|
|
||||||
|
private static final String STATE_DEVICE = "stateDevice";
|
||||||
|
GBDevice device;
|
||||||
|
|
||||||
|
NumberPicker pickerHour, pickerMinute, pickerSecond;
|
||||||
|
|
||||||
|
Handler handler;
|
||||||
|
Runnable holdCalibration;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_watchxplus_calibration);
|
||||||
|
|
||||||
|
pickerHour = findViewById(R.id.np_hour);
|
||||||
|
pickerMinute = findViewById(R.id.np_minute);
|
||||||
|
pickerSecond = findViewById(R.id.np_second);
|
||||||
|
|
||||||
|
pickerHour.setMinValue(1);
|
||||||
|
pickerHour.setMaxValue(12);
|
||||||
|
pickerHour.setValue(12);
|
||||||
|
pickerMinute.setMinValue(0);
|
||||||
|
pickerMinute.setMaxValue(59);
|
||||||
|
pickerMinute.setValue(0);
|
||||||
|
pickerSecond.setMinValue(0);
|
||||||
|
pickerSecond.setMaxValue(59);
|
||||||
|
pickerSecond.setValue(0);
|
||||||
|
|
||||||
|
handler = new Handler();
|
||||||
|
holdCalibration = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(new Intent(LenovoWatchConstants.ACTION_CALIBRATION_HOLD));
|
||||||
|
handler.postDelayed(this, 10000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Intent intent = getIntent();
|
||||||
|
device = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||||
|
if (device == null && savedInstanceState != null) {
|
||||||
|
device = savedInstanceState.getParcelable(STATE_DEVICE);
|
||||||
|
}
|
||||||
|
if (device == null) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
final Button btCalibrate = findViewById(R.id.watch9_bt_calibrate);
|
||||||
|
btCalibrate.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
btCalibrate.setEnabled(false);
|
||||||
|
handler.removeCallbacks(holdCalibration);
|
||||||
|
Intent calibrationData = new Intent(LenovoWatchConstants.ACTION_CALIBRATION_SEND);
|
||||||
|
calibrationData.putExtra(LenovoWatchConstants.VALUE_CALIBRATION_HOUR, pickerHour.getValue());
|
||||||
|
calibrationData.putExtra(LenovoWatchConstants.VALUE_CALIBRATION_MINUTE, pickerMinute.getValue());
|
||||||
|
calibrationData.putExtra(LenovoWatchConstants.VALUE_CALIBRATION_SECOND, pickerSecond.getValue());
|
||||||
|
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(calibrationData);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
outState.putParcelable(STATE_DEVICE, device);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||||
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
|
device = savedInstanceState.getParcelable(STATE_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
Intent calibration = new Intent(LenovoWatchConstants.ACTION_CALIBRATION);
|
||||||
|
calibration.putExtra(LenovoWatchConstants.ACTION_ENABLE, true);
|
||||||
|
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(calibration);
|
||||||
|
handler.postDelayed(holdCalibration, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
Intent calibration = new Intent(LenovoWatchConstants.ACTION_CALIBRATION);
|
||||||
|
calibration.putExtra(LenovoWatchConstants.ACTION_ENABLE, false);
|
||||||
|
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(calibration);
|
||||||
|
handler.removeCallbacks(holdCalibration);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,79 @@
|
|||||||
|
/* Copyright (C) 2018-2019 maxirnilian
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lenovo;
|
||||||
|
|
||||||
|
public class LenovoWatchConstants {
|
||||||
|
|
||||||
|
public static final byte RESPONSE = 0x13;
|
||||||
|
public static final byte REQUEST = 0x31;
|
||||||
|
|
||||||
|
public static final byte WRITE_VALUE = 0x01;
|
||||||
|
public static final byte READ_VALUE = 0x02;
|
||||||
|
public static final byte TASK = 0x04;
|
||||||
|
public static final byte KEEP_ALIVE = -0x80;
|
||||||
|
|
||||||
|
public static final byte[] CMD_HEADER = new byte[]{0x23, 0x01, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
// byte[] COMMAND = new byte[]{0x23, 0x01, 0x00, 0x31, 0x00, ... , 0x00}
|
||||||
|
// | | | | | | └ Checksum
|
||||||
|
// | | | | | └ Command + value
|
||||||
|
// | | | | └ Sequence number
|
||||||
|
// | | | └ Response/Request indicator
|
||||||
|
// | | └ Value length
|
||||||
|
// | |
|
||||||
|
// └-----└ Header
|
||||||
|
|
||||||
|
public static final byte[] CMD_FIRMWARE_INFO = new byte[]{0x01, 0x02};
|
||||||
|
public static final byte[] CMD_AUTHORIZATION_TASK = new byte[]{0x01, 0x05};
|
||||||
|
public static final byte[] CMD_TIME_SETTINGS = new byte[]{0x01, 0x08};
|
||||||
|
public static final byte[] CMD_ALARM_SETTINGS = new byte[]{0x01, 0x0A};
|
||||||
|
public static final byte[] CMD_BATTERY_INFO = new byte[]{0x01, 0x14};
|
||||||
|
|
||||||
|
public static final byte[] CMD_NOTIFICATION_TASK = new byte[]{0x03, 0x01};
|
||||||
|
public static final byte[] CMD_NOTIFICATION_SETTINGS = new byte[]{0x03, 0x02};
|
||||||
|
public static final byte[] CMD_CALIBRATION_INIT_TASK = new byte[]{0x03, 0x31};
|
||||||
|
public static final byte[] CMD_CALIBRATION_TASK = new byte[]{0x03, 0x33, 0x01};
|
||||||
|
public static final byte[] CMD_CALIBRATION_KEEP_ALIVE = new byte[]{0x03, 0x34};
|
||||||
|
public static final byte[] CMD_DO_NOT_DISTURB_SETTINGS = new byte[]{0x03, 0x61};
|
||||||
|
|
||||||
|
public static final byte[] CMD_FITNESS_GOAL_SETTINGS = new byte[]{0x10, 0x02};
|
||||||
|
|
||||||
|
public static final byte[] RESP_AUTHORIZATION_TASK = new byte[]{0x01, 0x01, 0x05};
|
||||||
|
public static final byte[] RESP_BUTTON_INDICATOR = new byte[]{0x04, 0x03, 0x11};
|
||||||
|
public static final byte[] RESP_ALARM_INDICATOR = new byte[]{-0x80, 0x01, 0x0A};
|
||||||
|
|
||||||
|
public static final byte[] RESP_FIRMWARE_INFO = new byte[]{0x08, 0x01, 0x02};
|
||||||
|
public static final byte[] RESP_TIME_SETTINGS = new byte[]{0x08, 0x01, 0x08};
|
||||||
|
public static final byte[] RESP_BATTERY_INFO = new byte[]{0x08, 0x01, 0x14};
|
||||||
|
public static final byte[] RESP_NOTIFICATION_SETTINGS = new byte[]{0x01, 0x03, 0x02};
|
||||||
|
|
||||||
|
public static final String ACTION_ENABLE = "action.watch9.enable";
|
||||||
|
|
||||||
|
public static final String ACTION_CALIBRATION
|
||||||
|
= "nodomain.freeyourgadget.gadgetbridge.devices.action.lenovowatch.start_calibration";
|
||||||
|
public static final String ACTION_CALIBRATION_SEND
|
||||||
|
= "nodomain.freeyourgadget.gadgetbridge.devices.action.lenovowatch.send_calibration";
|
||||||
|
public static final String ACTION_CALIBRATION_HOLD
|
||||||
|
= "nodomain.freeyourgadget.gadgetbridge.devices.action.lenovowatch.keep_calibrating";
|
||||||
|
public static final String VALUE_CALIBRATION_HOUR
|
||||||
|
= "value.lenovowatch.calibration_hour";
|
||||||
|
public static final String VALUE_CALIBRATION_MINUTE
|
||||||
|
= "value.lenovowatch.calibration_minute";
|
||||||
|
public static final String VALUE_CALIBRATION_SECOND
|
||||||
|
= "value.lenovowatch.calibration_second";
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,129 @@
|
|||||||
|
/* Copyright (C) 2018-2019 Daniele Gobbetti, maxirnilian
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lenovo;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenterv2;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.DiscoveryActivity;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
|
public class LenovoWatchPairingActivity extends AbstractGBActivity {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(LenovoWatchPairingActivity.class);
|
||||||
|
|
||||||
|
private static final String STATE_DEVICE_CANDIDATE = "stateDeviceCandidate";
|
||||||
|
|
||||||
|
private TextView message;
|
||||||
|
private GBDeviceCandidate deviceCandidate;
|
||||||
|
|
||||||
|
private final BroadcastReceiver mPairingReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (GBDevice.ACTION_DEVICE_CHANGED.equals(intent.getAction())) {
|
||||||
|
GBDevice device = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||||
|
LOG.debug("pairing activity: device changed: " + device);
|
||||||
|
if (deviceCandidate.getMacAddress().equals(device.getAddress())) {
|
||||||
|
if (device.isInitialized()) {
|
||||||
|
pairingFinished();
|
||||||
|
} else if (device.isConnecting() || device.isInitializing()) {
|
||||||
|
LOG.info("still connecting/initializing device...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_watch9_pairing);
|
||||||
|
|
||||||
|
message = findViewById(R.id.watch9_pair_message);
|
||||||
|
Intent intent = getIntent();
|
||||||
|
deviceCandidate = intent.getParcelableExtra(DeviceCoordinator.EXTRA_DEVICE_CANDIDATE);
|
||||||
|
if (deviceCandidate == null && savedInstanceState != null) {
|
||||||
|
deviceCandidate = savedInstanceState.getParcelable(STATE_DEVICE_CANDIDATE);
|
||||||
|
}
|
||||||
|
if (deviceCandidate == null) {
|
||||||
|
Toast.makeText(this, getString(R.string.message_cannot_pair_no_mac), Toast.LENGTH_SHORT).show();
|
||||||
|
startActivity(new Intent(this, DiscoveryActivity.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
startPairing();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
outState.putParcelable(STATE_DEVICE_CANDIDATE, deviceCandidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||||
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
|
deviceCandidate = savedInstanceState.getParcelable(STATE_DEVICE_CANDIDATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
AndroidUtils.safeUnregisterBroadcastReceiver(LocalBroadcastManager.getInstance(this), mPairingReceiver);
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startPairing() {
|
||||||
|
message.setText(getString(R.string.pairing, deviceCandidate));
|
||||||
|
|
||||||
|
IntentFilter filter = new IntentFilter(GBDevice.ACTION_DEVICE_CHANGED);
|
||||||
|
LocalBroadcastManager.getInstance(this).registerReceiver(mPairingReceiver, filter);
|
||||||
|
|
||||||
|
GBApplication.deviceService().disconnect();
|
||||||
|
GBDevice device = DeviceHelper.getInstance().toSupportedDevice(deviceCandidate);
|
||||||
|
if (device != null) {
|
||||||
|
GBApplication.deviceService().connect(device, true);
|
||||||
|
} else {
|
||||||
|
GB.toast(this, "Unable to connect, can't recognize the device type: " + deviceCandidate, Toast.LENGTH_LONG, GB.ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pairingFinished() {
|
||||||
|
AndroidUtils.safeUnregisterBroadcastReceiver(LocalBroadcastManager.getInstance(this), mPairingReceiver);
|
||||||
|
|
||||||
|
Intent intent = new Intent(this, ControlCenterv2.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
startActivity(intent);
|
||||||
|
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,114 @@
|
|||||||
|
/* Copyright (C) 2018-2019 maxirnilian
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lenovo.watchxplus;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lenovo.LenovoWatchConstants;
|
||||||
|
|
||||||
|
public final class WatchXPlusConstants extends LenovoWatchConstants {
|
||||||
|
public static final UUID UUID_SERVICE_WATCHXPLUS = UUID.fromString("0000a800-0000-1000-8000-00805f9b34fb");
|
||||||
|
|
||||||
|
public static final UUID UUID_UNKNOWN_DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
|
||||||
|
|
||||||
|
public static final UUID UUID_CHARACTERISTIC_WRITE = UUID.fromString("0000a801-0000-1000-8000-00805f9b34fb");
|
||||||
|
public static final UUID UUID_CHARACTERISTIC_DATABASE_READ = UUID.fromString("0000a802-0000-1000-8000-00805f9b34fb");
|
||||||
|
public static final UUID UUID_CHARACTERISTIC_UNKNOWN_3 = UUID.fromString("0000a803-0000-1000-8000-00805f9b34fb");
|
||||||
|
public static final UUID UUID_CHARACTERISTIC_UNKNOWN_4 = UUID.fromString("0000a804-0000-1000-8000-00805f9b34fb");
|
||||||
|
|
||||||
|
public static final String PREF_ACTIVATE_DISPLAY = "activate_display_on_lift_wrist";
|
||||||
|
public static final String PREF_DISCONNECT_REMIND = "disconnect_notification";
|
||||||
|
public static final String PREF_FIND_PHONE = "prefs_find_phone";
|
||||||
|
public static final String PREF_FIND_PHONE_DURATION = "prefs_find_phone_duration";
|
||||||
|
public static final String PREF_ALTITUDE = "pref_watchxplus_altitude";
|
||||||
|
public static final String PREF_REPEAT = "watchxplus_repeat";
|
||||||
|
public static final String PREF_CONTINIOUS = "watchxplus_continious";
|
||||||
|
public static final String PREF_MISSED_CALL = "watchxplus_missed";
|
||||||
|
public static final String PREF_MISSED_CALL_REPEAT = "watchxplus_repeat_missedcall";
|
||||||
|
public static final String PREF_IS_BP_CALIBRATED = "watchxplus_is_bp_calibrated";
|
||||||
|
public static final String PREF_BUTTON_REJECT = "watchxplus_button_reject";
|
||||||
|
public static final String PREF_SHAKE_REJECT = "watchxplus_shake_reject";
|
||||||
|
public static final String PREF_BP_CAL_LOW = "pref_wxp_bp_calibration_low";
|
||||||
|
public static final String PREF_BP_CAL_HIGH = "pref_wxp_bp_calibration_high";
|
||||||
|
public static final String PREF_BP_CAL_SWITCH = "wxp_button_BP_calibration_list";
|
||||||
|
public static final String PREF_DO_NOT_DISTURB = "do_not_disturb_no_auto";
|
||||||
|
public static final String PREF_DO_NOT_DISTURB_START = "do_not_disturb_no_auto_start";
|
||||||
|
public static final String PREF_DO_NOT_DISTURB_END = "do_not_disturb_no_auto_end";
|
||||||
|
public static final String PREF_LONGSIT_SWITCH = "pref_watchxplus_longsit_switch";
|
||||||
|
public static final String PREF_LONGSIT_PERIOD = "pref_watchxplus_longsit_period";
|
||||||
|
public static final String PREF_WXP_LANGUAGE = "pref_wxp_language";
|
||||||
|
public static final String PREF_POWER_MODE = "pref_wxp_power_mode";
|
||||||
|
|
||||||
|
|
||||||
|
// time format constants
|
||||||
|
public static final byte ARG_SET_TIMEMODE_24H = 0x00;
|
||||||
|
public static final byte ARG_SET_TIMEMODE_12H = 0x01;
|
||||||
|
|
||||||
|
public static final int NOTIFICATION_CHANNEL_DEFAULT = 0;
|
||||||
|
public static final int NOTIFICATION_CHANNEL_PHONE_CALL = 10;
|
||||||
|
|
||||||
|
public static final byte[] CMD_WEATHER_SET = new byte[]{0x01, 0x10};
|
||||||
|
public static final byte[] CMD_RETRIEVE_DATA_COUNT = new byte[]{(byte)0xF0, 0x10};
|
||||||
|
public static final byte[] CMD_RETRIEVE_DATA_DETAILS = new byte[]{(byte)0xF0, 0x11};
|
||||||
|
public static final byte[] CMD_RETRIEVE_DATA_CONTENT = new byte[]{(byte)0xF0, 0x12};
|
||||||
|
public static final byte[] CMD_REMOVE_DATA_CONTENT = new byte[]{(byte)0xF0, 0x32};
|
||||||
|
public static final byte[] CMD_BLOOD_PRESSURE_MEASURE = new byte[]{0x05, 0x0D};
|
||||||
|
public static final byte[] CMD_HEART_RATE_MEASURE = new byte[]{0x03, 0x23};
|
||||||
|
public static final byte[] CMD_IS_BP_CALIBRATED = new byte[]{0x05, 0x0B};
|
||||||
|
public static final byte[] CMD_BP_CALIBRATION = new byte[]{0x05, 0x0C};
|
||||||
|
|
||||||
|
public static final byte[] CMD_NOTIFICATION_TEXT_TASK = new byte[]{0x03, 0x06};
|
||||||
|
public static final byte[] CMD_NOTIFICATION_CANCEL = new byte[]{0x03, 0x04};
|
||||||
|
public static final byte[] CMD_NOTIFICATION_SETTINGS = new byte[]{0x03, 0x02};
|
||||||
|
public static final byte[] CMD_DO_NOT_DISTURB_SETTINGS = new byte[]{0x03, 0x61};
|
||||||
|
public static final byte[] CMD_POWER_MODE = new byte[]{0x03, -0x7F};
|
||||||
|
public static final byte[] CMD_SET_QUITE_HOURS_TIME = new byte[]{0x03, 0x62};
|
||||||
|
public static final byte[] CMD_SET_QUITE_HOURS_SWITCH = new byte[]{0x03, 0x61};
|
||||||
|
public static final byte[] CMD_SET_PERSONAL_INFO = new byte[]{0x01, 0x0E};
|
||||||
|
public static final byte[] CMD_INACTIVITY_REMINDER_SWITCH = new byte[]{0x03, 0x51};
|
||||||
|
public static final byte[] CMD_INACTIVITY_REMINDER_SET = new byte[]{0x03, 0x52};
|
||||||
|
public static final byte[] CMD_SET_UNITS = new byte[]{0x03, -0x6D};
|
||||||
|
|
||||||
|
public static final byte[] CMD_FITNESS_GOAL_SETTINGS = new byte[]{0x10, 0x02};
|
||||||
|
public static final byte[] CMD_DAY_STEPS_INFO = new byte[]{0x10, 0x03};
|
||||||
|
|
||||||
|
public static final byte[] CMD_SHAKE_SWITCH = new byte[]{0x03, -0x6E};
|
||||||
|
public static final byte[] CMD_DISCONNECT_REMIND = new byte[]{0x00, 0x11};
|
||||||
|
public static final byte[] CMD_TIME_LANGUAGE = new byte[]{0x03, -0x6F};
|
||||||
|
public static final byte[] CMD_ALTITUDE = new byte[]{0x05, 0x0A};
|
||||||
|
|
||||||
|
public static final byte[] RESP_SHAKE_SWITCH = new byte[]{0x08, 0x03, -0x6E};
|
||||||
|
public static final byte[] RESP_DISCONNECT_REMIND = new byte[]{0x08, 0x00, 0x11};
|
||||||
|
public static final byte[] RESP_IS_BP_CALIBRATED = new byte[]{0x08, 0x05, 0x0B};
|
||||||
|
public static final byte[] RESP_BUTTON_WHILE_RING = new byte[]{0x04, 0x03, 0x03};
|
||||||
|
public static final byte[] RESP_BP_CALIBRATION = new byte[]{0x08, 0x05, 0x0C};
|
||||||
|
public static final byte[] RESP_SET_PERSONAL_INFO = new byte[]{0x08, 0x01, 0x0E};
|
||||||
|
public static final byte[] RESP_GOAL_AIM_STATUS = new byte[]{0x08, 0x10, 0x02};
|
||||||
|
public static final byte[] RESP_INACTIVITY_REMINDER_SWITCH = new byte[]{0x08, 0x03, 0x51};
|
||||||
|
public static final byte[] RESP_INACTIVITY_REMINDER_SET = new byte[]{0x08, 0x03, 0x52};
|
||||||
|
|
||||||
|
public static final byte[] RESP_AUTHORIZATION_TASK = new byte[]{0x01, 0x01, 0x05};
|
||||||
|
public static final byte[] RESP_DAY_STEPS_INDICATOR = new byte[]{0x08, 0x10, 0x03};
|
||||||
|
public static final byte[] RESP_HEARTRATE = new byte[]{(byte) 0x80, 0x15, 0x03};
|
||||||
|
|
||||||
|
public static final byte[] RESP_DATA_COUNT = new byte[]{0x08, (byte)0xF0, 0x10};
|
||||||
|
public static final byte[] RESP_DATA_DETAILS = new byte[]{0x08, (byte)0xF0, 0x11};
|
||||||
|
public static final byte[] RESP_DATA_CONTENT = new byte[]{0x08, (byte)0xF0, 0x12};
|
||||||
|
public static final byte[] RESP_DATA_CONTENT_REMOVE = new byte[]{-0x80, (byte)0xF0, 0x32};
|
||||||
|
public static final byte[] RESP_BP_MEASURE_STARTED = new byte[]{0x08, 0x05, 0x0D};
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,352 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lenovo.watchxplus;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.bluetooth.le.ScanFilter;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.ParcelUuid;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lenovo.LenovoWatchPairingActivity;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lenovo.watchxplus.WatchXPlusDeviceSupport;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
|
|
||||||
|
import static nodomain.freeyourgadget.gadgetbridge.GBApplication.getContext;
|
||||||
|
|
||||||
|
|
||||||
|
public class WatchXPlusDeviceCoordinator extends AbstractDeviceCoordinator {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(WatchXPlusDeviceSupport.class);
|
||||||
|
private static final int FindPhone_ON = -1;
|
||||||
|
public static final int FindPhone_OFF = 0;
|
||||||
|
public static boolean isBPCalibrated = false;
|
||||||
|
|
||||||
|
private static Prefs prefs = GBApplication.getPrefs();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
public Collection<? extends ScanFilter> createBLEScanFilters() {
|
||||||
|
ParcelUuid watchXpService = new ParcelUuid(WatchXPlusConstants.UUID_SERVICE_WATCHXPLUS);
|
||||||
|
ScanFilter filter = new ScanFilter.Builder().setServiceUuid(watchXpService).build();
|
||||||
|
return Collections.singletonList(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBondingStyle() {
|
||||||
|
return BONDING_STYLE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public DeviceType getSupportedType(GBDeviceCandidate candidate) {
|
||||||
|
String macAddress = candidate.getMacAddress().toUpperCase();
|
||||||
|
String deviceName = candidate.getName().toUpperCase();
|
||||||
|
if (candidate.supportsService(WatchXPlusConstants.UUID_SERVICE_WATCHXPLUS)) {
|
||||||
|
return DeviceType.WATCHXPLUS;
|
||||||
|
} else if (macAddress.startsWith("DC:41:E5")) {
|
||||||
|
return DeviceType.WATCHXPLUS;
|
||||||
|
} else if (deviceName.equalsIgnoreCase("WATCH XPLUS")) {
|
||||||
|
return DeviceType.WATCHXPLUS;
|
||||||
|
// add initial support for Watch X non-plus (forces Watch X to be recognized as Watch XPlus)
|
||||||
|
// Watch X non-plus have same MAC address as Watch 9 (starts with "1C:87:79")
|
||||||
|
} else if (deviceName.equalsIgnoreCase("WATCH X")) {
|
||||||
|
return DeviceType.WATCHXPLUS;
|
||||||
|
}
|
||||||
|
return DeviceType.UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeviceType getDeviceType() {
|
||||||
|
return DeviceType.WATCHXPLUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Class<? extends Activity> getPairingActivity() {
|
||||||
|
return LenovoWatchPairingActivity.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsActivityDataFetching() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsActivityTracking() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SampleProvider<? extends ActivitySample> getSampleProvider(GBDevice device, DaoSession session) {
|
||||||
|
return new WatchXPlusSampleProvider(device, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InstallHandler findInstallHandler(Uri uri, Context context) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsScreenshots() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAlarmSlotCount() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsSmartWakeup(GBDevice device) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsHeartRateMeasurement(GBDevice device) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getManufacturer() {
|
||||||
|
return "Lenovo";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsAppsManagement() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Activity> getAppsManagementActivity() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsCalendarEvents() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsRealtimeData() { return false; }
|
||||||
|
@Override
|
||||||
|
public boolean supportsWeather() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsFindDevice() { return false; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
|
||||||
|
return new int[]{
|
||||||
|
R.xml.devicesettings_liftwrist_display,
|
||||||
|
R.xml.devicesettings_disconnectnotification,
|
||||||
|
R.xml.devicesettings_find_phone,
|
||||||
|
R.xml.devicesettings_timeformat,
|
||||||
|
R.xml.devicesettings_donotdisturb_no_auto
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Prefs from device settings on main page
|
||||||
|
*/
|
||||||
|
// return time format pref
|
||||||
|
public static byte getTimeMode(SharedPreferences sharedPrefs) {
|
||||||
|
String timeMode = sharedPrefs.getString(DeviceSettingsPreferenceConst.PREF_TIMEFORMAT, getContext().getString(R.string.p_timeformat_24h));
|
||||||
|
assert timeMode != null;
|
||||||
|
if (timeMode.equals(getContext().getString(R.string.p_timeformat_24h))) {
|
||||||
|
return WatchXPlusConstants.ARG_SET_TIMEMODE_24H;
|
||||||
|
} else {
|
||||||
|
return WatchXPlusConstants.ARG_SET_TIMEMODE_12H;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return watch language pref
|
||||||
|
public static byte getLanguage(SharedPreferences sharedPrefs) {
|
||||||
|
int settingRead = prefs.getInt(WatchXPlusConstants.PREF_WXP_LANGUAGE, 1);
|
||||||
|
return (byte) settingRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if it is needed to toggle Lift Wrist to Sreen on
|
||||||
|
public static boolean shouldEnableHeadsUpScreen(SharedPreferences sharedPrefs) {
|
||||||
|
String liftMode = sharedPrefs.getString(WatchXPlusConstants.PREF_ACTIVATE_DISPLAY, getContext().getString(R.string.p_on));
|
||||||
|
// WatchXPlus doesn't support scheduled intervals. Treat it as "on".
|
||||||
|
assert liftMode != null;
|
||||||
|
return !liftMode.equals(getContext().getString(R.string.p_off));
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if it is needed to toggle Disconnect reminder
|
||||||
|
public static boolean shouldEnableDisconnectReminder(SharedPreferences sharedPrefs) {
|
||||||
|
String lostReminder = sharedPrefs.getString(WatchXPlusConstants.PREF_DISCONNECT_REMIND, getContext().getString(R.string.p_on));
|
||||||
|
// WatchXPlus doesn't support scheduled intervals. Treat it as "on".
|
||||||
|
assert lostReminder != null;
|
||||||
|
return !lostReminder.equals(getContext().getString(R.string.p_off));
|
||||||
|
}
|
||||||
|
|
||||||
|
// find phone settings
|
||||||
|
/**
|
||||||
|
* @return {@link #FindPhone_OFF}, {@link #FindPhone_ON}, or the duration
|
||||||
|
*/
|
||||||
|
public static int getFindPhone(SharedPreferences sharedPrefs) {
|
||||||
|
String findPhone = sharedPrefs.getString(WatchXPlusConstants.PREF_FIND_PHONE, getContext().getString(R.string.p_off));
|
||||||
|
|
||||||
|
assert findPhone != null;
|
||||||
|
if (findPhone.equals(getContext().getString(R.string.p_off))) {
|
||||||
|
return FindPhone_OFF;
|
||||||
|
} else if (findPhone.equals(getContext().getString(R.string.p_on))) {
|
||||||
|
return FindPhone_ON;
|
||||||
|
} else { // Duration
|
||||||
|
String duration = sharedPrefs.getString(WatchXPlusConstants.PREF_FIND_PHONE_DURATION, "0");
|
||||||
|
|
||||||
|
try {
|
||||||
|
int iDuration;
|
||||||
|
|
||||||
|
try {
|
||||||
|
assert duration != null;
|
||||||
|
iDuration = Integer.valueOf(duration);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
iDuration = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
return iDuration;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return FindPhone_ON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param startOut out Only hour/minute are used.
|
||||||
|
* @param endOut out Only hour/minute are used.
|
||||||
|
* @return True if quite hours are enabled.
|
||||||
|
*/
|
||||||
|
public static boolean getQuiteHours(SharedPreferences sharedPrefs, Calendar startOut, Calendar endOut) {
|
||||||
|
String doNotDisturb = sharedPrefs.getString(WatchXPlusConstants.PREF_DO_NOT_DISTURB, getContext().getString(R.string.p_off));
|
||||||
|
|
||||||
|
assert doNotDisturb != null;
|
||||||
|
if (doNotDisturb.equals(getContext().getString(R.string.p_off))) {
|
||||||
|
LOG.info(" DND is disabled ");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
String start = sharedPrefs.getString(WatchXPlusConstants.PREF_DO_NOT_DISTURB_START, "00:00");
|
||||||
|
String end = sharedPrefs.getString(WatchXPlusConstants.PREF_DO_NOT_DISTURB_END, "00:00");
|
||||||
|
|
||||||
|
DateFormat df = new SimpleDateFormat("HH:mm");
|
||||||
|
|
||||||
|
try {
|
||||||
|
startOut.setTime(df.parse(start));
|
||||||
|
endOut.setTime(df.parse(end));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param startOut out Only hour/minute are used.
|
||||||
|
* @param endOut out Only hour/minute are used.
|
||||||
|
* @return True if quite hours are enabled.
|
||||||
|
*/
|
||||||
|
public static boolean getLongSitHours(SharedPreferences sharedPrefs, Calendar startOut, Calendar endOut) {
|
||||||
|
boolean enabled = prefs.getBoolean(WatchXPlusConstants.PREF_LONGSIT_SWITCH, false);
|
||||||
|
|
||||||
|
if (!enabled) {
|
||||||
|
LOG.info(" DND is disabled ");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
String start = sharedPrefs.getString(WatchXPlusConstants.PREF_DO_NOT_DISTURB_START, "00:00");
|
||||||
|
String end = sharedPrefs.getString(WatchXPlusConstants.PREF_DO_NOT_DISTURB_END, "00:00");
|
||||||
|
|
||||||
|
DateFormat df = new SimpleDateFormat("HH:mm");
|
||||||
|
|
||||||
|
try {
|
||||||
|
startOut.setTime(df.parse(start));
|
||||||
|
endOut.setTime(df.parse(end));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Values from device specific settings page
|
||||||
|
*/
|
||||||
|
// read altitude from preferences
|
||||||
|
public static int getAltitude(String address) {
|
||||||
|
return prefs.getInt(WatchXPlusConstants.PREF_ALTITUDE, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read repeat call notification
|
||||||
|
public static int getRepeatOnCall(String address) {
|
||||||
|
return prefs.getInt(WatchXPlusConstants.PREF_REPEAT, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//read continious call notification
|
||||||
|
public static boolean getContiniousVibrationOnCall(String address) {
|
||||||
|
return prefs.getBoolean(WatchXPlusConstants.PREF_CONTINIOUS, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//read missed call notification
|
||||||
|
public static boolean getMissedCallReminder(String address) {
|
||||||
|
return prefs.getBoolean(WatchXPlusConstants.PREF_MISSED_CALL, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//read missed call notification
|
||||||
|
public static int getMissedCallRepeat(String address) {
|
||||||
|
return prefs.getInt(WatchXPlusConstants.PREF_MISSED_CALL_REPEAT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//read button reject call settings
|
||||||
|
public static boolean getButtonReject(String address) {
|
||||||
|
return prefs.getBoolean(WatchXPlusConstants.PREF_BUTTON_REJECT, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//read shake wrist reject call settings
|
||||||
|
public static boolean getShakeReject(String address) {
|
||||||
|
return prefs.getBoolean(WatchXPlusConstants.PREF_SHAKE_REJECT, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Other saved preferences
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,64 @@
|
|||||||
|
/* Copyright (C) 2018-2019 Sebastian Kranz
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lenovo.watchxplus;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.Preference;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractSettingsActivity;
|
||||||
|
|
||||||
|
public class WatchXPlusPreferenceActivity extends AbstractSettingsActivity {
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
addPreferencesFromResource(R.xml.watchxplus_preferences);
|
||||||
|
|
||||||
|
// notifications
|
||||||
|
//addPreferenceHandlerFor(WatchXPlusConstants.PREF_REPEAT);
|
||||||
|
//addPreferenceHandlerFor(WatchXPlusConstants.PREF_CONTINIOUS);
|
||||||
|
//addPreferenceHandlerFor(WatchXPlusConstants.PREF_MISSED_CALL);
|
||||||
|
//addPreferenceHandlerFor(WatchXPlusConstants.PREF_MISSED_CALL_REPEAT);
|
||||||
|
//addPreferenceHandlerFor(WatchXPlusConstants.PREF_BUTTON_REJECT);
|
||||||
|
//addPreferenceHandlerFor(WatchXPlusConstants.PREF_SHAKE_REJECT);
|
||||||
|
|
||||||
|
// settings
|
||||||
|
addPreferenceHandlerFor(WatchXPlusConstants.PREF_POWER_MODE);
|
||||||
|
addPreferenceHandlerFor(WatchXPlusConstants.PREF_WXP_LANGUAGE);
|
||||||
|
addPreferenceHandlerFor(WatchXPlusConstants.PREF_LONGSIT_PERIOD);
|
||||||
|
addPreferenceHandlerFor(WatchXPlusConstants.PREF_LONGSIT_SWITCH);
|
||||||
|
// calibration
|
||||||
|
addPreferenceHandlerFor(WatchXPlusConstants.PREF_ALTITUDE);
|
||||||
|
addPreferenceHandlerFor(WatchXPlusConstants.PREF_BP_CAL_LOW);
|
||||||
|
addPreferenceHandlerFor(WatchXPlusConstants.PREF_BP_CAL_HIGH);
|
||||||
|
addPreferenceHandlerFor(WatchXPlusConstants.PREF_BP_CAL_SWITCH);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPreferenceHandlerFor(final String preferenceKey) {
|
||||||
|
Preference pref = findPreference(preferenceKey);
|
||||||
|
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
|
@Override public boolean onPreferenceChange(Preference preference, Object newVal) {
|
||||||
|
GBApplication.deviceService().onSendConfiguration(preferenceKey);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,63 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.lenovo.watchxplus;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import de.greenrobot.dao.AbstractDao;
|
||||||
|
import de.greenrobot.dao.Property;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractSampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.WatchXPlusActivitySample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.WatchXPlusActivitySampleDao;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
|
||||||
|
public class WatchXPlusSampleProvider extends AbstractSampleProvider<WatchXPlusActivitySample> {
|
||||||
|
|
||||||
|
public WatchXPlusSampleProvider(GBDevice device, DaoSession session) {
|
||||||
|
super(device, session);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int normalizeType(int rawType) {
|
||||||
|
return rawType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int toRawActivityKind(int activityKind) {
|
||||||
|
return activityKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float normalizeIntensity(int rawIntensity) {
|
||||||
|
return rawIntensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WatchXPlusActivitySample createActivitySample() {
|
||||||
|
return new WatchXPlusActivitySample();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractDao<WatchXPlusActivitySample, ?> getSampleDao() {
|
||||||
|
return getSession().getWatchXPlusActivitySampleDao();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected Property getRawKindSampleProperty() {
|
||||||
|
return WatchXPlusActivitySampleDao.Properties.RawKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected Property getTimestampSampleProperty() {
|
||||||
|
return WatchXPlusActivitySampleDao.Properties.Timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected Property getDeviceIdentifierSampleProperty() {
|
||||||
|
return WatchXPlusActivitySampleDao.Properties.DeviceId;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,82 @@
|
|||||||
|
NEED TO BE DONE
|
||||||
|
Watch settings
|
||||||
|
- Implement temperature alarm on watch //tried to implement with no luck
|
||||||
|
- Implement continuous blood pressure measurement (on, off, scheduled)
|
||||||
|
|
||||||
|
Add feature to initiate button press event on watch
|
||||||
|
- Send command to watch
|
||||||
|
- Get trigger on button press
|
||||||
|
|
||||||
|
Schedulers:
|
||||||
|
- Screen on scheduler (inApp, not supported by watch)
|
||||||
|
- Disconnect reminder scheduler (inApp, not supported by watch)
|
||||||
|
- Continuous blood pressure measurement (supported by watch, there are command for that, but not tested)
|
||||||
|
|
||||||
|
Refine get activity data
|
||||||
|
- Fix get sleep data
|
||||||
|
|
||||||
|
Measurements
|
||||||
|
- Blood pressure measurement
|
||||||
|
- Show blood pressure measurement (view)
|
||||||
|
- Implement heart rate measurement //tried to implement with no luck
|
||||||
|
- Implement temperature measurement //tried to implement with no luck
|
||||||
|
- Implement UV index measurement //tried to implement with no luck
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
WORK PROGRESS
|
||||||
|
Bump Gadgetbridge version to 0.39 (19.11.2019)
|
||||||
|
|
||||||
|
Send notification to watch
|
||||||
|
- On incoming call
|
||||||
|
- add function to cancel notification on watch (04.11.2019)
|
||||||
|
- cancel notification on change phone state (end call, reject call etc.) (06.11.2019)
|
||||||
|
- settings for repeat notification [0-10 times] (05.11.2019)
|
||||||
|
- settings for continious notification while phone ring [on, off] (06.11.2019)
|
||||||
|
- settings for send once notification for missed call [on, off] (06.11.2019)
|
||||||
|
* send missed call notification every minute for X times (17.11.2019)
|
||||||
|
- On text message, or other application
|
||||||
|
- On triger phone alarm (05.11.2019)
|
||||||
|
|
||||||
|
Call handling
|
||||||
|
- Setting for ignore/reject call with watch button [on->reject call, off->ignore call] (06.11.2019)
|
||||||
|
- Setting for ignore/reject call with shake device - duplicates button action [on, off] (06.11.2019)
|
||||||
|
- On watch - show small phone icon near bluetooth icon when there are missed call (06.11.2019)
|
||||||
|
|
||||||
|
Calibrations
|
||||||
|
- Time calibration
|
||||||
|
* send current date/time to watch
|
||||||
|
- Set watch alarms
|
||||||
|
- Altitude calibration [altitude (meters)] (04.11.2019)
|
||||||
|
* it's used in Climb activity
|
||||||
|
- Status of blood pressure calibration (06.11.2019)
|
||||||
|
* it's used in blood pressure measurement
|
||||||
|
- Blood pressure calibration (09.11.2019)
|
||||||
|
|
||||||
|
Device settings
|
||||||
|
- Lift wrist to screen on [on, off,TODO scheduled] (02.11.2019)
|
||||||
|
- Change time format 12/24h (02.11.2019)
|
||||||
|
- Disconnect reminder [on, off,TODO scheduled] (02.11.2019)
|
||||||
|
- Find my phone [on, off, ring duration] (02.11.2019)
|
||||||
|
- Set watch modes (energy saving) (10.11.2019) (Need testing)
|
||||||
|
- Normal -> the watch work normally
|
||||||
|
- Power-saving mode -> the app turn off the bluetooth on the watch
|
||||||
|
- Trad-watch mode -> the watch only works as an analog one
|
||||||
|
- Do not disturb [on, off, scheduled] (10.11.2019) (need reconnect to apply)
|
||||||
|
- Send User details to watch [height, weight, age, gender] (10.11.2019) (need more testing)
|
||||||
|
- Implemented long sit reminder (inactivity reminder)[on, off, period] (17.11.2019)
|
||||||
|
- Set watch language [English, Chinese] (17.11.2019)
|
||||||
|
- Set watch units (metric/imperial) (17.11.2019)
|
||||||
|
- Redesign Device Settings (19.11.2019)
|
||||||
|
|
||||||
|
Activity data
|
||||||
|
- get steps per day
|
||||||
|
- get heart rate measurements
|
||||||
|
- get sleep data
|
||||||
|
- set user goal for steps
|
||||||
|
|
||||||
|
Send weather
|
||||||
|
- Send weather icon (17.11.2019)
|
||||||
|
Changed in app device icon (02.11.2019)
|
||||||
|
Get blood pressure measurement result (work only if blood pressure is calibrated)
|
||||||
|
Pairing activity
|
@@ -63,7 +63,8 @@ public class Watch9DeviceCoordinator extends AbstractDeviceCoordinator {
|
|||||||
String deviceName = candidate.getName().toUpperCase();
|
String deviceName = candidate.getName().toUpperCase();
|
||||||
if (candidate.supportsService(Watch9Constants.UUID_SERVICE_WATCH9)) {
|
if (candidate.supportsService(Watch9Constants.UUID_SERVICE_WATCH9)) {
|
||||||
return DeviceType.WATCH9;
|
return DeviceType.WATCH9;
|
||||||
} else if (macAddress.startsWith("1C:87:79")) {
|
// add support for Watch X non-plus (same MAC address)
|
||||||
|
} else if ((macAddress.startsWith("1C:87:79")) && (!deviceName.equalsIgnoreCase("WATCH X"))) {
|
||||||
return DeviceType.WATCH9;
|
return DeviceType.WATCH9;
|
||||||
} else if (deviceName.equals("WATCH 9")) {
|
} else if (deviceName.equals("WATCH 9")) {
|
||||||
return DeviceType.WATCH9;
|
return DeviceType.WATCH9;
|
||||||
|
@@ -71,6 +71,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.NotificationFilterEntry;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.entities.NotificationFilterEntryDao;
|
import nodomain.freeyourgadget.gadgetbridge.entities.NotificationFilterEntryDao;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.AppNotificationType;
|
import nodomain.freeyourgadget.gadgetbridge.model.AppNotificationType;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||||
@@ -255,9 +256,12 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldIgnore(sbn)) {
|
if (shouldIgnore(sbn)) {
|
||||||
LOG.info("Ignore notification");
|
if (!"com.sec.android.app.clockpackage".equals(sbn.getPackageName())) { // workaround to allow phone alarm notification
|
||||||
return;
|
LOG.info("Ignore notification: " + sbn.getPackageName()); // need to fix
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (GBApplication.getGrantedInterruptionFilter()) {
|
switch (GBApplication.getGrantedInterruptionFilter()) {
|
||||||
@@ -682,7 +686,6 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
if (!isServiceRunning() || sbn == null) {
|
if (!isServiceRunning() || sbn == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return shouldIgnoreSource(sbn.getPackageName()) || shouldIgnoreNotification(
|
return shouldIgnoreSource(sbn.getPackageName()) || shouldIgnoreNotification(
|
||||||
sbn.getNotification(), sbn.getPackageName());
|
sbn.getNotification(), sbn.getPackageName());
|
||||||
|
|
||||||
@@ -726,8 +729,9 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
|
|
||||||
MediaSessionCompat.Token mediaSession = getMediaSession(notification);
|
MediaSessionCompat.Token mediaSession = getMediaSession(notification);
|
||||||
//try to handle media session notifications
|
//try to handle media session notifications
|
||||||
if (mediaSession != null && handleMediaSessionNotification(mediaSession))
|
if (mediaSession != null && handleMediaSessionNotification(mediaSession)) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
NotificationType type = AppNotificationType.getInstance().get(source);
|
NotificationType type = AppNotificationType.getInstance().get(source);
|
||||||
//ignore notifications marked as LocalOnly https://developer.android.com/reference/android/app/Notification.html#FLAG_LOCAL_ONLY
|
//ignore notifications marked as LocalOnly https://developer.android.com/reference/android/app/Notification.html#FLAG_LOCAL_ONLY
|
||||||
@@ -748,7 +752,6 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (notification.flags & Notification.FLAG_ONGOING_EVENT) == Notification.FLAG_ONGOING_EVENT;
|
return (notification.flags & Notification.FLAG_ONGOING_EVENT) == Notification.FLAG_ONGOING_EVENT;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -56,6 +56,8 @@ public enum DeviceType {
|
|||||||
ZETIME(80, R.drawable.ic_device_zetime, R.drawable.ic_device_zetime_disabled, R.string.devicetype_mykronoz_zetime),
|
ZETIME(80, R.drawable.ic_device_zetime, R.drawable.ic_device_zetime_disabled, R.string.devicetype_mykronoz_zetime),
|
||||||
ID115(90, R.drawable.ic_device_h30_h10, R.drawable.ic_device_h30_h10_disabled, R.string.devicetype_id115),
|
ID115(90, R.drawable.ic_device_h30_h10, R.drawable.ic_device_h30_h10_disabled, R.string.devicetype_id115),
|
||||||
WATCH9(100, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_watch9),
|
WATCH9(100, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_watch9),
|
||||||
|
WATCHX(101, R.drawable.ic_device_watchxplus, R.drawable.ic_device_watchxplus_disabled, R.string.devicetype_watchx),
|
||||||
|
WATCHXPLUS(102, R.drawable.ic_device_watchxplus, R.drawable.ic_device_watchxplus_disabled, R.string.devicetype_watchxplus),
|
||||||
ROIDMI(110, R.drawable.ic_device_roidmi, R.drawable.ic_device_roidmi_disabled, R.string.devicetype_roidmi),
|
ROIDMI(110, R.drawable.ic_device_roidmi, R.drawable.ic_device_roidmi_disabled, R.string.devicetype_roidmi),
|
||||||
ROIDMI3(112, R.drawable.ic_device_roidmi, R.drawable.ic_device_roidmi_disabled, R.string.devicetype_roidmi3),
|
ROIDMI3(112, R.drawable.ic_device_roidmi, R.drawable.ic_device_roidmi_disabled, R.string.devicetype_roidmi3),
|
||||||
CASIOGB6900(120, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_casiogb6900),
|
CASIOGB6900(120, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_casiogb6900),
|
||||||
|
@@ -57,6 +57,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSuppo
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.roidmi.RoidmiSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.roidmi.RoidmiSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.vibratissimo.VibratissimoSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.vibratissimo.VibratissimoSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.watch9.Watch9DeviceSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.watch9.Watch9DeviceSupport;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lenovo.watchxplus.WatchXPlusDeviceSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.xwatch.XWatchSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.xwatch.XWatchSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.zetime.ZeTimeDeviceSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.zetime.ZeTimeDeviceSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
@@ -197,6 +198,9 @@ public class DeviceSupportFactory {
|
|||||||
case WATCH9:
|
case WATCH9:
|
||||||
deviceSupport = new ServiceDeviceSupport(new Watch9DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
deviceSupport = new ServiceDeviceSupport(new Watch9DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||||
break;
|
break;
|
||||||
|
case WATCHXPLUS:
|
||||||
|
deviceSupport = new ServiceDeviceSupport(new WatchXPlusDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||||
|
break;
|
||||||
case ROIDMI:
|
case ROIDMI:
|
||||||
deviceSupport = new ServiceDeviceSupport(new RoidmiSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
deviceSupport = new ServiceDeviceSupport(new RoidmiSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||||
break;
|
break;
|
||||||
|
@@ -0,0 +1,92 @@
|
|||||||
|
/* Copyright (C) 2018-2019 maxirnilian
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.lenovo.operations;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothGatt;
|
||||||
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lenovo.watchxplus.WatchXPlusConstants;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.watch9.Watch9Constants;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEOperation;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lenovo.watchxplus.WatchXPlusDeviceSupport;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
|
public class InitOperation extends AbstractBTLEOperation<WatchXPlusDeviceSupport>{
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(InitOperation.class);
|
||||||
|
|
||||||
|
private final TransactionBuilder builder;
|
||||||
|
private final boolean needsAuth;
|
||||||
|
private final BluetoothGattCharacteristic cmdCharacteristic = getCharacteristic(WatchXPlusConstants.UUID_CHARACTERISTIC_WRITE);
|
||||||
|
private final BluetoothGattCharacteristic dbCharacteristic = getCharacteristic(WatchXPlusConstants.UUID_CHARACTERISTIC_DATABASE_READ);
|
||||||
|
|
||||||
|
public InitOperation(boolean needsAuth, WatchXPlusDeviceSupport support, TransactionBuilder builder) {
|
||||||
|
super(support);
|
||||||
|
this.needsAuth = needsAuth;
|
||||||
|
this.builder = builder;
|
||||||
|
builder.setGattCallback(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doPerform() throws IOException {
|
||||||
|
builder.notify(cmdCharacteristic, true).notify(dbCharacteristic, true);
|
||||||
|
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.AUTHENTICATING, getContext()));
|
||||||
|
getSupport().authorizationRequest(builder, needsAuth);
|
||||||
|
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
|
||||||
|
getSupport().initialize(builder);
|
||||||
|
getSupport().performImmediately(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCharacteristicChanged(BluetoothGatt gatt,
|
||||||
|
BluetoothGattCharacteristic characteristic) {
|
||||||
|
UUID characteristicUUID = characteristic.getUuid();
|
||||||
|
if (Watch9Constants.UUID_CHARACTERISTIC_WRITE.equals(characteristicUUID) && needsAuth) {
|
||||||
|
try {
|
||||||
|
byte[] value = characteristic.getValue();
|
||||||
|
getSupport().logMessageContent(value);
|
||||||
|
if (ArrayUtils.equals(value, Watch9Constants.RESP_AUTHORIZATION_TASK, 5) && value[8] == 0x01) {
|
||||||
|
TransactionBuilder builder = getSupport().createTransactionBuilder("authInit");
|
||||||
|
builder.setGattCallback(this);
|
||||||
|
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
|
||||||
|
getSupport().initialize(builder).performImmediately(builder);
|
||||||
|
} else {
|
||||||
|
return super.onCharacteristicChanged(gatt, characteristic);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
GB.toast(getContext(), "Error authenticating Watch X Plus", Toast.LENGTH_LONG, GB.ERROR, e);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
LOG.info("Unhandled characteristic changed: " + characteristicUUID);
|
||||||
|
return super.onCharacteristicChanged(gatt, characteristic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@@ -65,7 +65,6 @@ public class XWatchSupport extends AbstractBTLEDeviceSupport {
|
|||||||
private static final Logger LOG = LoggerFactory.getLogger(XWatchSupport.class);
|
private static final Logger LOG = LoggerFactory.getLogger(XWatchSupport.class);
|
||||||
private final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo();
|
private final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo();
|
||||||
TransactionBuilder builder = null;
|
TransactionBuilder builder = null;
|
||||||
private DeviceInfo mDeviceInfo;
|
|
||||||
private byte dayToFetch; //0 = Today; 1 = Yesterday ...
|
private byte dayToFetch; //0 = Today; 1 = Yesterday ...
|
||||||
private byte maxDayToFetch;
|
private byte maxDayToFetch;
|
||||||
long lastButtonTimestamp;
|
long lastButtonTimestamp;
|
||||||
@@ -359,7 +358,7 @@ public class XWatchSupport extends AbstractBTLEDeviceSupport {
|
|||||||
|
|
||||||
private void handleDeviceInfo(byte[] value, int status) {
|
private void handleDeviceInfo(byte[] value, int status) {
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
mDeviceInfo = new DeviceInfo(value);
|
DeviceInfo mDeviceInfo = new DeviceInfo(value);
|
||||||
LOG.warn("Device info: " + mDeviceInfo);
|
LOG.warn("Device info: " + mDeviceInfo);
|
||||||
versionCmd.hwVersion = "1.0";
|
versionCmd.hwVersion = "1.0";
|
||||||
versionCmd.fwVersion = "1.0";
|
versionCmd.fwVersion = "1.0";
|
||||||
|
@@ -72,6 +72,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.QHybridCoordinator;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.devices.roidmi.Roidmi1Coordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.roidmi.Roidmi1Coordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.roidmi.Roidmi3Coordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.roidmi.Roidmi3Coordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.vibratissimo.VibratissimoCoordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.vibratissimo.VibratissimoCoordinator;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lenovo.watchxplus.WatchXPlusDeviceCoordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.watch9.Watch9DeviceCoordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.watch9.Watch9DeviceCoordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.xwatch.XWatchCoordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.xwatch.XWatchCoordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.zetime.ZeTimeCoordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.zetime.ZeTimeCoordinator;
|
||||||
@@ -232,6 +233,7 @@ public class DeviceHelper {
|
|||||||
result.add(new ZeTimeCoordinator());
|
result.add(new ZeTimeCoordinator());
|
||||||
result.add(new ID115Coordinator());
|
result.add(new ID115Coordinator());
|
||||||
result.add(new Watch9DeviceCoordinator());
|
result.add(new Watch9DeviceCoordinator());
|
||||||
|
result.add(new WatchXPlusDeviceCoordinator());
|
||||||
result.add(new Roidmi1Coordinator());
|
result.add(new Roidmi1Coordinator());
|
||||||
result.add(new Roidmi3Coordinator());
|
result.add(new Roidmi3Coordinator());
|
||||||
result.add(new CasioGB6900DeviceCoordinator());
|
result.add(new CasioGB6900DeviceCoordinator());
|
||||||
|
@@ -1,5 +1,22 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
<string name="pref_display_add_device_fab">Бутон за ново устройство</string>
|
||||||
|
<string name="pref_display_add_device_fab_on">Винаги видим</string>
|
||||||
|
<string name="pref_display_add_device_fab_off">Видим само ако няма свързано устройство</string>
|
||||||
|
<string name="language_and_region_prefs">Език и регион</string>
|
||||||
|
<string name="activity_prefs_about_you">За Вас</string>
|
||||||
|
<string name="activity_prefs_year_birth">Година на раждане</string>
|
||||||
|
<string name="activity_prefs_gender">Пол</string>
|
||||||
|
<string name="activity_prefs_height_cm">Височина в cm</string>
|
||||||
|
<string name="activity_prefs_weight_kg">Тегло в kg</string>
|
||||||
|
<string name="pref_header_charts">Настройки на Графиката</string>
|
||||||
|
<string name="pref_title_charts_average">Показвай средни стойности</string>
|
||||||
|
<string name="activity_prefs_charts">Настройки на графика</string>
|
||||||
|
<string name="activity_prefs_chart_max_heart_rate">Max сърдечен ритъм</string>
|
||||||
|
<string name="activity_prefs_chart_min_heart_rate">Min сърдечен ритъм</string>
|
||||||
|
<string name="pref_title_charts_range">Обхват на Графиката</string>
|
||||||
|
<string name="pref_charts_range_on">Обхвата е Месец</string>
|
||||||
|
<string name="pref_charts_range_off">Обхвата е Седмица</string>
|
||||||
<string name="app_name">Gadgetbridge</string>
|
<string name="app_name">Gadgetbridge</string>
|
||||||
<string name="title_activity_controlcenter">Gadgetbridge</string>
|
<string name="title_activity_controlcenter">Gadgetbridge</string>
|
||||||
<string name="action_settings">Настройки</string>
|
<string name="action_settings">Настройки</string>
|
||||||
@@ -30,6 +47,12 @@
|
|||||||
<string name="appmanager_cached_watchapps_watchfaces">Приложения в кеша</string>
|
<string name="appmanager_cached_watchapps_watchfaces">Приложения в кеша</string>
|
||||||
<string name="appmanager_installed_watchapps">Инсталирани приложения</string>
|
<string name="appmanager_installed_watchapps">Инсталирани приложения</string>
|
||||||
<string name="appmanager_installed_watchfaces">Инсталирани циферблати</string>
|
<string name="appmanager_installed_watchfaces">Инсталирани циферблати</string>
|
||||||
|
<string name="mi2_prefs_activate_display_on_lift">Включи екрана при вдигане</string>
|
||||||
|
<string name="prefs_disconnect_notification">Известие при прекъсване</string>
|
||||||
|
<string name="prefs_find_phone">Намери телефона</string>
|
||||||
|
<string name="prefs_enable_find_phone">Включи намиране на телефона</string>
|
||||||
|
<string name="prefs_find_phone_summary">Използвайте устройството, за да накарате телефона да звъни.</string>
|
||||||
|
<string name="prefs_find_phone_duration">Звънене - секунди</string>
|
||||||
<string name="appmananger_app_delete">Изтриване</string>
|
<string name="appmananger_app_delete">Изтриване</string>
|
||||||
<string name="appmananger_app_delete_cache">Изтриване и премахване от кеша</string>
|
<string name="appmananger_app_delete_cache">Изтриване и премахване от кеша</string>
|
||||||
<string name="appmananger_app_reinstall">Преинсталиране</string>
|
<string name="appmananger_app_reinstall">Преинсталиране</string>
|
||||||
@@ -253,6 +276,51 @@
|
|||||||
<string name="miband_prefs_alias">Име/Псевдоним</string>
|
<string name="miband_prefs_alias">Име/Псевдоним</string>
|
||||||
<string name="pref_header_vibration_count">Брой на вибрациите</string>
|
<string name="pref_header_vibration_count">Брой на вибрациите</string>
|
||||||
<string name="watch9_pairing_tap_hint">Когато часовникът завибрира, разклатете устройството или натиснете бутона</string>
|
<string name="watch9_pairing_tap_hint">Когато часовникът завибрира, разклатете устройството или натиснете бутона</string>
|
||||||
|
<string name="watch9_time_minutes">Минути:</string>
|
||||||
|
<string name="watch9_time_hours">Часове:</string>
|
||||||
|
<string name="watch9_time_seconds">Секунди:</string>
|
||||||
|
<string name="watch9_calibration_hint">Задайте времето, което показва устройството Ви.</string>
|
||||||
|
<string name="watch9_calibration_button">Сверяване</string>
|
||||||
|
<string name="title_activity_watch9_pairing">Watch 9 свързване</string>
|
||||||
|
<string name="title_activity_watch9_calibration">Watch 9 сверяване</string>
|
||||||
|
|
||||||
|
<string name="title_activity_watchXplus_calibration">Watch X Plus сверяване</string>
|
||||||
|
<string name="pref_wxp_title_unit_system">Единици</string>
|
||||||
|
<string name="pref_wxp_title_timeformat">Формат на часа</string>
|
||||||
|
<string name="pref_wxp_title_altitude">Калибриране на височината</string>
|
||||||
|
<string name="pref_wxp_title_repeat_on_call">Повтаряй известие за позвъняване</string>
|
||||||
|
<string name="pref_wxp_title_repeat_on_call_summary">Възможни стойности min=0, max=10</string>
|
||||||
|
<string name="prefs_wxp_continious">Известявай докато телефона звъни</string>
|
||||||
|
<string name="prefs_wxp_missed">Известие за пропуснато обаждане</string>
|
||||||
|
<string name="preferences_watchxplus_settings">Watch X Plus настройки</string>
|
||||||
|
<string name="pref_header_wxp_notification_call">Известия при обаждане</string>
|
||||||
|
<string name="pref_header_wxp_notification_misscall">Известия при пропуснато обаждане</string>
|
||||||
|
<string name="pref_wxp_title_reject_summary">Изкл. - заглуши, Вкл. - откажи</string>
|
||||||
|
<string name="prefs_wxp_reject">Бутона заглушава/отказва повикване</string>
|
||||||
|
<string name="pref_wxp_title_shake_reject_summary">Повтаря действието на бутона</string>
|
||||||
|
<string name="prefs_wxp_shake_reject">Разклати за заглушаване/отказване на повикването</string>
|
||||||
|
<string name="wxp_bp_calibration_prefs">Калибриране на кръвно налягане</string>
|
||||||
|
<string name="pref_wxp_bp_calibration_low">Кръвно налягане DIASTOLIC (ниска)</string>
|
||||||
|
<string name="pref_wxp_bp_calibration_high">Кръвно налягане SYSTOLIC (висока)</string>
|
||||||
|
<string name="prefs_wxp_button_bp_calibration">Калибриране</string>
|
||||||
|
<string name="prefs_wxp_button_bp_calibration_sum">Натисни тук за калибриране</string>
|
||||||
|
<string name="pref_header_wxp_calibration">Калибриране на сензорите</string>
|
||||||
|
<string name="pref_header_wxp_settings">Настройки на устройството</string>
|
||||||
|
<string name="wxp_power_mode_title">Режим на часовника</string>
|
||||||
|
<string name="wxp_mode_normal">Нормален</string>
|
||||||
|
<string name="wxp_mode_saving">Икономичен</string>
|
||||||
|
<string name="wxp_mode_watch">Само часовник</string>
|
||||||
|
<string name="pref_wxp_title_repeat_on_misscall_summary">Повтаряй известие за пропуснато повикване всяка минута за X пъти</string>
|
||||||
|
<string name="pref_wxp_title_repeat_on_misscall">Повтаряй известието за пропуснато повикване</string>
|
||||||
|
<string name="pref_header_wxp_notification_callhandling">Управление на обажданията</string>
|
||||||
|
<string name="pref_header_wxp_longsit">Напомняне за бездействие</string>
|
||||||
|
<string name="pref_wxp_longsit_period_summary">Напомняй ако няма активност за повече от X минути</string>
|
||||||
|
<string name="pref_wxp_longsit_switch_summary">Времевия интервал е от настройката за DND</string>
|
||||||
|
<string name="prefs_wxp_longsit_switch">Включи напомняне за активност</string>
|
||||||
|
<string name="pref_wxp_title_longsit">Период на неактивност (минути)</string>
|
||||||
|
<string name="wxp_language_title">Език</string>
|
||||||
|
<string name="pref_header_wxp_call_notification">Известия и Обаждания</string>
|
||||||
|
|
||||||
<string name="title_activity_sleepmonitor">Наблюдение/анализ на съня</string>
|
<string name="title_activity_sleepmonitor">Наблюдение/анализ на съня</string>
|
||||||
<string name="pref_write_logfiles">Съхраняване на log файлове</string>
|
<string name="pref_write_logfiles">Съхраняване на log файлове</string>
|
||||||
<string name="initializing">Инициализиране</string>
|
<string name="initializing">Инициализиране</string>
|
||||||
@@ -420,4 +488,113 @@
|
|||||||
<string name="title_activity_device_specific_settings">Специфични настройки за устройството</string>
|
<string name="title_activity_device_specific_settings">Специфични настройки за устройството</string>
|
||||||
<string name="average">Средно: %1$s</string>
|
<string name="average">Средно: %1$s</string>
|
||||||
<string name="mi2_prefs_button_press_broadcast_default_value" translatable="false">nodomain.freeyourgadget.gadgetbridge.ButtonPressed</string>
|
<string name="mi2_prefs_button_press_broadcast_default_value" translatable="false">nodomain.freeyourgadget.gadgetbridge.ButtonPressed</string>
|
||||||
|
<string name="Cancel">Отказ</string>
|
||||||
|
<string name="Delete">Изтрий</string>
|
||||||
|
<string name="abstract_chart_fragment_kind_deep_sleep">Дълбок сън</string>
|
||||||
|
<string name="abstract_chart_fragment_kind_light_sleep">Лек сън</string>
|
||||||
|
<string name="abstract_chart_fragment_kind_not_worn">Не е носен</string>
|
||||||
|
<string name="abstract_chart_fragment_kind_activity">Активност</string>
|
||||||
|
<string name="_pebble_watch_reply">Отговори</string>
|
||||||
|
<string name="action_db_management">Управление на базата</string>
|
||||||
|
<string name="activity_DB_empty_button">Изчисти БД</string>
|
||||||
|
<string name="activity_DB_import_button">Импорт БД</string>
|
||||||
|
<string name="activity_DB_delete_legacy_button">Изтрий стара БД</string>
|
||||||
|
<string name="activity_DB_ExportButton">Експорт на БД</string>
|
||||||
|
<string name="activity_DB_test_export_message">Експортиране на БД...</string>
|
||||||
|
<string name="activity_DB_test_export_button">Стартирай авто експортиране</string>
|
||||||
|
<string name="activity_db_management_autoexport_explanation">Локацията за експорт на БД е:</string>
|
||||||
|
<string name="activity_db_management_autoexport_label">АвтоЕкспорт</string>
|
||||||
|
<string name="activity_db_management_empty_DB">ИзпразниБД</string>
|
||||||
|
<string name="activity_db_management_empty_db_warning">Внимание! Ако натиснете този бутон БД ще се изтрие.</string>
|
||||||
|
<string name="activity_db_management_exportimport_label">Експорт и Импорт</string>
|
||||||
|
<string name="activity_prefs_sleep_duration">Време за сън в часове</string>
|
||||||
|
<string name="activity_summaries">Активности</string>
|
||||||
|
<string name="activity_type_activity">Активност</string>
|
||||||
|
<string name="activity_type_biking">Колоездене</string>
|
||||||
|
<string name="activity_type_deep_sleep">Дълбок сън</string>
|
||||||
|
<string name="activity_type_light_sleep">Лек сън</string>
|
||||||
|
<string name="activity_type_exercise">Упражнение</string>
|
||||||
|
<string name="activity_type_not_measured">Не е измерено</string>
|
||||||
|
<string name="activity_type_not_worn">Не е носено</string>
|
||||||
|
<string name="activity_type_running">Бягане</string>
|
||||||
|
<string name="activity_type_swimming">Плуване</string>
|
||||||
|
<string name="activity_type_unknown">Неизвестна активност</string>
|
||||||
|
<string name="activity_type_walking">Ходене</string>
|
||||||
|
<string name="appwidget_not_connected">Не е свързан, алармата не е настроена.</string>
|
||||||
|
<string name="appwidget_setting_alarm">Аларма за %1$02d:%2$02d</string>
|
||||||
|
<string name="automatic">Автоматично</string>
|
||||||
|
<string name="authenticating">Удостоверяване</string>
|
||||||
|
<string name="authentication_required">Изисква удостоверяване</string>
|
||||||
|
<string name="charts_legend_heartrate">Сърдечна честота</string>
|
||||||
|
<string name="choose_auto_export_location">Избери локация за експорт</string>
|
||||||
|
<string name="dateformat_time">Час</string>
|
||||||
|
<string name="dbmanagementactivity_overwrite">Замени</string>
|
||||||
|
<string name="device_fw">Firmware версия: %1$s</string>
|
||||||
|
<string name="device_hw">Hardware версия: %1$s</string>
|
||||||
|
<string name="device_not_connected">Не е свързан.</string>
|
||||||
|
<string name="devicetype_unknown">Неизвестно устройство</string>
|
||||||
|
<string name="discovery_attempting_to_pair">Опит за свързване с %1$s</string>
|
||||||
|
<string name="discovery_dont_pair">Не се свързвай</string>
|
||||||
|
<string name="discovery_enable_bluetooth">Включи bluetooth за намиране на устройства.</string>
|
||||||
|
<string name="discovery_pair_title">Свързване с %1$s?</string>
|
||||||
|
<string name="discovery_trying_to_connect_to">Опит за свързване с: %1$s</string>
|
||||||
|
<string name="discovery_yes_pair">Свържи</string>
|
||||||
|
<string name="filter_mode_none">Не филтрирай</string>
|
||||||
|
<string name="find_device_you_found_it">Намери ме!</string>
|
||||||
|
<string name="kind_font">Шрифт</string>
|
||||||
|
<string name="kind_invalid">Невалидни данни</string>
|
||||||
|
<string name="live_activity_heart_rate">Сърдечен ритъм</string>
|
||||||
|
<string name="maximum_duration">Продължителност</string>
|
||||||
|
<string name="menuitem_alarm">Аларма</string>
|
||||||
|
<string name="menuitem_activity">Активност</string>
|
||||||
|
<string name="menuitem_compass">Компас</string>
|
||||||
|
<string name="menuitem_music">Музика</string>
|
||||||
|
<string name="menuitem_settings">Настройки</string>
|
||||||
|
<string name="menuitem_notifications">Известия</string>
|
||||||
|
<string name="menuitem_weather">Прогноза за време</string>
|
||||||
|
<string name="menuitem_timer">Таймер</string>
|
||||||
|
<string name="mi2_dnd_off">Изкл.</string>
|
||||||
|
<string name="mi2_dnd_scheduled">Разписание</string>
|
||||||
|
<string name="mi2_prefs_do_not_disturb_end">Край</string>
|
||||||
|
<string name="mi2_prefs_do_not_disturb_start">Начало</string>
|
||||||
|
<string name="mi2_prefs_do_not_disturb">Не безпокой</string>
|
||||||
|
<string name="you_slept">Вие спахте от %1$s до %2$s</string>
|
||||||
|
<string name="widget_steps_label">Стъпки: %1$02d</string>
|
||||||
|
<string name="widget_sleep_label">Сън: %1$s</string>
|
||||||
|
<string name="widget_5_minutes">5 минути</string>
|
||||||
|
<string name="widget_20_minutes">20 минути</string>
|
||||||
|
<string name="widget_1_hour">1 час</string>
|
||||||
|
<string name="widget_10_minutes">10 минути</string>
|
||||||
|
<string name="weekstepschart_steps_a_month">Крачки за месец</string>
|
||||||
|
<string name="weeksleepchart_sleep_a_month">Сън за месец</string>
|
||||||
|
<string name="warning">Внимание!</string>
|
||||||
|
<string name="waiting_for_reconnect">Изчаква свързване</string>
|
||||||
|
<string name="user_feedback_all_alarms_disabled">Всички аларми са изключени</string>
|
||||||
|
<string name="unit_metric">Метрична</string>
|
||||||
|
<string name="unit_imperial">Инчова</string>
|
||||||
|
<string name="toast_notification_filter_words_empty_hint">Въведете поне една дума</string>
|
||||||
|
<string name="toast_notification_filter_saved_successfully">Филтъра за известия е запазен</string>
|
||||||
|
<string name="title_activity_vibration">Вибрация</string>
|
||||||
|
<string name="title_activity_notification_filter">Филтър за известия</string>
|
||||||
|
<string name="title_activity_db_management">Управление на БД</string>
|
||||||
|
<string name="select_all">Избери всички</string>
|
||||||
|
<string name="share">Сподели</string>
|
||||||
|
<string name="save_configuration">Запази настройките</string>
|
||||||
|
<string name="prefs_hr_alarm_high">Горна граница</string>
|
||||||
|
<string name="prefs_hr_alarm_low">Долна граница</string>
|
||||||
|
<string name="preferences_rtl_settings">От ляво на дясно</string>
|
||||||
|
<string name="pref_screen_notification_profile_alarm_clock">Аларми</string>
|
||||||
|
<string name="p_unit_metric">метрични</string>
|
||||||
|
<string name="p_unit_imperial">инчови</string>
|
||||||
|
<string name="p_steps">крачки</string>
|
||||||
|
<string name="p_scheduled">разписание</string>
|
||||||
|
<string name="p_pebble_privacy_mode_off">изкл.</string>
|
||||||
|
<string name="p_on">вкл.</string>
|
||||||
|
<string name="p_off">изкл.</string>
|
||||||
|
<string name="p_menuitem_weather">прогноза</string>
|
||||||
|
<string name="p_menuitem_settings">настройки</string>
|
||||||
|
<string name="p_menuitem_notifications">известия</string>
|
||||||
|
<string name="off">Изкл.</string>
|
||||||
|
<string name="on">Вкл.</string>
|
||||||
|
<string name="no_data">Няма данни</string>
|
||||||
</resources>
|
</resources>
|
@@ -69,6 +69,33 @@
|
|||||||
<item>never</item>
|
<item>never</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="wxp_language">
|
||||||
|
<item name="0">@string/simplified_chinese</item>
|
||||||
|
<item name="1">@string/english</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="wxp_language_values">
|
||||||
|
<item>0</item>
|
||||||
|
<item>1</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="wxp_bp_cal">
|
||||||
|
<item name="0">@string/prefs_wxp_button_bp_calibration</item>
|
||||||
|
<item name="1">@string/Cancel</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="wxp_bp_cal_values">
|
||||||
|
<item>0</item>
|
||||||
|
<item>1</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="wxp_mode">
|
||||||
|
<item name="0">@string/wxp_mode_normal</item>
|
||||||
|
<item name="1">@string/wxp_mode_saving</item>
|
||||||
|
<item name="2">@string/wxp_mode_watch</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="wxp_mode_values">
|
||||||
|
<item>0</item>
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<string-array name="gender">
|
<string-array name="gender">
|
||||||
<item name="1">@string/male</item>
|
<item name="1">@string/male</item>
|
||||||
<item name="0">@string/female</item>
|
<item name="0">@string/female</item>
|
||||||
|
@@ -189,6 +189,44 @@
|
|||||||
<string name="pref_title_screentime">Screen on duration</string>
|
<string name="pref_title_screentime">Screen on duration</string>
|
||||||
<string name="prefs_title_all_day_heart_rate">All day heart rate measurement</string>
|
<string name="prefs_title_all_day_heart_rate">All day heart rate measurement</string>
|
||||||
<string name="preferences_hplus_settings">HPlus/Makibes settings</string>
|
<string name="preferences_hplus_settings">HPlus/Makibes settings</string>
|
||||||
|
<!-- WatchXPlus Preferences -->
|
||||||
|
<string name="title_activity_watchXplus_calibration">Watch X Plus calibration</string>
|
||||||
|
<string name="pref_wxp_title_unit_system">Units</string>
|
||||||
|
<string name="pref_wxp_title_timeformat">Time format</string>
|
||||||
|
<string name="pref_wxp_title_altitude">Altitude calibration</string>
|
||||||
|
<string name="pref_wxp_title_repeat_on_call">Repeat call notification</string>
|
||||||
|
<string name="pref_wxp_title_repeat_on_call_summary">Possible values min=0, max=10</string>
|
||||||
|
<string name="prefs_wxp_continious">Vibration during phone ring</string>
|
||||||
|
<string name="prefs_wxp_missed">Vibration on missed call</string>
|
||||||
|
<string name="preferences_watchxplus_settings">Watch X Plus settings</string>
|
||||||
|
<string name="pref_header_wxp_call_notification">Notifications and Calls</string>
|
||||||
|
<string name="pref_header_wxp_notification_call">Call notifications</string>
|
||||||
|
<string name="pref_header_wxp_notification_misscall">MissCall notifications</string>
|
||||||
|
<string name="pref_wxp_title_reject_summary">Off - ignore, On - reject</string>
|
||||||
|
<string name="prefs_wxp_reject">Button ignore/reject call</string>
|
||||||
|
<string name="pref_wxp_title_shake_reject_summary">Duplicates watch button action</string>
|
||||||
|
<string name="prefs_wxp_shake_reject">Shake wrist ignore/reject call</string>
|
||||||
|
<string name="wxp_bp_calibration_prefs">Blood Pressure calibration</string>
|
||||||
|
<string name="pref_wxp_bp_calibration_low">Blood Pressure DIASTOLIC (low)</string>
|
||||||
|
<string name="pref_wxp_bp_calibration_high">Blood Pressure SYSTOLIC (high)</string>
|
||||||
|
<string name="prefs_wxp_button_bp_calibration">Calibration</string>
|
||||||
|
<string name="prefs_wxp_button_bp_calibration_sum">Press here to begin calibration</string>
|
||||||
|
<string name="pref_header_wxp_calibration">Sensors Calibration</string>
|
||||||
|
<string name="pref_header_wxp_settings">Device settings</string>
|
||||||
|
<string name="wxp_power_mode_title">Watch mode</string>
|
||||||
|
<string name="wxp_mode_normal">Normal</string>
|
||||||
|
<string name="wxp_mode_saving">Power saving</string>
|
||||||
|
<string name="wxp_mode_watch">Only watch</string>
|
||||||
|
<string name="pref_wxp_title_repeat_on_misscall_summary">Repeat missed call notification every minute for X times</string>
|
||||||
|
<string name="pref_wxp_title_repeat_on_misscall">Repeat missed call notification</string>
|
||||||
|
<string name="pref_header_wxp_notification_callhandling">Call Handling</string>
|
||||||
|
<string name="pref_header_wxp_longsit">Inactivity reminder</string>
|
||||||
|
<string name="pref_wxp_longsit_period_summary">Remind if there is no activity for more than X minutes</string>
|
||||||
|
<string name="pref_wxp_longsit_switch_summary">Inactivity time interval is from DND setting</string>
|
||||||
|
<string name="prefs_wxp_longsit_switch">Enable inactivity reminder</string>
|
||||||
|
<string name="pref_wxp_title_longsit">Inactivity period (minutes)</string>
|
||||||
|
<string name="wxp_language_title">Language</string>
|
||||||
|
|
||||||
<!-- Makibes HR3 Preferences -->
|
<!-- Makibes HR3 Preferences -->
|
||||||
<string name="preferences_makibes_hr3_settings">Makibes HR3 settings</string>
|
<string name="preferences_makibes_hr3_settings">Makibes HR3 settings</string>
|
||||||
<!-- ID115 Preferences -->
|
<!-- ID115 Preferences -->
|
||||||
@@ -683,6 +721,8 @@
|
|||||||
<string name="devicetype_mykronoz_zetime">MyKronoz ZeTime</string>
|
<string name="devicetype_mykronoz_zetime">MyKronoz ZeTime</string>
|
||||||
<string name="devicetype_id115">ID115</string>
|
<string name="devicetype_id115">ID115</string>
|
||||||
<string name="devicetype_watch9">Watch 9</string>
|
<string name="devicetype_watch9">Watch 9</string>
|
||||||
|
<string name="devicetype_watchx">Watch X</string>
|
||||||
|
<string name="devicetype_watchxplus">Watch X Plus</string>
|
||||||
<string name="devicetype_roidmi">Roidmi</string>
|
<string name="devicetype_roidmi">Roidmi</string>
|
||||||
<string name="devicetype_roidmi3">Roidmi 3</string>
|
<string name="devicetype_roidmi3">Roidmi 3</string>
|
||||||
<string name="devicetype_casiogb6900">Casio GB-6900</string>
|
<string name="devicetype_casiogb6900">Casio GB-6900</string>
|
||||||
|
@@ -580,6 +580,12 @@
|
|||||||
android:icon="@drawable/ic_device_zetime"
|
android:icon="@drawable/ic_device_zetime"
|
||||||
android:key="pref_key_zetime"
|
android:key="pref_key_zetime"
|
||||||
android:title="@string/zetime_title_settings"/>
|
android:title="@string/zetime_title_settings"/>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:icon="@drawable/ic_device_watchxplus"
|
||||||
|
android:key="pref_key_watchxplus"
|
||||||
|
android:title="@string/preferences_watchxplus_settings"/>
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
|
128
app/src/main/res/xml/watchxplus_preferences.xml
Normal file
128
app/src/main/res/xml/watchxplus_preferences.xml
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="pref_category_watchxplus_notification"
|
||||||
|
android:title="@string/pref_header_wxp_call_notification">
|
||||||
|
<PreferenceScreen
|
||||||
|
android:key="pref_category_watchxplus_ringing"
|
||||||
|
android:title="@string/pref_header_wxp_notification_call">
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="@string/pref_header_wxp_notification_call"/>
|
||||||
|
<EditTextPreference
|
||||||
|
android:defaultValue="0"
|
||||||
|
android:key="watchxplus_repeat"
|
||||||
|
android:summary="@string/pref_wxp_title_repeat_on_call_summary"
|
||||||
|
android:title="@string/pref_wxp_title_repeat_on_call"/>
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:layout="@layout/preference_checkbox"
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="watchxplus_continious"
|
||||||
|
android:title="@string/prefs_wxp_continious" />
|
||||||
|
</PreferenceScreen>
|
||||||
|
<PreferenceScreen
|
||||||
|
android:key="pref_category_watchxplus_miss"
|
||||||
|
android:title="@string/pref_header_wxp_notification_misscall">
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="@string/pref_header_wxp_notification_misscall"/>
|
||||||
|
<EditTextPreference
|
||||||
|
android:defaultValue="0"
|
||||||
|
android:key="watchxplus_repeat_missedcall"
|
||||||
|
android:summary="@string/pref_wxp_title_repeat_on_misscall_summary"
|
||||||
|
android:title="@string/pref_wxp_title_repeat_on_misscall"/>
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:layout="@layout/preference_checkbox"
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="watchxplus_missed"
|
||||||
|
android:title="@string/prefs_wxp_missed" />
|
||||||
|
</PreferenceScreen>
|
||||||
|
<PreferenceScreen
|
||||||
|
android:key="pref_category_watchxplus_callhandling"
|
||||||
|
android:title="@string/pref_header_wxp_notification_callhandling">
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="@string/pref_header_wxp_notification_callhandling"/>
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:layout="@layout/preference_checkbox"
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="watchxplus_button_reject"
|
||||||
|
android:summary="@string/pref_wxp_title_reject_summary"
|
||||||
|
android:title="@string/prefs_wxp_reject" />
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:layout="@layout/preference_checkbox"
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="watchxplus_shake_reject"
|
||||||
|
android:summary="@string/pref_wxp_title_shake_reject_summary"
|
||||||
|
android:title="@string/prefs_wxp_shake_reject" />
|
||||||
|
</PreferenceScreen>
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="pref_category_watchxplus_settings"
|
||||||
|
android:title="@string/pref_header_wxp_settings">
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue="0"
|
||||||
|
android:title="@string/wxp_power_mode_title"
|
||||||
|
android:entries="@array/wxp_mode"
|
||||||
|
android:entryValues="@array/wxp_mode_values"
|
||||||
|
android:key="pref_wxp_power_mode"
|
||||||
|
android:summary="%s" />
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue="1"
|
||||||
|
android:title="@string/pref_title_language"
|
||||||
|
android:entries="@array/wxp_language"
|
||||||
|
android:entryValues="@array/wxp_language_values"
|
||||||
|
android:key="pref_wxp_language"
|
||||||
|
android:summary="%s" />
|
||||||
|
<PreferenceScreen
|
||||||
|
android:key="pref_category_watchxplus_longsit_settings"
|
||||||
|
android:title="@string/pref_header_wxp_longsit">
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="@string/pref_header_wxp_longsit"/>
|
||||||
|
<EditTextPreference
|
||||||
|
android:defaultValue="60"
|
||||||
|
android:key="pref_watchxplus_longsit_period"
|
||||||
|
android:summary="@string/pref_wxp_longsit_period_summary"
|
||||||
|
android:title="@string/pref_wxp_title_longsit"/>
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:layout="@layout/preference_checkbox"
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="pref_watchxplus_longsit_switch"
|
||||||
|
android:summary="@string/pref_wxp_longsit_switch_summary"
|
||||||
|
android:title="@string/prefs_wxp_longsit_switch" />
|
||||||
|
</PreferenceScreen>
|
||||||
|
</PreferenceCategory>
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="pref_category_watchxplus_calibration"
|
||||||
|
android:title="@string/pref_header_wxp_calibration">
|
||||||
|
|
||||||
|
<EditTextPreference
|
||||||
|
android:defaultValue="200"
|
||||||
|
android:key="pref_watchxplus_altitude"
|
||||||
|
android:title="@string/pref_wxp_title_altitude"/>
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
android:key="wxp_bp_calibration"
|
||||||
|
android:title="@string/wxp_bp_calibration_prefs">
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="@string/wxp_bp_calibration_prefs"/>
|
||||||
|
<EditTextPreference
|
||||||
|
android:inputType="number"
|
||||||
|
android:key="pref_wxp_bp_calibration_low"
|
||||||
|
android:defaultValue="80"
|
||||||
|
android:title="@string/pref_wxp_bp_calibration_low"
|
||||||
|
android:summary="@string/pref_rtl_max_line_length_summary"/>
|
||||||
|
<EditTextPreference
|
||||||
|
android:inputType="number"
|
||||||
|
android:key="pref_wxp_bp_calibration_high"
|
||||||
|
android:defaultValue="130"
|
||||||
|
android:title="@string/pref_wxp_bp_calibration_high"
|
||||||
|
android:summary="@string/pref_rtl_max_line_length_summary"/>
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue="1"
|
||||||
|
android:title="@string/prefs_wxp_button_bp_calibration"
|
||||||
|
android:entries="@array/wxp_bp_cal"
|
||||||
|
android:entryValues="@array/wxp_bp_cal_values"
|
||||||
|
android:key="wxp_button_BP_calibration_list"
|
||||||
|
android:summary="@string/prefs_wxp_button_bp_calibration_sum" />
|
||||||
|
</PreferenceScreen>
|
||||||
|
</PreferenceCategory>
|
||||||
|
</PreferenceScreen>
|
Reference in New Issue
Block a user