diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/lenovo/watchxplus/WatchXPlusConstants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/lenovo/watchxplus/WatchXPlusConstants.java
index dfe3a641e..bc25a933e 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/lenovo/watchxplus/WatchXPlusConstants.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/lenovo/watchxplus/WatchXPlusConstants.java
@@ -36,7 +36,12 @@ public final class WatchXPlusConstants extends LenovoWatchConstants {
public static final String PREF_FIND_PHONE_DURATION = "prefs_find_phone_duration";
public static final String PREF_ALTITUDE = "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_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";
+
// time format constants
public static final byte ARG_SET_TIMEMODE_24H = 0x00;
@@ -71,6 +76,7 @@ public final class WatchXPlusConstants extends LenovoWatchConstants {
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_AUTHORIZATION_TASK = new byte[]{0x01, 0x01, 0x05};
public static final byte[] RESP_DAY_STEPS_INDICATOR = new byte[]{0x08, 0x10, 0x03};
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/lenovo/watchxplus/WatchXPlusDeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/lenovo/watchxplus/WatchXPlusDeviceCoordinator.java
index 71863c7e8..6814968fd 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/lenovo/watchxplus/WatchXPlusDeviceCoordinator.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/lenovo/watchxplus/WatchXPlusDeviceCoordinator.java
@@ -223,6 +223,14 @@ Prefs from device settings on main page
}
}
+ public static byte getBPCalibrationStatus(SharedPreferences sharedPrefs) {
+ String timeMode = sharedPrefs.getString(DeviceSettingsPreferenceConst.PREF_TIMEFORMAT, getContext().getString(R.string.p_timeformat_24h));
+ if (timeMode.equals(getContext().getString(R.string.p_timeformat_24h))) {
+ return WatchXPlusConstants.ARG_SET_TIMEMODE_24H;
+ } else {
+ return WatchXPlusConstants.ARG_SET_TIMEMODE_12H;
+ }
+ }
/*
Values from device specific settings page
*/
@@ -236,17 +244,30 @@ Values from device specific settings page
return (int) prefs.getInt(WatchXPlusConstants.PREF_REPEAT, 1);
}
+//read continious call notification
+ public static boolean getContiniousVibrationOnCall(String address) {
+ return (boolean) prefs.getBoolean(WatchXPlusConstants.PREF_CONTINIOUS, false);
+ }
+
+//read missed call notification
+ public static boolean getMissedCallReminder(String address) {
+ return (boolean) prefs.getBoolean(WatchXPlusConstants.PREF_MISSED_CALL, false);
+ }
+
+//read button reject call settings
+ public static boolean getButtonReject(String address) {
+ return (boolean) prefs.getBoolean(WatchXPlusConstants.PREF_BUTTON_REJECT, false);
+ }
+
+//read shake wrist reject call settings
+ public static boolean getShakeReject(String address) {
+ return (boolean) prefs.getBoolean(WatchXPlusConstants.PREF_SHAKE_REJECT, false);
+ }
+
/*
Other saved preferences
*/
- public static byte getBPCalibrationStatus(SharedPreferences sharedPrefs) {
- String timeMode = sharedPrefs.getString(DeviceSettingsPreferenceConst.PREF_TIMEFORMAT, getContext().getString(R.string.p_timeformat_24h));
- if (timeMode.equals(getContext().getString(R.string.p_timeformat_24h))) {
- return WatchXPlusConstants.ARG_SET_TIMEMODE_24H;
- } else {
- return WatchXPlusConstants.ARG_SET_TIMEMODE_12H;
- }
- }
+
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java
index 331f7bc99..14e100b3e 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java
@@ -69,6 +69,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.NotificationFilterEntry;
import nodomain.freeyourgadget.gadgetbridge.entities.NotificationFilterEntryDao;
import nodomain.freeyourgadget.gadgetbridge.model.AppNotificationType;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
@@ -249,8 +250,8 @@ public class NotificationListener extends NotificationListenerService {
}
if (shouldIgnore(sbn)) {
- if (!"com.sec.android.app.clockpackage".equals(sbn.getPackageName())) { // allow phone alarm notification
- LOG.info("Ignore notification: " + sbn.getPackageName());
+ if (!"com.sec.android.app.clockpackage".equals(sbn.getPackageName())) { // workaround to allow phone alarm notification
+ LOG.info("Ignore notification: " + sbn.getPackageName()); // need to fix
return;
}
}
@@ -677,7 +678,6 @@ public class NotificationListener extends NotificationListenerService {
if (!isServiceRunning() || sbn == null) {
return true;
}
-
return shouldIgnoreSource(sbn.getPackageName()) || shouldIgnoreNotification(
sbn.getNotification(), sbn.getPackageName());
@@ -721,8 +721,9 @@ public class NotificationListener extends NotificationListenerService {
MediaSessionCompat.Token mediaSession = getMediaSession(notification);
//try to handle media session notifications
- if (mediaSession != null && handleMediaSessionNotification(mediaSession))
+ if (mediaSession != null && handleMediaSessionNotification(mediaSession)) {
return true;
+ }
NotificationType type = AppNotificationType.getInstance().get(source);
//ignore notifications marked as LocalOnly https://developer.android.com/reference/android/app/Notification.html#FLAG_LOCAL_ONLY
@@ -743,7 +744,6 @@ public class NotificationListener extends NotificationListenerService {
return true;
}
}
-
return (notification.flags & Notification.FLAG_ONGOING_EVENT) == Notification.FLAG_ONGOING_EVENT;
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/lenovo/watchxplus/WatchXPlusDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/lenovo/watchxplus/WatchXPlusDeviceSupport.java
index a0bdf88fb..fe5d55256 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/lenovo/watchxplus/WatchXPlusDeviceSupport.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/lenovo/watchxplus/WatchXPlusDeviceSupport.java
@@ -25,6 +25,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.Uri;
+import android.os.CountDownTimer;
import android.os.Handler;
import androidx.annotation.IntRange;
@@ -53,6 +54,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSett
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
+import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
import nodomain.freeyourgadget.gadgetbridge.devices.lenovo.DataType;
import nodomain.freeyourgadget.gadgetbridge.devices.lenovo.watchxplus.WatchXPlusConstants;
@@ -62,6 +64,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.WatchXPlusActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.WatchXPlusHealthActivityOverlay;
import nodomain.freeyourgadget.gadgetbridge.entities.WatchXPlusHealthActivityOverlayDao;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
+import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmClockReceiver;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
@@ -81,13 +84,13 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
-import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.WaitAction;
import nodomain.freeyourgadget.gadgetbridge.service.devices.lenovo.operations.InitOperation;
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
+
public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
private boolean needsAuth;
@@ -466,80 +469,48 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
alarmValue));
}
}
- int repeat = 0;
+
+ // variables to handle ring notifications
boolean isRinging = false;
+ int remainingRepeats = 0;
@Override
public void onSetCallState(final CallSpec callSpec) {
- int repeatDelay = 5000;
+ final int repeatDelay = 5000; // repeat delay of 5 sec
+ // get settings from device settings page
+ final boolean continiousRing = WatchXPlusDeviceCoordinator.getContiniousVibrationOnCall(getDevice().getAddress());
+ boolean missedCall = WatchXPlusDeviceCoordinator.getMissedCallReminder(getDevice().getAddress());
int repeatCount = WatchXPlusDeviceCoordinator.getRepeatOnCall(getDevice().getAddress());
- if (repeatCount < 0) {
- repeatCount = 0;
- }
- if (repeatCount > 5) {
- repeatCount = 5;
- }
-
- if("Phone".equals(callSpec.name)) { // ignore notification if caller name is Phone
- return;
- }
+ // check if repeatCount is in boundaries min=0, max=10
+ if (repeatCount < 0) repeatCount = 0;
+ if (repeatCount > 10) repeatCount = 10; // limit repeats to 10
switch (callSpec.command) {
case CallSpec.CALL_INCOMING:
isRinging = true;
- sendNotification(WatchXPlusConstants.NOTIFICATION_CHANNEL_PHONE_CALL, callSpec.name);
-// TODO dirty code, need to fix
-// repeat call notification up to 5 times
- Handler handler = new Handler();
- if (repeatCount > 0) {
+ remainingRepeats = repeatCount;
+ if (("Phone".equals(callSpec.name)) || (callSpec.name.contains("ropusn")) || (callSpec.name.contains("issed"))) {
+ // do nothing for notifications without caller name, e.g. system call event
+ } else {
+ // send first notification
+ sendNotification(WatchXPlusConstants.NOTIFICATION_CHANNEL_PHONE_CALL, callSpec.name);
+ // init repeat handler
+ final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
- // Actions to do after 5 seconds
- if (isRinging) {
+ // Actions to do after repeatDelay seconds
+ if (((isRinging) && (remainingRepeats > 0)) || ((isRinging) && (continiousRing))) {
+ remainingRepeats = remainingRepeats - 1;
sendNotification(WatchXPlusConstants.NOTIFICATION_CHANNEL_PHONE_CALL, callSpec.name);
+ // re-run handler
+ handler.postDelayed(this, repeatDelay);
+ } else {
+ remainingRepeats = 0;
+ // stop handler
+ handler.removeCallbacks(this);
}
}
}, repeatDelay);
}
- if (repeatCount > 1) {
- handler.postDelayed(new Runnable() {
- public void run() {
- // Actions to do after 5 seconds
- if (isRinging) {
- sendNotification(WatchXPlusConstants.NOTIFICATION_CHANNEL_PHONE_CALL, callSpec.name);
- }
- }
- }, repeatDelay * 2);
- }
- if (repeatCount > 2) {
- handler.postDelayed(new Runnable() {
- public void run() {
- // Actions to do after 5 seconds
- if (isRinging) {
- sendNotification(WatchXPlusConstants.NOTIFICATION_CHANNEL_PHONE_CALL, callSpec.name);
- }
- }
- }, repeatDelay * 3);
- }
- if (repeatCount > 3) {
- handler.postDelayed(new Runnable() {
- public void run() {
- // Actions to do after 5 seconds
- if (isRinging) {
- sendNotification(WatchXPlusConstants.NOTIFICATION_CHANNEL_PHONE_CALL, callSpec.name);
- }
- }
- }, repeatDelay * 4);
- }
- if (repeatCount > 4) {
- handler.postDelayed(new Runnable() {
- public void run() {
- // Actions to do after 5 seconds
- if (isRinging) {
- sendNotification(WatchXPlusConstants.NOTIFICATION_CHANNEL_PHONE_CALL, callSpec.name);
- }
- }
- }, repeatDelay * 5);
- }
break;
case CallSpec.CALL_START:
isRinging = false;
@@ -559,19 +530,44 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
break;
case CallSpec.CALL_END:
if (isRinging) {
- // it's a missed call
- // don't clear notification to preserve small icon near bluetooth
+ // it's a missed call, don't clear notification to preserve small icon near bluetooth
isRinging = false;
+ // send missed call notification if enabled in settings
+ if (missedCall) {
+ sendNotification(WatchXPlusConstants.NOTIFICATION_CHANNEL_PHONE_CALL, "Missed call");
+ }
} else {
isRinging = false;
cancelNotification();
}
break;
default:
+ isRinging = false;
+ cancelNotification();
break;
}
}
+// handle button press while ringing
+ private void handleButtonWhenRing(byte[] value) {
+ GBDeviceEventCallControl callCmd = new GBDeviceEventCallControl();
+ // get saved settings if true - reject call, otherwise ignore call
+ boolean buttonReject = WatchXPlusDeviceCoordinator.getButtonReject(getDevice().getAddress());
+ if (buttonReject) {
+ LOG.info(" call rejected ");
+ isRinging = false;
+ callCmd.event = GBDeviceEventCallControl.Event.REJECT;
+ evaluateGBDeviceEvent(callCmd);
+ cancelNotification();
+ } else {
+ LOG.info(" call ignored ");
+ isRinging = false;
+ callCmd.event = GBDeviceEventCallControl.Event.IGNORE;
+ evaluateGBDeviceEvent(callCmd);
+ cancelNotification();
+ }
+ }
+
@Override
public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) {
@@ -830,6 +826,8 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
handleFirmwareInfo(value);
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_SHAKE_SWITCH, 5)) {
handleShakeState(value);
+ } else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_BUTTON_WHILE_RING, 5)) {
+ handleButtonWhenRing(value);
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_DISCONNECT_REMIND, 5)) {
handleDisconnectReminderState(value);
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_BATTERY_INFO, 5)) {
@@ -1387,9 +1385,12 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
WatchXPlusDeviceCoordinator.shouldEnableHeadsUpScreen(sharedPreferences));
}
- // Command to toggle Lift Wrist to Light Screen
+ // Command to toggle Lift Wrist to Light Screen, and shake to ignore/reject call
private WatchXPlusDeviceSupport setHeadsUpScreen(TransactionBuilder transactionBuilder, boolean enable) {
- byte refuseCall = 0x00; // force refuse call to OFF
+ boolean shakeReject = WatchXPlusDeviceCoordinator.getShakeReject(getDevice().getAddress());
+ byte refuseCall = 0x00; // force shake wrist to ignore/reject call to OFF
+ // returned characteristic is equal with button press while ringing
+ if (shakeReject) refuseCall = 0x01;
byte lightScreen = 0x00;
if (enable) {
lightScreen = 0x01;
@@ -1427,7 +1428,7 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
WatchXPlusConstants.READ_VALUE));
return this;
}
-// Request status of Lift Wrist to Light Screen, and Shake to Refuse Call
+// Request status of Lift Wrist to Light Screen, and Shake to Ignore/Reject Call
public WatchXPlusDeviceSupport getShakeStatus(TransactionBuilder transactionBuilder) {
transactionBuilder.write(getCharacteristic(WatchXPlusConstants.UUID_CHARACTERISTIC_WRITE),
buildCommand(WatchXPlusConstants.CMD_SHAKE_SWITCH,
diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml
index 10ac20d9b..3b7f192df 100644
--- a/app/src/main/res/values-bg/strings.xml
+++ b/app/src/main/res/values-bg/strings.xml
@@ -288,7 +288,13 @@
Формат на часа
Калибриране на височина
Повтори известия за звънене
- Възможни стойности min=0, max=5
+ Възможни стойности min=0, max=10
+ Известие докато звъни
+ Изкл. - игнорира, Вкл. - отказ
+ Бутона игнорира/отказва повикване
+ Дублира действието на бутона
+ Разклащането игнорира/отказва повикване
+ Известие за пропуснато повикване
WatchXPlus настройки
WatchXPlus калибриране
Наблюдение/анализ на съня
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e3409ae9d..fe73c3cd3 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -191,8 +191,14 @@
Time format
Altitude calibration
Repeat call notification
- Possible values min=0, max=5
+ Possible values min=0, max=10
+ Vibration during phone ring
+ Vibration on missed call
WatchXPlus settings
+ Off - ignore, On - reject
+ Button ignore/reject call
+ Duplicates watch button action
+ Shake wrist ignore/reject call
WatchXPlus calibration
Makibes HR3 settings
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 3bf87b1a8..a44d6e6e5 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -588,6 +588,28 @@
android:key="watchxplus_repeat"
android:summary="@string/pref_wxp_title_repeat_on_call_summary"
android:title="@string/pref_wxp_title_repeat_on_call"/>
+
+
+
+