1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-09-27 08:47:03 +02:00
- Cleaned code for repeat watch vibration during phone ring.
- On my samsung phone and Bulgarian language, when call is ended, on watch shows notification with name "Phone" and vibrates until disconnect from app. Finally managed to fix it.
ADD:
- Add setting for ignore/reject phone call with device button.
- Add setting for ignore/reject phone call with shake device. (duplicates button action) P.S. to apply needs to reconnect device.
- Add setting for sending Missed call if call is missed.
- Add setting for continious vibration while phone ringing.
NEED MORE TESTING:
- When phone alarm trigger - send notification on watch. Works on samsung phone. Don't have other phones for testing.

P.S. To apply altitude calibration, need to disconnect and reconnect watch
This commit is contained in:
mamutcho 2019-11-06 23:56:24 +02:00
parent 81997e7725
commit 33f18036d3
7 changed files with 142 additions and 80 deletions

View File

@ -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};

View File

@ -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;
}
}
}

View File

@ -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;
}

View File

@ -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,

View File

@ -288,7 +288,13 @@
<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=5</string>
<string name="pref_wxp_title_repeat_on_call_summary">Възможни стойности min=0, max=10</string>
<string name="prefs_wxp_continious">Известие докато звъни</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="prefs_wxp_missed">Известие за пропуснато повикване</string>
<string name="preferences_watchxplus_settings">WatchXPlus настройки</string>
<string name="pref_header_wxp_calibration">WatchXPlus калибриране</string>
<string name="title_activity_sleepmonitor">Наблюдение/анализ на съня</string>

View File

@ -191,8 +191,14 @@
<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=5</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">WatchXPlus settings</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="pref_header_wxp_calibration">WatchXPlus calibration</string>
<!-- Makibes HR3 Preferences -->
<string name="preferences_makibes_hr3_settings">Makibes HR3 settings</string>

View File

@ -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"/>
<CheckBoxPreference
android:layout="@layout/preference_checkbox"
android:defaultValue="false"
android:key="watchxplus_continious"
android:title="@string/prefs_wxp_continious" />
<CheckBoxPreference
android:layout="@layout/preference_checkbox"
android:defaultValue="false"
android:key="watchxplus_missed"
android:title="@string/prefs_wxp_missed" />
<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" />
</PreferenceCategory>
<PreferenceCategory
android:key="pref_category_watchxplus_calibration"