mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-29 12:05:53 +01:00
Huami/Xiaomi: centralize handling of device state events
Gadgetbridge can be configured to perform an action when a Huami device is taken off or the user was detected to fall asleep or wake up. This functionality was specific to Huami devices, but this changeset moves this upstream to the AbstractDeviceSupport class in combination with new GBDeviceEvents. Now that the ADS has centralized support for this functionality, the same logic can be used for other devices. In this case, an implementation is added for supported Xiaomi devices.
This commit is contained in:
parent
2ff92c73f8
commit
435d41aca0
@ -382,4 +382,12 @@ public class DeviceSettingsPreferenceConst {
|
||||
public static final String PREF_FEMOMETER_MEASUREMENT_MODE = "femometer_measurement_mode";
|
||||
|
||||
public static final String PREF_PREFIX_NOTIFICATION_WITH_APP = "pref_prefix_notification_with_app";
|
||||
public static final String PREF_DEVICE_ACTION_SELECTION_OFF = "UNKNOWN";
|
||||
public static final String PREF_DEVICE_ACTION_SELECTION_BROADCAST = "BROADCAST";
|
||||
public static final String PREF_DEVICE_ACTION_FELL_SLEEP_SELECTION = "events_forwarding_fellsleep_action_selection";
|
||||
public static final String PREF_DEVICE_ACTION_FELL_SLEEP_BROADCAST = "prefs_events_forwarding_fellsleep_broadcast";
|
||||
public static final String PREF_DEVICE_ACTION_WOKE_UP_SELECTION = "events_forwarding_wokeup_action_selection";
|
||||
public static final String PREF_DEVICE_ACTION_WOKE_UP_BROADCAST = "prefs_events_forwarding_wokeup_broadcast";
|
||||
public static final String PREF_DEVICE_ACTION_START_NON_WEAR_SELECTION = "events_forwarding_startnonwear_action_selection";
|
||||
public static final String PREF_DEVICE_ACTION_START_NON_WEAR_BROADCAST = "prefs_events_forwarding_startnonwear_broadcast";
|
||||
}
|
||||
|
@ -59,14 +59,14 @@ import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.*;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_CONTROL_CENTER_SORTABLE;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_FELL_SLEEP_BROADCAST;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_FELL_SLEEP_SELECTION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_SELECTION_BROADCAST;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_SELECTION_OFF;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_START_NON_WEAR_BROADCAST;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_START_NON_WEAR_SELECTION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_WOKE_UP_BROADCAST;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_WOKE_UP_SELECTION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_ACTION_FELL_SLEEP_BROADCAST;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_ACTION_FELL_SLEEP_SELECTION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_ACTION_SELECTION_BROADCAST;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_ACTION_SELECTION_OFF;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_ACTION_START_NON_WEAR_BROADCAST;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_ACTION_START_NON_WEAR_SELECTION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_ACTION_WOKE_UP_BROADCAST;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_ACTION_WOKE_UP_SELECTION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DISPLAY_ITEMS;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_EXPOSE_HR_THIRDPARTY;
|
||||
|
@ -0,0 +1,30 @@
|
||||
/* Copyright (C) 2023 Yoran Vulker
|
||||
|
||||
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.deviceevents;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.SleepState;
|
||||
|
||||
public class GBDeviceEventSleepStateDetection extends GBDeviceEvent {
|
||||
public SleepState sleepState;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + String.format(Locale.ROOT, "sleepState=%s", sleepState);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/* Copyright (C) 2023 Yoran Vulker
|
||||
|
||||
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.deviceevents;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WearingState;
|
||||
|
||||
public class GBDeviceEventWearState extends GBDeviceEvent {
|
||||
public WearingState wearingState = WearingState.UNKNOWN;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + String.format(Locale.ROOT, "wearingState=%s", wearingState);
|
||||
}
|
||||
}
|
@ -98,15 +98,6 @@ public class HuamiConst {
|
||||
public static final String PREF_BUTTON_ACTION_SELECTION_FITNESS_APP_STOP = "FITNESS_CONTROL_STOP";
|
||||
public static final String PREF_BUTTON_ACTION_SELECTION_FITNESS_APP_TOGGLE = "FITNESS_CONTROL_TOGGLE";
|
||||
|
||||
public static final String PREF_DEVICE_ACTION_SELECTION_OFF = "UNKNOWN";
|
||||
public static final String PREF_DEVICE_ACTION_SELECTION_BROADCAST = "BROADCAST";
|
||||
public static final String PREF_DEVICE_ACTION_FELL_SLEEP_SELECTION = "events_forwarding_fellsleep_action_selection";
|
||||
public static final String PREF_DEVICE_ACTION_FELL_SLEEP_BROADCAST = "prefs_events_forwarding_fellsleep_broadcast";
|
||||
public static final String PREF_DEVICE_ACTION_WOKE_UP_SELECTION = "events_forwarding_wokeup_action_selection";
|
||||
public static final String PREF_DEVICE_ACTION_WOKE_UP_BROADCAST = "prefs_events_forwarding_wokeup_broadcast";
|
||||
public static final String PREF_DEVICE_ACTION_START_NON_WEAR_SELECTION = "events_forwarding_startnonwear_action_selection";
|
||||
public static final String PREF_DEVICE_ACTION_START_NON_WEAR_BROADCAST = "prefs_events_forwarding_startnonwear_broadcast";
|
||||
|
||||
/**
|
||||
* The suffixes match the enum {@link nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiVibrationPatternNotificationType}.
|
||||
*/
|
||||
|
@ -410,6 +410,9 @@ public abstract class XiaomiCoordinator extends AbstractBLEDeviceCoordinator {
|
||||
settings.add(R.xml.devicesettings_contacts);
|
||||
}
|
||||
settings.add(R.xml.devicesettings_camera_remote);
|
||||
if (supportsWearingAndSleepingDataThroughDeviceState()) {
|
||||
settings.add(R.xml.devicesettings_device_actions);
|
||||
}
|
||||
|
||||
//
|
||||
// Developer
|
||||
@ -487,4 +490,8 @@ public abstract class XiaomiCoordinator extends AbstractBLEDeviceCoordinator {
|
||||
public boolean supportsMultipleWeatherLocations() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean supportsWearingAndSleepingDataThroughDeviceState() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -67,4 +67,9 @@ public class XiaomiWatchS1ActiveCoordinator extends XiaomiCoordinator {
|
||||
public boolean supportsMultipleWeatherLocations() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsWearingAndSleepingDataThroughDeviceState() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
/* Copyright (C) 2023 Yoran Vulker
|
||||
|
||||
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.model;
|
||||
|
||||
public enum SleepState {
|
||||
UNKNOWN,
|
||||
ASLEEP,
|
||||
AWAKE,
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/* Copyright (C) 2023 Yoran Vulker
|
||||
|
||||
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.model;
|
||||
|
||||
public enum WearingState {
|
||||
UNKNOWN,
|
||||
WEARING,
|
||||
NOT_WEARING,
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/* Copyright (C) 2015-2021 Andreas Böhler, Andreas Shimokawa, Carsten
|
||||
/* Copyright (C) 2015-2023 Andreas Böhler, Andreas Shimokawa, Carsten
|
||||
Pfeiffer, Daniele Gobbetti, José Rebelo, Pauli Salmenrinne, Sebastian Kranz,
|
||||
Taavi Eomäe
|
||||
Taavi Eomäe, Yoran Vulker
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
@ -56,6 +56,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.FindPhoneActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AbstractAppManagerFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.capabilities.loyaltycards.LoyaltyCard;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBAccess;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
@ -67,6 +68,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallContro
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventDisplayMessage;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFmFrequency;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSleepStateDetection;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdateDeviceInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventLEDColor;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
|
||||
@ -75,10 +77,12 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdateDevi
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventScreenshot;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventWearState;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BatteryLevel;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.externalevents.NotificationListener;
|
||||
import nodomain.freeyourgadget.gadgetbridge.externalevents.opentracks.OpenTracksController;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
|
||||
@ -90,6 +94,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.SleepState;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WearingState;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WorldClock;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NavigationInfoSpec;
|
||||
@ -208,6 +214,10 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
|
||||
handleGBDeviceEvent((GBDeviceEventUpdateDeviceState) deviceEvent);
|
||||
} else if (deviceEvent instanceof GBDeviceEventFmFrequency) {
|
||||
handleGBDeviceEvent((GBDeviceEventFmFrequency) deviceEvent);
|
||||
} else if (deviceEvent instanceof GBDeviceEventWearState) {
|
||||
handleGBDeviceEvent((GBDeviceEventWearState) deviceEvent);
|
||||
} else if (deviceEvent instanceof GBDeviceEventSleepStateDetection) {
|
||||
handleGBDeviceEvent((GBDeviceEventSleepStateDetection) deviceEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -521,6 +531,133 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
|
||||
gbDevice.sendDeviceUpdateIntent(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to run specific actions configured in the device preferences, upon wear state
|
||||
* or awake/asleep events.
|
||||
*
|
||||
* @param action
|
||||
* @param message
|
||||
*/
|
||||
private void handleDeviceAction(String action, String message) {
|
||||
String actionDisabled = getContext().getString(R.string.pref_button_action_disabled_value);
|
||||
|
||||
if (actionDisabled.equals(action)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String actionBroadcast = getContext().getString(R.string.pref_device_action_broadcast_value);
|
||||
final String actionFitnessControlStart = getContext().getString(R.string.pref_device_action_fitness_app_control_start_value);
|
||||
final String actionFitnessControlStop = getContext().getString(R.string.pref_device_action_fitness_app_control_stop_value);
|
||||
final String actionFitnessControlToggle = getContext().getString(R.string.pref_device_action_fitness_app_control_toggle_value);
|
||||
final String actionMediaPlay = getContext().getString(R.string.pref_media_play_value);
|
||||
final String actionMediaPause = getContext().getString(R.string.pref_media_pause_value);
|
||||
final String actionMediaPlayPause = getContext().getString(R.string.pref_media_playpause_value);
|
||||
|
||||
if (actionBroadcast.equals(action)) {
|
||||
if (message != null) {
|
||||
Intent in = new Intent();
|
||||
in.setAction(message);
|
||||
LOG.info("Sending broadcast " + message);
|
||||
getContext().getApplicationContext().sendBroadcast(in);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (actionFitnessControlStart.equals(action)) {
|
||||
OpenTracksController.startRecording(getContext());
|
||||
return;
|
||||
}
|
||||
|
||||
if (actionFitnessControlStop.equals(action)) {
|
||||
OpenTracksController.stopRecording(getContext());
|
||||
return;
|
||||
}
|
||||
|
||||
if (actionFitnessControlToggle.equals(action)) {
|
||||
OpenTracksController.toggleRecording(getContext());
|
||||
return;
|
||||
}
|
||||
|
||||
if (actionMediaPlay.equals(action) ||
|
||||
actionMediaPause.equals(action) ||
|
||||
actionMediaPlayPause.equals(action)
|
||||
) {
|
||||
GBDeviceEventMusicControl deviceEventMusicControl = new GBDeviceEventMusicControl();
|
||||
deviceEventMusicControl.event = GBDeviceEventMusicControl.Event.valueOf(action);
|
||||
evaluateGBDeviceEvent(deviceEventMusicControl);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.warn("Unhandled device state change action (action: {}, message: {})", action, message);
|
||||
}
|
||||
|
||||
private void handleGBDeviceEvent(GBDeviceEventSleepStateDetection event) {
|
||||
LOG.debug("Got SLEEP_STATE_DETECTION device event, detected sleep state = {}", event.sleepState);
|
||||
|
||||
if (event.sleepState == SleepState.UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
String actionDisabled = getContext().getString(R.string.pref_button_action_disabled_value);
|
||||
String actionPreferenceKey, messagePreferenceKey;
|
||||
int defaultBroadcastMessageResource;
|
||||
|
||||
switch (event.sleepState) {
|
||||
case AWAKE:
|
||||
actionPreferenceKey = DeviceSettingsPreferenceConst.PREF_DEVICE_ACTION_WOKE_UP_SELECTION;
|
||||
messagePreferenceKey = DeviceSettingsPreferenceConst.PREF_DEVICE_ACTION_WOKE_UP_BROADCAST;
|
||||
defaultBroadcastMessageResource = R.string.prefs_events_forwarding_wokeup_broadcast_default_value;
|
||||
break;
|
||||
case ASLEEP:
|
||||
actionPreferenceKey = DeviceSettingsPreferenceConst.PREF_DEVICE_ACTION_FELL_SLEEP_SELECTION;
|
||||
messagePreferenceKey = DeviceSettingsPreferenceConst.PREF_DEVICE_ACTION_FELL_SLEEP_BROADCAST;
|
||||
defaultBroadcastMessageResource = R.string.prefs_events_forwarding_fellsleep_broadcast_default_value;
|
||||
break;
|
||||
default:
|
||||
LOG.warn("Unable to deduce action and broadcast message preference key for sleep state {}", event.sleepState);
|
||||
return;
|
||||
}
|
||||
|
||||
String action = getDevicePrefs().getString(actionPreferenceKey, actionDisabled);
|
||||
|
||||
if (actionDisabled.equals(action)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String broadcastMessage = getDevicePrefs().getString(messagePreferenceKey, context.getString(defaultBroadcastMessageResource));
|
||||
handleDeviceAction(action, broadcastMessage);
|
||||
}
|
||||
|
||||
private void handleGBDeviceEvent(GBDeviceEventWearState event) {
|
||||
LOG.debug("Got WEAR_STATE device event, wearingState = {}", event.wearingState);
|
||||
|
||||
if (event.wearingState == WearingState.UNKNOWN) {
|
||||
LOG.warn("WEAR_STATE state is UNKNOWN, aborting further evaluation");
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.wearingState != WearingState.NOT_WEARING) {
|
||||
LOG.debug("WEAR_STATE state is not NOT_WEARING, aborting further evaluation");
|
||||
}
|
||||
|
||||
String valueDisabled = getContext().getString(R.string.pref_button_action_disabled_value);
|
||||
String actionOnUnwear = getDevicePrefs().getString(
|
||||
DeviceSettingsPreferenceConst.PREF_DEVICE_ACTION_START_NON_WEAR_SELECTION,
|
||||
valueDisabled
|
||||
);
|
||||
|
||||
// check if an action is set
|
||||
if (actionOnUnwear.equals(valueDisabled)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String broadcastMessage = getDevicePrefs().getString(
|
||||
DeviceSettingsPreferenceConst.PREF_DEVICE_ACTION_START_NON_WEAR_BROADCAST,
|
||||
getContext().getString(R.string.prefs_events_forwarding_startnonwear_broadcast_default_value)
|
||||
);
|
||||
|
||||
handleDeviceAction(actionOnUnwear, broadcastMessage);
|
||||
}
|
||||
|
||||
private StoreDataTask createStoreTask(String task, Context context, GBDeviceEventBatteryInfo deviceEvent) {
|
||||
return new StoreDataTask(task, context, deviceEvent);
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* Copyright (C) 2015-2021 Andreas Böhler, Andreas Shimokawa, Avamander,
|
||||
/* Copyright (C) 2015-2023 Andreas Böhler, Andreas Shimokawa, Avamander,
|
||||
Carsten Pfeiffer, Daniel Dakhno, Daniele Gobbetti, Daniel Hauck, Dikay900,
|
||||
Frank Slezak, ivanovlev, João Paulo Barraca, José Rebelo, Julien Pivotto,
|
||||
Kasha, keeshii, mamucho, Martin, Matthieu Baerts, Nephiel, Sebastian Kranz,
|
||||
Sergey Trofimov, Steffen Liebergeld, Taavi Eomäe, Uwe Hermann
|
||||
Sergey Trofimov, Steffen Liebergeld, Taavi Eomäe, Uwe Hermann, Yoran Vulker
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* Copyright (C) 2015-2021 Andreas Shimokawa, Carsten Pfeiffer, Christian
|
||||
/* Copyright (C) 2015-2023 Andreas Shimokawa, Carsten Pfeiffer, Christian
|
||||
Fischer, Daniele Gobbetti, Dmitry Markin, JohnnySun, José Rebelo, Julien
|
||||
Pivotto, Kasha, Michal Novotny, Petr Vaněk, Sebastian Kranz, Sergey Trofimov,
|
||||
Steffen Liebergeld, Taavi Eomäe, Zhong Jianxin
|
||||
Steffen Liebergeld, Taavi Eomäe, Yoran Vulker, Zhong Jianxin
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
@ -80,12 +80,15 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSett
|
||||
import nodomain.freeyourgadget.gadgetbridge.capabilities.password.PasswordCapabilityImpl;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventNotificationControl;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSleepStateDetection;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventWearState;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.ActivateDisplayOnLift;
|
||||
@ -121,6 +124,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.SleepState;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WearingState;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.AbstractFetchOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.FetchStatisticsOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.FetchTemperatureOperation;
|
||||
@ -220,6 +225,7 @@ import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.Dev
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_TIMEFORMAT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_USER_FITNESS_GOAL_NOTIFICATION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_WEARLOCATION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_ACTION_SELECTION_OFF;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.Huami2021Service.WORKOUT_GPS_FLAG_POSITION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.Huami2021Service.WORKOUT_GPS_FLAG_STATUS;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_BUTTON_ACTION_SELECTION_BROADCAST;
|
||||
@ -227,13 +233,6 @@ import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_BUTTON_ACTION_SELECTION_FITNESS_APP_STOP;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_BUTTON_ACTION_SELECTION_FITNESS_APP_TOGGLE;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_BUTTON_ACTION_SELECTION_OFF;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_FELL_SLEEP_BROADCAST;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_FELL_SLEEP_SELECTION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_SELECTION_OFF;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_START_NON_WEAR_BROADCAST;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_START_NON_WEAR_SELECTION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_WOKE_UP_BROADCAST;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_DEVICE_ACTION_WOKE_UP_SELECTION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_HUAMI_VIBRATION_COUNT_ALARM;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_HUAMI_VIBRATION_COUNT_APP_ALERTS;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst.PREF_HUAMI_VIBRATION_COUNT_EVENT_REMINDER;
|
||||
@ -1788,13 +1787,12 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements
|
||||
}
|
||||
|
||||
private void executeButtonAction(String buttonKey) {
|
||||
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
|
||||
String buttonPreference = prefs.getString(buttonKey, PREF_BUTTON_ACTION_SELECTION_OFF);
|
||||
String buttonPreference = getDevicePrefs().getString(buttonKey, PREF_BUTTON_ACTION_SELECTION_OFF);
|
||||
|
||||
if (buttonPreference.equals(PREF_BUTTON_ACTION_SELECTION_OFF)) {
|
||||
return;
|
||||
}
|
||||
if (prefs.getBoolean(HuamiConst.PREF_BUTTON_ACTION_VIBRATE, false)) {
|
||||
if (getDevicePrefs().getBoolean(HuamiConst.PREF_BUTTON_ACTION_VIBRATE, false)) {
|
||||
vibrateOnce();
|
||||
}
|
||||
switch (buttonPreference) {
|
||||
@ -1815,37 +1813,6 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleDeviceAction(String deviceAction, String message) {
|
||||
if (deviceAction.equals(PREF_DEVICE_ACTION_SELECTION_OFF)) {
|
||||
return;
|
||||
}
|
||||
switch (deviceAction) {
|
||||
case PREF_BUTTON_ACTION_SELECTION_BROADCAST:
|
||||
sendSystemBroadcast(message);
|
||||
break;
|
||||
case PREF_BUTTON_ACTION_SELECTION_FITNESS_APP_START:
|
||||
OpenTracksController.startRecording(this.getContext());
|
||||
break;
|
||||
case PREF_BUTTON_ACTION_SELECTION_FITNESS_APP_STOP:
|
||||
OpenTracksController.stopRecording(this.getContext());
|
||||
break;
|
||||
case PREF_BUTTON_ACTION_SELECTION_FITNESS_APP_TOGGLE:
|
||||
OpenTracksController.toggleRecording(this.getContext());
|
||||
break;
|
||||
default:
|
||||
handleMediaButton(deviceAction);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendSystemBroadcast(String message){
|
||||
if (message !=null) {
|
||||
Intent in = new Intent();
|
||||
in.setAction(message);
|
||||
LOG.info("Sending broadcast " + message);
|
||||
this.getContext().getApplicationContext().sendBroadcast(in);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendSystemBroadcastWithButtonId() {
|
||||
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
|
||||
String requiredButtonPressMessage = prefs.getString(HuamiConst.PREF_BUTTON_ACTION_BROADCAST,
|
||||
@ -1857,12 +1824,12 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements
|
||||
this.getContext().getApplicationContext().sendBroadcast(in);
|
||||
}
|
||||
|
||||
private void handleMediaButton(String MediaAction) {
|
||||
if (MediaAction.equals(PREF_DEVICE_ACTION_SELECTION_OFF)) {
|
||||
private void handleMediaButton(String mediaAction) {
|
||||
if (mediaAction.equals(PREF_DEVICE_ACTION_SELECTION_OFF) || mediaAction.equals(PREF_BUTTON_ACTION_SELECTION_OFF)) {
|
||||
return;
|
||||
}
|
||||
GBDeviceEventMusicControl deviceEventMusicControl = new GBDeviceEventMusicControl();
|
||||
deviceEventMusicControl.event = GBDeviceEventMusicControl.Event.valueOf(MediaAction);
|
||||
deviceEventMusicControl.event = GBDeviceEventMusicControl.Event.valueOf(mediaAction);
|
||||
evaluateGBDeviceEvent(deviceEventMusicControl);
|
||||
}
|
||||
|
||||
@ -2190,34 +2157,28 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements
|
||||
}
|
||||
}
|
||||
|
||||
protected void processDeviceEvent(int event){
|
||||
LOG.debug("Handling device event: " + event);
|
||||
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
|
||||
String deviceActionBroadcastMessage=null;
|
||||
|
||||
switch (event) {
|
||||
protected void processDeviceEvent(int deviceEvent){
|
||||
LOG.debug("Handling device event: " + deviceEvent);
|
||||
GBDeviceEvent event;
|
||||
switch (deviceEvent) {
|
||||
case HuamiDeviceEvent.WOKE_UP:
|
||||
String wakeupAction = prefs.getString(PREF_DEVICE_ACTION_WOKE_UP_SELECTION,PREF_DEVICE_ACTION_SELECTION_OFF);
|
||||
if (wakeupAction.equals(PREF_DEVICE_ACTION_SELECTION_OFF)) return;
|
||||
deviceActionBroadcastMessage= prefs.getString(PREF_DEVICE_ACTION_WOKE_UP_BROADCAST,
|
||||
this.getContext().getString(R.string.prefs_events_forwarding_wokeup_broadcast_default_value));
|
||||
handleDeviceAction(wakeupAction, deviceActionBroadcastMessage);
|
||||
event = new GBDeviceEventSleepStateDetection();
|
||||
((GBDeviceEventSleepStateDetection) event).sleepState = SleepState.AWAKE;
|
||||
break;
|
||||
case HuamiDeviceEvent.FELL_ASLEEP:
|
||||
String fellsleepAction = prefs.getString(PREF_DEVICE_ACTION_FELL_SLEEP_SELECTION,PREF_DEVICE_ACTION_SELECTION_OFF);
|
||||
if (fellsleepAction.equals(PREF_DEVICE_ACTION_SELECTION_OFF)) return;
|
||||
deviceActionBroadcastMessage= prefs.getString(PREF_DEVICE_ACTION_FELL_SLEEP_BROADCAST,
|
||||
this.getContext().getString(R.string.prefs_events_forwarding_fellsleep_broadcast_default_value));
|
||||
handleDeviceAction(fellsleepAction, deviceActionBroadcastMessage);
|
||||
event = new GBDeviceEventSleepStateDetection();
|
||||
((GBDeviceEventSleepStateDetection) event).sleepState = SleepState.ASLEEP;
|
||||
break;
|
||||
case HuamiDeviceEvent.START_NONWEAR:
|
||||
String nonwearAction = prefs.getString(PREF_DEVICE_ACTION_START_NON_WEAR_SELECTION,PREF_DEVICE_ACTION_SELECTION_OFF);
|
||||
if (nonwearAction.equals(PREF_DEVICE_ACTION_SELECTION_OFF)) return;
|
||||
deviceActionBroadcastMessage= prefs.getString(PREF_DEVICE_ACTION_START_NON_WEAR_BROADCAST,
|
||||
this.getContext().getString(R.string.prefs_events_forwarding_startnonwear_broadcast_default_value));
|
||||
handleDeviceAction(nonwearAction, deviceActionBroadcastMessage);
|
||||
event = new GBDeviceEventWearState();
|
||||
((GBDeviceEventWearState) event).wearingState = WearingState.NOT_WEARING;
|
||||
break;
|
||||
default:
|
||||
LOG.warn("Unhandled device event {}", deviceEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
evaluateGBDeviceEvent(event);
|
||||
}
|
||||
|
||||
private void handleLongButtonEvent(){
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 José Rebelo
|
||||
/* Copyright (C) 2023 José Rebelo, Yoran Vulker
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
@ -36,13 +36,17 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSett
|
||||
import nodomain.freeyourgadget.gadgetbridge.capabilities.password.PasswordCapabilityImpl;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSleepStateDetection;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdateDeviceInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventWearState;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.xiaomi.XiaomiFWHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.SleepState;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WearingState;
|
||||
import nodomain.freeyourgadget.gadgetbridge.proto.xiaomi.XiaomiProto;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetProgressAction;
|
||||
@ -73,11 +77,14 @@ public class XiaomiSystemService extends AbstractXiaomiService implements Xiaomi
|
||||
public static final int CMD_PASSWORD_SET = 21;
|
||||
public static final int CMD_DISPLAY_ITEMS_GET = 29;
|
||||
public static final int CMD_DISPLAY_ITEMS_SET = 30;
|
||||
public static final int CMD_DEVICE_STATE_GET = 78;
|
||||
public static final int CMD_DEVICE_STATE = 79;
|
||||
|
||||
// Not null if we're installing a firmware
|
||||
private XiaomiFWHelper fwHelper = null;
|
||||
private XiaomiProto.DeviceState cachedDeviceState = null;
|
||||
private WearingState currentWearingState = WearingState.UNKNOWN;
|
||||
private BatteryState currentBatteryState = BatteryState.UNKNOWN;
|
||||
private SleepState currentSleepDetectionState = SleepState.UNKNOWN;
|
||||
|
||||
public XiaomiSystemService(final XiaomiSupport support) {
|
||||
super(support);
|
||||
@ -87,7 +94,10 @@ public class XiaomiSystemService extends AbstractXiaomiService implements Xiaomi
|
||||
public void initialize() {
|
||||
// Request device info and configs
|
||||
getSupport().sendCommand("get device info", COMMAND_TYPE, CMD_DEVICE_INFO);
|
||||
getSupport().sendCommand("get battery", COMMAND_TYPE, CMD_BATTERY);
|
||||
getSupport().sendCommand("get device status", COMMAND_TYPE, CMD_DEVICE_STATE_GET);
|
||||
// device status request may initialize wearing, charger, sleeping, and activity state, so
|
||||
// get battery level as a failsafe for devices that don't support CMD_DEVICE_STATE_SET command
|
||||
getSupport().sendCommand("get battery state", COMMAND_TYPE, CMD_BATTERY);
|
||||
getSupport().sendCommand("get password", COMMAND_TYPE, CMD_PASSWORD_GET);
|
||||
getSupport().sendCommand("get display items", COMMAND_TYPE, CMD_DISPLAY_ITEMS_GET);
|
||||
}
|
||||
@ -129,14 +139,15 @@ public class XiaomiSystemService extends AbstractXiaomiService implements Xiaomi
|
||||
case CMD_DISPLAY_ITEMS_GET:
|
||||
handleDisplayItems(cmd.getSystem().getDisplayItems());
|
||||
return;
|
||||
case CMD_DEVICE_STATE_GET:
|
||||
handleBasicDeviceState(cmd.getSystem().hasBasicDeviceState()
|
||||
? cmd.getSystem().getBasicDeviceState()
|
||||
: null);
|
||||
return;
|
||||
case CMD_DEVICE_STATE:
|
||||
// some devices (e.g. Xiaomi Watch S1 Active) only broadcast the charger state through
|
||||
// this message, so this will need to be kept cached to process when the battery levels
|
||||
// get requested
|
||||
cachedDeviceState = cmd.getSystem().getDeviceState();
|
||||
|
||||
// request battery state to request battery level and charger state on supported models
|
||||
getSupport().sendCommand("request battery state", COMMAND_TYPE, CMD_BATTERY);
|
||||
handleDeviceState(cmd.getSystem().hasDeviceState()
|
||||
? cmd.getSystem().getDeviceState()
|
||||
: null);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -246,6 +257,17 @@ public class XiaomiSystemService extends AbstractXiaomiService implements Xiaomi
|
||||
getSupport().evaluateGBDeviceEvent(gbDeviceEventUpdateDeviceInfo);
|
||||
}
|
||||
|
||||
private BatteryState convertBatteryStateFromRawValue(int chargerState) {
|
||||
switch (chargerState) {
|
||||
case 1:
|
||||
return BatteryState.BATTERY_CHARGING;
|
||||
case 2:
|
||||
return BatteryState.BATTERY_NORMAL;
|
||||
}
|
||||
|
||||
return BatteryState.UNKNOWN;
|
||||
}
|
||||
|
||||
private void handleBattery(final XiaomiProto.Battery battery) {
|
||||
LOG.debug("Got battery: {}", battery.getLevel());
|
||||
|
||||
@ -253,25 +275,18 @@ public class XiaomiSystemService extends AbstractXiaomiService implements Xiaomi
|
||||
batteryInfo.batteryIndex = 0;
|
||||
batteryInfo.level = battery.getLevel();
|
||||
|
||||
int chargerState = battery.getState();
|
||||
// currentBatteryState may already be set if the DeviceState message contained the field,
|
||||
// but since some models report their charger state through this message, we will update it
|
||||
// from here
|
||||
if (battery.hasState()) {
|
||||
currentBatteryState = convertBatteryStateFromRawValue(battery.getState());
|
||||
|
||||
// if device state is cached and the charging state there is set, take the charger status
|
||||
// from there
|
||||
if (cachedDeviceState != null && cachedDeviceState.hasChargingState()) {
|
||||
chargerState = cachedDeviceState.getChargingState();
|
||||
}
|
||||
|
||||
switch (chargerState) {
|
||||
case 1:
|
||||
batteryInfo.state = BatteryState.BATTERY_CHARGING;
|
||||
break;
|
||||
case 2:
|
||||
batteryInfo.state = BatteryState.BATTERY_NORMAL;
|
||||
break;
|
||||
default:
|
||||
batteryInfo.state = BatteryState.UNKNOWN;
|
||||
if (currentBatteryState == BatteryState.UNKNOWN) {
|
||||
LOG.warn("Unknown battery state {}", battery.getState());
|
||||
}
|
||||
}
|
||||
|
||||
batteryInfo.state = currentBatteryState;
|
||||
getSupport().evaluateGBDeviceEvent(batteryInfo);
|
||||
}
|
||||
|
||||
@ -446,6 +461,155 @@ public class XiaomiSystemService extends AbstractXiaomiService implements Xiaomi
|
||||
getSupport().evaluateGBDeviceEvent(eventUpdatePreferences);
|
||||
}
|
||||
|
||||
private void handleWearingState(int newStateValue) {
|
||||
WearingState newState;
|
||||
|
||||
switch (newStateValue) {
|
||||
case 1:
|
||||
newState = WearingState.WEARING;
|
||||
break;
|
||||
case 2:
|
||||
newState = WearingState.NOT_WEARING;
|
||||
break;
|
||||
default:
|
||||
LOG.warn("Unknown wearing state {}", newStateValue);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.debug("Current wearing state = {}, new wearing state = {}", currentWearingState, newState);
|
||||
|
||||
if (currentWearingState != WearingState.UNKNOWN && currentWearingState != newState) {
|
||||
GBDeviceEventWearState event = new GBDeviceEventWearState();
|
||||
event.wearingState = newState;
|
||||
getSupport().evaluateGBDeviceEvent(event);
|
||||
}
|
||||
|
||||
currentWearingState = newState;
|
||||
}
|
||||
|
||||
private void handleSleepDetectionState(int newStateValue) {
|
||||
SleepState newState;
|
||||
|
||||
switch (newStateValue) {
|
||||
case 1:
|
||||
newState = SleepState.ASLEEP;
|
||||
break;
|
||||
case 2:
|
||||
newState = SleepState.AWAKE;
|
||||
break;
|
||||
default:
|
||||
LOG.warn("Unknown sleep detection state {}", newStateValue);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.debug("Current sleep detection state = {}, new sleep detection state = {}", currentSleepDetectionState, newState);
|
||||
|
||||
if (currentSleepDetectionState != SleepState.UNKNOWN && currentSleepDetectionState != newState) {
|
||||
GBDeviceEventSleepStateDetection event = new GBDeviceEventSleepStateDetection();
|
||||
event.sleepState = newState;
|
||||
getSupport().evaluateGBDeviceEvent(event);
|
||||
}
|
||||
|
||||
currentSleepDetectionState = newState;
|
||||
}
|
||||
|
||||
public void handleBasicDeviceState(XiaomiProto.BasicDeviceState deviceState) {
|
||||
LOG.debug("Got basic device state: {}", deviceState);
|
||||
|
||||
if (null == deviceState) {
|
||||
LOG.warn("Got null for BasicDeviceState, requesting battery state and returning");
|
||||
getSupport().sendCommand("request battery state", COMMAND_TYPE, CMD_BATTERY);
|
||||
return;
|
||||
}
|
||||
|
||||
// handle battery info from message
|
||||
{
|
||||
BatteryState newBatteryState = deviceState.getIsCharging() ? BatteryState.BATTERY_CHARGING : BatteryState.BATTERY_NORMAL;
|
||||
LOG.debug("Previous charging state: {}, new charging state: {}", currentBatteryState, newBatteryState);
|
||||
|
||||
currentBatteryState = newBatteryState;
|
||||
|
||||
// if the device state did not have a battery level, request it from the device through other means.
|
||||
// the battery state is now cached, so that it can be used when another response with battery level is received.
|
||||
if (!deviceState.hasBatteryLevel()) {
|
||||
getSupport().sendCommand("request battery state", COMMAND_TYPE, CMD_BATTERY);
|
||||
} else {
|
||||
GBDeviceEventBatteryInfo event = new GBDeviceEventBatteryInfo();
|
||||
event.batteryIndex = 0;
|
||||
event.state = newBatteryState;
|
||||
event.level = deviceState.getBatteryLevel();
|
||||
getSupport().evaluateGBDeviceEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
// handle sleep state from message
|
||||
{
|
||||
SleepState newSleepState = deviceState.getIsUserAsleep() ? SleepState.ASLEEP : SleepState.AWAKE;
|
||||
LOG.debug("Previous sleep state: {}, new sleep state: {}", currentSleepDetectionState, newSleepState);
|
||||
|
||||
// send event if the previous state is known and the new state is different from cached
|
||||
if (currentSleepDetectionState != SleepState.UNKNOWN && currentSleepDetectionState != newSleepState) {
|
||||
GBDeviceEventSleepStateDetection event = new GBDeviceEventSleepStateDetection();
|
||||
event.sleepState = newSleepState;
|
||||
getSupport().evaluateGBDeviceEvent(event);
|
||||
}
|
||||
|
||||
currentSleepDetectionState = newSleepState;
|
||||
}
|
||||
|
||||
// handle wearing state from message
|
||||
{
|
||||
WearingState newWearingState = deviceState.getIsWorn() ? WearingState.WEARING : WearingState.NOT_WEARING;
|
||||
LOG.debug("Previous wearing state: {}, new wearing state: {}", currentWearingState, newWearingState);
|
||||
|
||||
if (currentWearingState != WearingState.UNKNOWN && currentWearingState != newWearingState) {
|
||||
GBDeviceEventWearState event = new GBDeviceEventWearState();
|
||||
event.wearingState = newWearingState;
|
||||
getSupport().evaluateGBDeviceEvent(event);
|
||||
}
|
||||
|
||||
currentWearingState = newWearingState;
|
||||
}
|
||||
|
||||
// TODO: handle activity state
|
||||
}
|
||||
|
||||
public void handleDeviceState(XiaomiProto.DeviceState deviceState) {
|
||||
LOG.debug("Got device state: {}", deviceState);
|
||||
|
||||
if (null == deviceState) {
|
||||
LOG.warn("Got null for DeviceState, requesting battery state and returning");
|
||||
getSupport().sendCommand("request battery state", COMMAND_TYPE, CMD_BATTERY);
|
||||
return;
|
||||
}
|
||||
|
||||
if (deviceState.hasWearingState()) {
|
||||
handleWearingState(deviceState.getWearingState());
|
||||
}
|
||||
|
||||
// The charger state of some devices can only be known when listening for device status
|
||||
// updates. If available, this state will be cached here and updated in the GBDevice upon
|
||||
// the next retrieval of the battery level
|
||||
if (deviceState.hasChargingState()) {
|
||||
BatteryState newBatteryState = convertBatteryStateFromRawValue(deviceState.getChargingState());
|
||||
|
||||
LOG.debug("Current battery state = {}, new battery state = {}", currentBatteryState, newBatteryState);
|
||||
|
||||
if (currentBatteryState != newBatteryState) {
|
||||
currentBatteryState = newBatteryState;
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceState.hasSleepState()) {
|
||||
handleSleepDetectionState(deviceState.getSleepState());
|
||||
}
|
||||
|
||||
// TODO process warning (unknown possible values) and activity information
|
||||
|
||||
// request battery state to request battery level and charger state on supported models
|
||||
getSupport().sendCommand("request battery state", COMMAND_TYPE, CMD_BATTERY);
|
||||
}
|
||||
|
||||
public void onFindPhone(final boolean start) {
|
||||
LOG.debug("Find phone: {}", start);
|
||||
|
||||
|
@ -129,6 +129,9 @@ message System {
|
||||
// 2, 47
|
||||
optional VibrationPatternAck vibrationPatternAck = 43;
|
||||
|
||||
// 2, 78
|
||||
optional BasicDeviceState basicDeviceState = 48;
|
||||
|
||||
// 2, 79
|
||||
optional DeviceState deviceState = 49;
|
||||
}
|
||||
@ -304,6 +307,14 @@ message DeviceActivityState {
|
||||
optional uint32 currentActivityState = 2;
|
||||
}
|
||||
|
||||
message BasicDeviceState {
|
||||
required bool isCharging = 1; // true when connected to charger
|
||||
optional uint32 batteryLevel = 2;
|
||||
required bool isWorn = 3; // true when the device detects it's being worn
|
||||
required bool isUserAsleep = 4; // true when the device detected its user is asleep
|
||||
optional DeviceActivityState activityState = 5;
|
||||
}
|
||||
|
||||
message DeviceState {
|
||||
optional uint32 chargingState = 1; // 1 charging, 2 not charging
|
||||
optional uint32 wearingState = 2; // 1 wearing, 2 not wearing
|
||||
|
Loading…
Reference in New Issue
Block a user