mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-28 21:06:50 +01:00
Support for alarm clock notifications for Mi1 + Mi2 #538
No support for Pebble and HPlus for now. Atm relies on the CM deskclock alarm, which nicely broadcasts events about the current alarm. See https://github.com/CyanogenMod/android_packages_apps_DeskClock.git
This commit is contained in:
parent
e2b3394900
commit
4f0674d038
@ -23,6 +23,7 @@ public final class MiBandConst {
|
||||
|
||||
|
||||
public static final String ORIGIN_INCOMING_CALL = "incoming_call";
|
||||
public static final String ORIGIN_ALARM_CLOCK = "alarm_clock";
|
||||
public static final String MI_GENERAL_NAME_PREFIX = "MI";
|
||||
public static final String MI_BAND2_NAME = "MI Band 2";
|
||||
public static final String MI_1 = "1";
|
||||
|
@ -17,6 +17,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_ALARM_CLOCK;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_INCOMING_CALL;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_ACTIVATE_DISPLAY_ON_LIFT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MI2_DATEFORMAT;
|
||||
@ -146,6 +147,7 @@ public class MiBandPreferencesActivity extends AbstractSettingsActivity {
|
||||
prefKeys.add(PREF_MIBAND_FITNESS_GOAL);
|
||||
prefKeys.add(PREF_MIBAND_RESERVE_ALARM_FOR_CALENDAR);
|
||||
prefKeys.add(PREF_MIBAND_DEVICE_TIME_OFFSET_HOURS);
|
||||
prefKeys.add(getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_ALARM_CLOCK));
|
||||
prefKeys.add(getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_INCOMING_CALL));
|
||||
|
||||
for (NotificationType type : NotificationType.values()) {
|
||||
|
@ -0,0 +1,67 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.externalevents;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||
|
||||
public class AlarmClockReceiver extends BroadcastReceiver {
|
||||
/**
|
||||
* AlarmActivity and AlarmService (when unbound) listen for this broadcast intent
|
||||
* so that other applications can snooze the alarm (after ALARM_ALERT_ACTION and before
|
||||
* ALARM_DONE_ACTION).
|
||||
*/
|
||||
public static final String ALARM_SNOOZE_ACTION = "com.android.deskclock.ALARM_SNOOZE";
|
||||
|
||||
/**
|
||||
* AlarmActivity and AlarmService listen for this broadcast intent so that other
|
||||
* applications can dismiss the alarm (after ALARM_ALERT_ACTION and before ALARM_DONE_ACTION).
|
||||
*/
|
||||
public static final String ALARM_DISMISS_ACTION = "com.android.deskclock.ALARM_DISMISS";
|
||||
|
||||
/** A public action sent by AlarmService when the alarm has started. */
|
||||
public static final String ALARM_ALERT_ACTION = "com.android.deskclock.ALARM_ALERT";
|
||||
|
||||
/** A public action sent by AlarmService when the alarm has stopped for any reason. */
|
||||
public static final String ALARM_DONE_ACTION = "com.android.deskclock.ALARM_DONE";
|
||||
private int lastId;
|
||||
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (ALARM_ALERT_ACTION.equals(action)) {
|
||||
sendAlarm(true);
|
||||
} else if (ALARM_DONE_ACTION.equals(action)) {
|
||||
sendAlarm(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private synchronized void sendAlarm(boolean on) {
|
||||
dismissLastAlarm();
|
||||
if (on) {
|
||||
lastId = generateId();
|
||||
NotificationSpec spec = new NotificationSpec();
|
||||
spec.type = NotificationType.GENERIC_ALARM_CLOCK;
|
||||
// can we get the alarm title somehow?
|
||||
GBApplication.deviceService().onNotification(spec);
|
||||
}
|
||||
}
|
||||
|
||||
private void dismissLastAlarm() {
|
||||
if (lastId != 0) {
|
||||
GBApplication.deviceService().onDeleteNotification(lastId);
|
||||
lastId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private int generateId() {
|
||||
// lacks negative values, but should be sufficient
|
||||
return (int) (Math.random() * Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
@ -17,7 +17,8 @@ public enum NotificationType {
|
||||
SIGNAL(PebbleIconID.NOTIFICATION_HIPCHAT, PebbleColor.BlueMoon),
|
||||
TWITTER(PebbleIconID.NOTIFICATION_TWITTER, PebbleColor.BlueMoon),
|
||||
TELEGRAM(PebbleIconID.NOTIFICATION_TELEGRAM, PebbleColor.PictonBlue),
|
||||
WHATSAPP(PebbleIconID.NOTIFICATION_WHATSAPP, PebbleColor.MayGreen);
|
||||
WHATSAPP(PebbleIconID.NOTIFICATION_WHATSAPP, PebbleColor.MayGreen),
|
||||
GENERIC_ALARM_CLOCK(PebbleIconID.ALARM_CLOCK, PebbleColor.Red);
|
||||
|
||||
public int icon;
|
||||
public byte color;
|
||||
@ -41,6 +42,7 @@ public enum NotificationType {
|
||||
case GENERIC_EMAIL:
|
||||
case GENERIC_NAVIGATION:
|
||||
case GENERIC_SMS:
|
||||
case GENERIC_ALARM_CLOCK:
|
||||
return getFixedValue();
|
||||
case FACEBOOK:
|
||||
case TWITTER:
|
||||
|
@ -27,6 +27,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.OnboardingActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmClockReceiver;
|
||||
import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmReceiver;
|
||||
import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothConnectReceiver;
|
||||
import nodomain.freeyourgadget.gadgetbridge.externalevents.K9Receiver;
|
||||
@ -152,8 +153,9 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
||||
private MusicPlaybackReceiver mMusicPlaybackReceiver = null;
|
||||
private TimeChangeReceiver mTimeChangeReceiver = null;
|
||||
private BluetoothConnectReceiver mBlueToothConnectReceiver = null;
|
||||
private AlarmReceiver mAlarmReceiver = null;
|
||||
private AlarmClockReceiver mAlarmClockReceiver = null;
|
||||
|
||||
private AlarmReceiver mAlarmReceiver = null;
|
||||
private Random mRandom = new Random();
|
||||
|
||||
/**
|
||||
@ -619,6 +621,13 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
||||
mAlarmReceiver = new AlarmReceiver();
|
||||
registerReceiver(mAlarmReceiver, new IntentFilter("DAILY_ALARM"));
|
||||
}
|
||||
if (mAlarmClockReceiver == null) {
|
||||
mAlarmClockReceiver = new AlarmClockReceiver();
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(AlarmClockReceiver.ALARM_ALERT_ACTION);
|
||||
filter.addAction(AlarmClockReceiver.ALARM_DONE_ACTION);
|
||||
registerReceiver(mAlarmClockReceiver, filter);
|
||||
}
|
||||
} else {
|
||||
if (mPhoneCallReceiver != null) {
|
||||
unregisterReceiver(mPhoneCallReceiver);
|
||||
@ -652,6 +661,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
||||
unregisterReceiver(mAlarmReceiver);
|
||||
mAlarmReceiver = null;
|
||||
}
|
||||
if (mAlarmClockReceiver != null) {
|
||||
unregisterReceiver(mAlarmClockReceiver);
|
||||
mAlarmClockReceiver = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
|
||||
@ -102,6 +103,8 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
private final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo();
|
||||
private final GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo();
|
||||
private RealtimeSamplesSupport realtimeSamplesSupport;
|
||||
private boolean alarmClockRining;
|
||||
private boolean alarmClockRinging;
|
||||
|
||||
public MiBandSupport() {
|
||||
super(LOG);
|
||||
@ -541,13 +544,29 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
|
||||
@Override
|
||||
public void onNotification(NotificationSpec notificationSpec) {
|
||||
if (notificationSpec.type == NotificationType.GENERIC_ALARM_CLOCK) {
|
||||
onAlarmClock(notificationSpec);
|
||||
return;
|
||||
}
|
||||
|
||||
String origin = notificationSpec.type.getGenericType();
|
||||
performPreferredNotification(origin + " received", origin, null);
|
||||
}
|
||||
|
||||
private void onAlarmClock(NotificationSpec notificationSpec) {
|
||||
alarmClockRining = true;
|
||||
AbortTransactionAction abortAction = new AbortTransactionAction() {
|
||||
@Override
|
||||
protected boolean shouldAbort() {
|
||||
return !isAlarmClockRinging();
|
||||
}
|
||||
};
|
||||
performPreferredNotification("alarm clock ringing", MiBandConst.ORIGIN_ALARM_CLOCK, abortAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteNotification(int id) {
|
||||
|
||||
alarmClockRining = false; // we should have the notificationtype at least to check
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -616,6 +635,10 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) {
|
||||
}
|
||||
|
||||
private boolean isAlarmClockRinging() {
|
||||
// don't synchronize, this is not really important
|
||||
return alarmClockRinging;
|
||||
}
|
||||
private boolean isTelephoneRinging() {
|
||||
// don't synchronize, this is not really important
|
||||
return telephoneRinging;
|
||||
|
@ -73,6 +73,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.CheckAuthenti
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.DeviceInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.NotificationStrategy;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.RealtimeSamplesSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.actions.StopNotificationAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.FetchActivityOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.InitOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.UpdateFirmwareOperation;
|
||||
@ -123,6 +124,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
private final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo();
|
||||
private final GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo();
|
||||
private RealtimeSamplesSupport realtimeSamplesSupport;
|
||||
private boolean alarmClockRinging;
|
||||
|
||||
public MiBand2Support() {
|
||||
super(LOG);
|
||||
@ -586,6 +588,10 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
|
||||
@Override
|
||||
public void onNotification(NotificationSpec notificationSpec) {
|
||||
if (notificationSpec.type == NotificationType.GENERIC_ALARM_CLOCK) {
|
||||
onAlarmClock(notificationSpec);
|
||||
return;
|
||||
}
|
||||
int alertLevel = MiBand2Service.ALERT_LEVEL_MESSAGE;
|
||||
if (notificationSpec.type == NotificationType.UNKNOWN) {
|
||||
alertLevel = MiBand2Service.ALERT_LEVEL_VIBRATE_ONLY;
|
||||
@ -594,9 +600,20 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
performPreferredNotification(origin + " received", origin, alertLevel, null);
|
||||
}
|
||||
|
||||
private void onAlarmClock(NotificationSpec notificationSpec) {
|
||||
alarmClockRinging = true;
|
||||
AbortTransactionAction abortAction = new StopNotificationAction(getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL)) {
|
||||
@Override
|
||||
protected boolean shouldAbort() {
|
||||
return !isAlarmClockRinging();
|
||||
}
|
||||
};
|
||||
performPreferredNotification("alarm clock ringing", MiBandConst.ORIGIN_ALARM_CLOCK, MiBand2Service.ALERT_LEVEL_VIBRATE_ONLY, abortAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteNotification(int id) {
|
||||
|
||||
alarmClockRinging = false; // we should have the notificationtype at least to check
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -616,23 +633,11 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
public void onSetCallState(CallSpec callSpec) {
|
||||
if (callSpec.command == CallSpec.CALL_INCOMING) {
|
||||
telephoneRinging = true;
|
||||
AbortTransactionAction abortAction = new AbortTransactionAction() {
|
||||
AbortTransactionAction abortAction = new StopNotificationAction(getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL)) {
|
||||
@Override
|
||||
protected boolean shouldAbort() {
|
||||
return !isTelephoneRinging();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean run(BluetoothGatt gatt) {
|
||||
if (!super.run(gatt)) {
|
||||
// send a signal to stop the vibration
|
||||
BluetoothGattCharacteristic characteristic = MiBand2Support.this.getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL);
|
||||
characteristic.setValue(new byte[] {MiBand2Service.ALERT_LEVEL_NONE});
|
||||
gatt.writeCharacteristic(characteristic);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
performPreferredNotification("incoming call", MiBandConst.ORIGIN_INCOMING_CALL, MiBand2Service.ALERT_LEVEL_PHONE_CALL, abortAction);
|
||||
} else if ((callSpec.command == CallSpec.CALL_START) || (callSpec.command == CallSpec.CALL_END)) {
|
||||
@ -644,6 +649,11 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) {
|
||||
}
|
||||
|
||||
private boolean isAlarmClockRinging() {
|
||||
// don't synchronize, this is not really important
|
||||
return alarmClockRinging;
|
||||
}
|
||||
|
||||
private boolean isTelephoneRinging() {
|
||||
// don't synchronize, this is not really important
|
||||
return telephoneRinging;
|
||||
|
@ -0,0 +1,28 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.actions;
|
||||
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Service;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.AbortTransactionAction;
|
||||
|
||||
public abstract class StopNotificationAction extends AbortTransactionAction {
|
||||
|
||||
private final BluetoothGattCharacteristic alertLevelCharacteristic;
|
||||
|
||||
public StopNotificationAction(BluetoothGattCharacteristic alertLevelCharacteristic) {
|
||||
this.alertLevelCharacteristic = alertLevelCharacteristic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean run(BluetoothGatt gatt) {
|
||||
if (!super.run(gatt)) {
|
||||
// send a signal to stop the vibration
|
||||
alertLevelCharacteristic.setValue(new byte[]{MiBand2Service.ALERT_LEVEL_NONE});
|
||||
gatt.writeCharacteristic(alertLevelCharacteristic);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -406,5 +406,6 @@
|
||||
|
||||
<string name="timeformat_24h">24H</string>
|
||||
<string name="timeformat_am_pm">AM/PM</string>
|
||||
<string name="pref_screen_notification_profile_alarm_clock">Alarm Clock</string>
|
||||
|
||||
</resources>
|
||||
|
@ -210,6 +210,36 @@
|
||||
android:title="@string/vibration_try"/>
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
android:key="vibration_profile_key"
|
||||
android:title="@string/pref_screen_notification_profile_alarm_clock"
|
||||
android:persistent="false">
|
||||
|
||||
<!-- workaround for missing toolbar -->
|
||||
<PreferenceCategory
|
||||
android:title="@string/pref_screen_notification_profile_alarm_clock"
|
||||
/>
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="@string/p_alarm_clock"
|
||||
android:entries="@array/vibration_profile"
|
||||
android:entryValues="@array/vibration_profile_values"
|
||||
android:key="mi_vibration_profile_alarm_clock"
|
||||
android:title="@string/miband_prefs_vibration"
|
||||
android:summary="%s" />
|
||||
|
||||
<EditTextPreference
|
||||
android:defaultValue="3"
|
||||
android:inputType="number"
|
||||
android:key="mi_vibration_count_alarm_clock"
|
||||
android:maxLength="2"
|
||||
android:title="@string/pref_title_notifications_repetitions" />
|
||||
<Preference
|
||||
android:key="mi_try_generic_alarm_clock"
|
||||
android:persistent="false"
|
||||
android:title="@string/vibration_try"/>
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
android:key="vibration_profile_key"
|
||||
android:title="@string/pref_screen_notification_profile_generic_navigation"
|
||||
|
Loading…
Reference in New Issue
Block a user