1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-07-23 23:32:23 +02:00

Make battery thresholds configurable

This commit is contained in:
José Rebelo 2024-06-10 13:51:07 +01:00 committed by José Rebelo
parent 243c1ba039
commit 76d633cde6
46 changed files with 503 additions and 331 deletions

View File

@ -87,6 +87,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import nodomain.freeyourgadget.gadgetbridge.util.preferences.DevicePrefs;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceType.AMAZFITBIP;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceType.AMAZFITCOR;
@ -1501,8 +1502,8 @@ public class GBApplication extends Application {
return context.getSharedPreferences("devicesettings_" + deviceIdentifier, Context.MODE_PRIVATE);
}
public static Prefs getDevicePrefs(final String deviceIdentifier) {
return new Prefs(getDeviceSpecificSharedPrefs(deviceIdentifier));
public static DevicePrefs getDevicePrefs(final String deviceIdentifier) {
return new DevicePrefs(getDeviceSpecificSharedPrefs(deviceIdentifier));
}
public static void deleteDeviceSpecificSharedPrefs(String deviceIdentifier) {

View File

@ -193,7 +193,7 @@ public class BatteryInfoActivity extends AbstractGBActivity {
battery_status_device_name_text.setText(gbDevice.getAliasOrName());
setBatteryLabels();
for (BatteryConfig batteryConfig : coordinator.getBatteryConfig()) {
for (BatteryConfig batteryConfig : coordinator.getBatteryConfig(gbDevice)) {
if (batteryConfig.getBatteryIndex() == batteryIndex) {
battery_status_extra_name.setText(batteryConfig.getBatteryLabel());
battery_status_device_icon.setImageResource(batteryConfig.getBatteryIcon());

View File

@ -34,6 +34,12 @@ public class DeviceSettingsPreferenceConst {
public static final String PREF_HEADER_FTP_SERVER_STATUS = "pref_header_ftp_server_status";
public static final String PREF_HEADER_FTP_SERVER_CONFIGURATION = "pref_header_ftp_server_configuration";
public static final String PREF_BATTERY_SHOW_IN_NOTIFICATION = "battery_show_in_notification_";
public static final String PREF_BATTERY_NOTIFY_LOW_ENABLED = "battery_notify_low_enabled_";
public static final String PREF_BATTERY_NOTIFY_LOW_THRESHOLD = "battery_notify_low_threshold_";
public static final String PREF_BATTERY_NOTIFY_FULL_ENABLED = "battery_notify_full_enabled_";
public static final String PREF_BATTERY_NOTIFY_FULL_THRESHOLD = "battery_notify_full_threshold_";
public static final String PREF_SCREEN_NIGHT_MODE = "pref_screen_night_mode";
public static final String PREF_SCREEN_SLEEP_MODE = "pref_screen_sleep_mode";
public static final String PREF_SCREEN_LIFT_WRIST = "pref_screen_lift_wrist";

View File

@ -43,9 +43,12 @@ import android.os.Bundle;
import android.text.InputType;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.preference.EditTextPreference;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreferenceCompat;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
@ -75,8 +78,11 @@ import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import nodomain.freeyourgadget.gadgetbridge.util.preferences.GBSimpleSummaryProvider;
import nodomain.freeyourgadget.gadgetbridge.util.preferences.MinMaxTextWatcher;
public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment implements DeviceSpecificSettingsHandler {
@ -129,6 +135,8 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
getPreferenceManager().setSharedPreferencesName("devicesettings_" + settingsFileSuffix);
LOG.debug("onCreatePreferences: {}", rootKey);
if (rootKey == null) {
// we are the main preference screen
boolean first = true;
@ -150,6 +158,7 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
// Use the root key here to set the root screen, so that the actionbar title gets updated
setPreferencesFromResource(setting, rootKey);
first = false;
addDynamicSettings(rootKey);
} else {
addPreferencesFromResource(setting);
}
@ -185,6 +194,91 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
setChangeListener();
}
private void addDynamicSettings(final String rootKey) {
if (rootKey.equals(DeviceSpecificSettingsScreen.BATTERY.getKey())) {
addBatterySettings();
}
}
private void addBatterySettings() {
final DeviceCoordinator coordinator = device.getDeviceCoordinator();
final PreferenceScreen batteryScreen = getPreferenceScreen();
if (batteryScreen == null) {
return;
}
final BatteryConfig[] batteryConfigs = coordinator.getBatteryConfig(device);
for (final BatteryConfig batteryConfig : batteryConfigs) {
if (batteryConfigs.length > 1) {
final Preference prefHeader = new PreferenceCategory(requireContext());
prefHeader.setKey("pref_battery_header_" + batteryConfig.getBatteryIndex());
prefHeader.setIconSpaceReserved(false);
if (batteryConfig.getBatteryLabel() > 0) {
prefHeader.setTitle(batteryConfig.getBatteryLabel());
} else {
prefHeader.setTitle(requireContext().getString(R.string.battery_i, batteryConfig.getBatteryIndex()));
}
batteryScreen.addPreference(prefHeader);
}
final SwitchPreferenceCompat showInNotification = new SwitchPreferenceCompat(requireContext());
showInNotification.setLayoutResource(R.layout.preference_checkbox);
showInNotification.setKey(PREF_BATTERY_SHOW_IN_NOTIFICATION + batteryConfig.getBatteryIndex());
showInNotification.setTitle(R.string.show_in_notification);
showInNotification.setIconSpaceReserved(false);
showInNotification.setDefaultValue(true);
batteryScreen.addPreference(showInNotification);
final SwitchPreferenceCompat notifyLowEnabled = new SwitchPreferenceCompat(requireContext());
notifyLowEnabled.setLayoutResource(R.layout.preference_checkbox);
notifyLowEnabled.setKey(PREF_BATTERY_NOTIFY_LOW_ENABLED + batteryConfig.getBatteryIndex());
notifyLowEnabled.setTitle(R.string.battery_low_notify_enabled);
notifyLowEnabled.setDefaultValue(true);
notifyLowEnabled.setIconSpaceReserved(false);
batteryScreen.addPreference(notifyLowEnabled);
final EditTextPreference notifyLowThreshold = new EditTextPreference(requireContext());
notifyLowThreshold.setKey(PREF_BATTERY_NOTIFY_LOW_THRESHOLD + batteryConfig.getBatteryIndex());
notifyLowThreshold.setTitle(R.string.battery_low_threshold);
notifyLowThreshold.setDialogTitle(R.string.battery_low_threshold);
notifyLowThreshold.setIconSpaceReserved(false);
notifyLowThreshold.setOnBindEditTextListener(editText -> {
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
editText.addTextChangedListener(new MinMaxTextWatcher(editText, 0, 100, true));
editText.setSelection(editText.getText().length());
});
notifyLowThreshold.setSummaryProvider(new GBSimpleSummaryProvider(
requireContext().getString(R.string.default_percentage, batteryConfig.getDefaultLowThreshold()),
R.string.battery_percentage_str
));
batteryScreen.addPreference(notifyLowThreshold);
final SwitchPreferenceCompat notifyFullEnabled = new SwitchPreferenceCompat(requireContext());
notifyFullEnabled.setLayoutResource(R.layout.preference_checkbox);
notifyFullEnabled.setKey(PREF_BATTERY_NOTIFY_FULL_ENABLED + batteryConfig.getBatteryIndex());
notifyFullEnabled.setTitle(R.string.battery_full_notify_enabled);
notifyFullEnabled.setDefaultValue(true);
notifyFullEnabled.setIconSpaceReserved(false);
batteryScreen.addPreference(notifyFullEnabled);
final EditTextPreference notifyFullThreshold = new EditTextPreference(requireContext());
notifyFullThreshold.setKey(PREF_BATTERY_NOTIFY_FULL_THRESHOLD + batteryConfig.getBatteryIndex());
notifyFullThreshold.setTitle(R.string.battery_full_threshold);
notifyFullThreshold.setDialogTitle(R.string.battery_full_threshold);
notifyFullThreshold.setIconSpaceReserved(false);
notifyFullThreshold.setOnBindEditTextListener(editText -> {
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
editText.addTextChangedListener(new MinMaxTextWatcher(editText, 0, 100, true));
editText.setSelection(editText.getText().length());
});
notifyFullThreshold.setSummaryProvider(new GBSimpleSummaryProvider(
requireContext().getString(R.string.default_percentage, batteryConfig.getDefaultFullThreshold()),
R.string.battery_percentage_str
));
batteryScreen.addPreference(notifyFullThreshold);
}
}
/*
* delayed execution so that the preferences are applied first
*/
@ -1110,6 +1204,12 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
coordinator.getSupportedDeviceSpecificConnectionSettings()
);
if (coordinator.getBatteryCount() > 0) {
deviceSpecificSettings.addRootScreen(
DeviceSpecificSettingsScreen.BATTERY
);
}
if (coordinator.supportsActivityTracking()) {
deviceSpecificSettings.addRootScreen(
DeviceSpecificSettingsScreen.ACTIVITY_INFO,

View File

@ -24,6 +24,7 @@ public enum DeviceSpecificSettingsScreen {
ACTIVITY_INFO("pref_screen_activity_info", R.xml.devicesettings_root_activity_info),
AUDIO("pref_screen_audio", R.xml.devicesettings_root_audio),
AUTHENTICATION("pref_screen_authentication", R.xml.devicesettings_root_authentication),
BATTERY("pref_screen_battery", R.xml.devicesettings_root_battery),
CALENDAR("pref_screen_calendar", R.xml.devicesettings_root_calendar),
CALLS_AND_NOTIFICATIONS("pref_screen_calls_and_notifications", R.xml.devicesettings_root_calls_and_notifications),
CONNECTION("pref_screen_connection", R.xml.devicesettings_root_connection),

View File

@ -133,7 +133,7 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
@Override
public GBDevice createDevice(GBDeviceCandidate candidate, DeviceType deviceType) {
GBDevice gbDevice = new GBDevice(candidate.getDevice().getAddress(), candidate.getName(), null, null, deviceType);
for (BatteryConfig batteryConfig : getBatteryConfig()) {
for (BatteryConfig batteryConfig : getBatteryConfig(gbDevice)) {
gbDevice.setBatteryIcon(batteryConfig.getBatteryIcon(), batteryConfig.getBatteryIndex());
gbDevice.setBatteryLabel(batteryConfig.getBatteryLabel(), batteryConfig.getBatteryIndex());
}
@ -684,8 +684,12 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
} //multiple battery support, default is 1, maximum is 3, 0 will disable the battery in UI
@Override
public BatteryConfig[] getBatteryConfig() {
return new BatteryConfig[0];
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
final BatteryConfig[] batteryConfigs = new BatteryConfig[getBatteryCount()];
for (int i = 0; i < getBatteryCount(); i++) {
batteryConfigs[i] = new BatteryConfig(i);
}
return batteryConfigs;
}
@Override

View File

@ -649,7 +649,7 @@ public interface DeviceCoordinator {
*/
int getBatteryCount();
BatteryConfig[] getBatteryConfig();
BatteryConfig[] getBatteryConfig(GBDevice device);
boolean supportsPowerOff();

View File

@ -47,6 +47,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.banglejs.BangleJSDeviceSupport;
@ -192,6 +193,19 @@ public class BangleJSCoordinator extends AbstractBLEDeviceCoordinator {
return true;
}
@Override
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
return new BatteryConfig[]{
new BatteryConfig(
0,
GBDevice.BATTERY_ICON_DEFAULT,
GBDevice.BATTERY_LABEL_DEFAULT,
15,
100
)
};
}
@Override
public int[] getSupportedDeviceSpecificSettings(final GBDevice device) {
final List<Integer> settings = new ArrayList<>();

View File

@ -43,7 +43,7 @@ public class GalaxyBuds2DeviceCoordinator extends GalaxyBudsGenericCoordinator {
}
@Override
public BatteryConfig[] getBatteryConfig() {
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
BatteryConfig battery1 = new BatteryConfig(0, R.drawable.ic_buds_pro_case, R.string.battery_case);
BatteryConfig battery2 = new BatteryConfig(1, R.drawable.ic_buds_pro_left, R.string.left_earbud);
BatteryConfig battery3 = new BatteryConfig(2, R.drawable.ic_buds_pro_right, R.string.right_earbud);

View File

@ -44,7 +44,7 @@ public class GalaxyBuds2ProDeviceCoordinator extends GalaxyBudsGenericCoordinato
}
@Override
public BatteryConfig[] getBatteryConfig() {
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
BatteryConfig battery1 = new BatteryConfig(0, R.drawable.ic_buds_pro_case, R.string.battery_case);
BatteryConfig battery2 = new BatteryConfig(1, R.drawable.ic_buds_pro_left, R.string.left_earbud);
BatteryConfig battery3 = new BatteryConfig(2, R.drawable.ic_buds_pro_right, R.string.right_earbud);

View File

@ -38,7 +38,7 @@ public class GalaxyBudsDeviceCoordinator extends GalaxyBudsGenericCoordinator {
}
@Override
public BatteryConfig[] getBatteryConfig() {
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
BatteryConfig battery1 = new BatteryConfig(0, R.drawable.ic_galaxy_buds_l, R.string.left_earbud);
BatteryConfig battery2 = new BatteryConfig(1, R.drawable.ic_galaxy_buds_r, R.string.right_earbud);
return new BatteryConfig[]{battery1, battery2};

View File

@ -37,7 +37,7 @@ public class GalaxyBudsLiveDeviceCoordinator extends GalaxyBudsGenericCoordinato
}
@Override
public BatteryConfig[] getBatteryConfig() {
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
BatteryConfig battery1 = new BatteryConfig(0, R.drawable.ic_tws_case, R.string.battery_case);
BatteryConfig battery2 = new BatteryConfig(1, R.drawable.ic_galaxy_buds_live_l, R.string.left_earbud);
BatteryConfig battery3 = new BatteryConfig(2, R.drawable.ic_galaxy_buds_live_r, R.string.right_earbud);

View File

@ -44,7 +44,7 @@ public class GalaxyBudsProDeviceCoordinator extends GalaxyBudsGenericCoordinator
}
@Override
public BatteryConfig[] getBatteryConfig() {
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
BatteryConfig battery1 = new BatteryConfig(0, R.drawable.ic_buds_pro_case, R.string.battery_case);
BatteryConfig battery2 = new BatteryConfig(1, R.drawable.ic_buds_pro_left, R.string.left_earbud);
BatteryConfig battery3 = new BatteryConfig(2, R.drawable.ic_buds_pro_right, R.string.right_earbud);

View File

@ -67,6 +67,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
import nodomain.freeyourgadget.gadgetbridge.util.XDatePreference;
import nodomain.freeyourgadget.gadgetbridge.util.XTimePreference;
import nodomain.freeyourgadget.gadgetbridge.util.preferences.MinMaxTextWatcher;
public class GarminRealtimeSettingsFragment extends AbstractPreferenceFragment {
private static final Logger LOG = LoggerFactory.getLogger(GarminRealtimeSettingsFragment.class);
@ -851,43 +852,4 @@ public class GarminRealtimeSettingsFragment extends AbstractPreferenceFragment {
).build();
GBApplication.deviceService(device).onSendConfiguration("protobuf:" + GB.hexdump(smart.toByteArray()));
}
private static class MinMaxTextWatcher implements TextWatcher {
private final EditText editText;
private final int min;
private final int max;
private MinMaxTextWatcher(final EditText editText, final int min, final int max) {
this.editText = editText;
this.min = min;
this.max = max;
}
@Override
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
}
@Override
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
}
@Override
public void afterTextChanged(final Editable editable) {
try {
final int val = Integer.parseInt(editable.toString());
editText.getRootView().findViewById(android.R.id.button1)
.setEnabled(val >= min && val <= max);
if (val < min) {
editText.setError(editText.getContext().getString(R.string.min_val, min));
} else if (val > max) {
editText.setError(editText.getContext().getString(R.string.max_val, max));
} else {
editText.setError(null);
}
} catch (final NumberFormatException e) {
editText.getRootView().findViewById(android.R.id.button1)
.setEnabled(false);
}
}
}
}

View File

@ -22,7 +22,6 @@ import android.content.Context;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import nodomain.freeyourgadget.gadgetbridge.GBException;
import nodomain.freeyourgadget.gadgetbridge.R;
@ -34,6 +33,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.LefunDeviceSupport;
@ -72,12 +72,6 @@ public class LefunDeviceCoordinator extends AbstractBLEDeviceCoordinator {
return false;
}
@Nullable
@Override
public Class<? extends Activity> getPairingActivity() {
return null;
}
@Override
public boolean supportsActivityDataFetching() {
return true;
@ -98,11 +92,6 @@ public class LefunDeviceCoordinator extends AbstractBLEDeviceCoordinator {
return null;
}
@Override
public boolean supportsScreenshots(final GBDevice device) {
return false;
}
@Override
public int getAlarmSlotCount(GBDevice device) {
return NUM_ALARM_SLOTS;
@ -118,34 +107,27 @@ public class LefunDeviceCoordinator extends AbstractBLEDeviceCoordinator {
return MANUFACTURER_NAME;
}
@Override
public boolean supportsAppsManagement(final GBDevice device) {
return false;
}
@Override
public Class<? extends Activity> getAppsManagementActivity() {
return null;
}
@Override
public boolean supportsCalendarEvents() {
return false;
}
@Override
public boolean supportsRealtimeData() {
return true;
}
@Override
public boolean supportsWeather() {
return false;
public boolean supportsFindDevice() {
return true;
}
@Override
public boolean supportsFindDevice() {
return true;
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
return new BatteryConfig[]{
new BatteryConfig(
0,
GBDevice.BATTERY_ICON_DEFAULT,
GBDevice.BATTERY_LABEL_DEFAULT,
15,
100
)
};
}
@Override
@ -167,13 +149,11 @@ public class LefunDeviceCoordinator extends AbstractBLEDeviceCoordinator {
return LefunDeviceSupport.class;
}
@Override
public int getDeviceNameResource() {
return R.string.devicetype_lefun;
}
@Override
public int getDefaultIconResource() {
return R.drawable.ic_device_h30_h10;

View File

@ -61,7 +61,7 @@ public abstract class AbstractEarCoordinator extends AbstractBLClassicDeviceCoor
}
@Override
public BatteryConfig[] getBatteryConfig() {
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
BatteryConfig battery1 = new BatteryConfig(0, R.drawable.ic_tws_case, R.string.battery_case);
BatteryConfig battery2 = new BatteryConfig(1, R.drawable.ic_nothing_ear_l, R.string.left_earbud);
BatteryConfig battery3 = new BatteryConfig(2, R.drawable.ic_nothing_ear_r, R.string.right_earbud);

View File

@ -17,25 +17,18 @@
package nodomain.freeyourgadget.gadgetbridge.devices.qc35;
import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.GBException;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLClassicDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qc35.QC35BaseSupport;
@ -50,12 +43,6 @@ public class QC35Coordinator extends AbstractBLClassicDeviceCoordinator {
return Pattern.compile("Bose QC 35.*");
}
@Nullable
@Override
public Class<? extends Activity> getPairingActivity() {
return null;
}
@Override
public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
return new int[]{
@ -69,82 +56,28 @@ public class QC35Coordinator extends AbstractBLClassicDeviceCoordinator {
return QC35BaseSupport.class;
}
@Override
public boolean supportsActivityDataFetching() {
return false;
}
@Override
public boolean supportsActivityTracking() {
return false;
}
@Override
public SampleProvider<? extends ActivitySample> getSampleProvider(GBDevice device, DaoSession session) {
return null;
}
@Override
public InstallHandler findInstallHandler(Uri uri, Context context) {
return null;
}
@Override
public boolean supportsScreenshots(final GBDevice device) {
return false;
}
@Override
public int getAlarmSlotCount(GBDevice device) {
return 0;
}
@Override
public boolean supportsHeartRateMeasurement(GBDevice device) {
return false;
}
@Override
public String getManufacturer() {
return "Bose";
}
@Override
public boolean supportsAppsManagement(final GBDevice device) {
return false;
}
@Override
public Class<? extends Activity> getAppsManagementActivity() {
return null;
}
@Override
public boolean supportsCalendarEvents() {
return false;
}
@Override
public boolean supportsRealtimeData() {
return false;
}
@Override
public boolean supportsWeather() {
return false;
}
@Override
public boolean supportsFindDevice() {
return false;
}
@Override
public int getDeviceNameResource() {
return R.string.devicetype_bose_qc35;
}
@Override
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
return new BatteryConfig[]{
new BatteryConfig(
0,
GBDevice.BATTERY_ICON_DEFAULT,
GBDevice.BATTERY_LABEL_DEFAULT,
25,
100
)
};
}
@Override
public int getDefaultIconResource() {

View File

@ -25,7 +25,6 @@ import android.net.Uri;
import android.os.ParcelUuid;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -46,12 +45,12 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpec
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.cmfwatchpro.CmfWatchProSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport;
@ -78,13 +77,6 @@ public class QHybridCoordinator extends AbstractBLEDeviceCoordinator {
return Collections.singletonList(new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString("3dda0001-957f-7d4a-34a6-74696673696d")).build());
}
@Nullable
@Override
public Class<? extends Activity> getPairingActivity() {
return null;
}
@Override
public boolean supportsActivityDataFetching() {
List<GBDevice> devices = GBApplication.app().getDeviceManager().getSelectedDevices();
@ -126,14 +118,6 @@ public class QHybridCoordinator extends AbstractBLEDeviceCoordinator {
return installHandler.isValid() ? installHandler : null;
}
@Override
public boolean supportsFlashing() { return false; }
@Override
public boolean supportsScreenshots(final GBDevice device) {
return false;
}
private boolean supportsAlarmConfiguration() {
List<GBDevice> devices = GBApplication.app().getDeviceManager().getSelectedDevices();
LOG.debug("devices count: " + devices.size());
@ -223,16 +207,6 @@ public class QHybridCoordinator extends AbstractBLEDeviceCoordinator {
return ".wapp";
}
@Override
public boolean supportsCalendarEvents() {
return false;
}
@Override
public boolean supportsRealtimeData() {
return false;
}
@Override
public boolean supportsWeather() {
return isHybridHR();
@ -248,6 +222,19 @@ public class QHybridCoordinator extends AbstractBLEDeviceCoordinator {
}
@Override
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
return new BatteryConfig[]{
new BatteryConfig(
0,
GBDevice.BATTERY_ICON_DEFAULT,
GBDevice.BATTERY_LABEL_DEFAULT,
isHybridHR(device) ? 10 : 2,
100
)
};
}
@Override
public DeviceSpecificSettings getDeviceSpecificSettings(final GBDevice device) {
final DeviceSpecificSettings deviceSpecificSettings = new DeviceSpecificSettings();

View File

@ -17,12 +17,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones;
import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.apache.commons.lang3.ArrayUtils;
@ -38,12 +33,10 @@ import nodomain.freeyourgadget.gadgetbridge.GBException;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLClassicDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.SonyHeadphonesSupport;
@ -67,77 +60,6 @@ public abstract class SonyHeadphonesCoordinator extends AbstractBLClassicDeviceC
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
}
@Nullable
@Override
public Class<? extends Activity> getPairingActivity() {
return null;
}
@Override
public boolean supportsActivityDataFetching() {
return false;
}
@Override
public boolean supportsActivityTracking() {
return false;
}
@Override
public SampleProvider<? extends ActivitySample> getSampleProvider(GBDevice device, DaoSession session) {
return null;
}
@Override
public InstallHandler findInstallHandler(Uri uri, Context context) {
return null;
}
@Override
public boolean supportsScreenshots(final GBDevice device) {
return false;
}
@Override
public int getAlarmSlotCount(GBDevice device) {
return 0;
}
@Override
public boolean supportsHeartRateMeasurement(GBDevice device) {
return false;
}
@Override
public boolean supportsAppsManagement(final GBDevice device) {
return false;
}
@Override
public Class<? extends Activity> getAppsManagementActivity() {
return null;
}
@Override
public boolean supportsCalendarEvents() {
return false;
}
@Override
public boolean supportsRealtimeData() {
return false;
}
@Override
public boolean supportsWeather() {
return false;
}
@Override
public boolean supportsFindDevice() {
return false;
}
@Override
public boolean supportsPowerOff() {
return supports(SonyHeadphonesCapabilities.PowerOffFromPhone);
@ -170,6 +92,26 @@ public abstract class SonyHeadphonesCoordinator extends AbstractBLClassicDeviceC
return batteryCount;
}
@Override
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
final List<BatteryConfig> batteries = new ArrayList<>(3);
if (supports(SonyHeadphonesCapabilities.BatterySingle)) {
batteries.add(new BatteryConfig(batteries.size()));
}
if (supports(SonyHeadphonesCapabilities.BatteryCase)) {
batteries.add(new BatteryConfig(batteries.size(), R.drawable.ic_tws_case, R.string.battery_case));
}
if (supports(SonyHeadphonesCapabilities.BatteryDual)) {
batteries.add(new BatteryConfig(batteries.size(), R.drawable.ic_galaxy_buds_l, R.string.left_earbud));
batteries.add(new BatteryConfig(batteries.size(), R.drawable.ic_galaxy_buds_r, R.string.right_earbud));
}
return batteries.toArray(new BatteryConfig[0]);
}
@Override
public int[] getSupportedDeviceSpecificSettings(final GBDevice device) {
final List<Integer> settings = new ArrayList<>();

View File

@ -25,6 +25,7 @@ import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCapabilities;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCoordinator;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
@ -36,7 +37,7 @@ public class SonyWF1000XM3Coordinator extends SonyHeadphonesCoordinator {
}
@Override
public BatteryConfig[] getBatteryConfig() {
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
final BatteryConfig battery1 = new BatteryConfig(0, R.drawable.ic_tws_case, R.string.battery_case);
final BatteryConfig battery2 = new BatteryConfig(1, R.drawable.ic_galaxy_buds_l, R.string.left_earbud);
final BatteryConfig battery3 = new BatteryConfig(2, R.drawable.ic_galaxy_buds_r, R.string.right_earbud);

View File

@ -23,6 +23,7 @@ import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCapabilities;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCoordinator;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
public class SonyWF1000XM4Coordinator extends SonyHeadphonesCoordinator {
@ -32,7 +33,7 @@ public class SonyWF1000XM4Coordinator extends SonyHeadphonesCoordinator {
}
@Override
public BatteryConfig[] getBatteryConfig() {
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
final BatteryConfig battery1 = new BatteryConfig(0, R.drawable.ic_tws_case, R.string.battery_case);
final BatteryConfig battery2 = new BatteryConfig(1, R.drawable.ic_galaxy_buds_l, R.string.left_earbud);
final BatteryConfig battery3 = new BatteryConfig(2, R.drawable.ic_galaxy_buds_r, R.string.right_earbud);

View File

@ -25,6 +25,7 @@ import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCapabilities;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCoordinator;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
@ -36,7 +37,7 @@ public class SonyWF1000XM5Coordinator extends SonyHeadphonesCoordinator {
}
@Override
public BatteryConfig[] getBatteryConfig() {
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
final BatteryConfig battery1 = new BatteryConfig(0, R.drawable.ic_tws_case, R.string.battery_case);
final BatteryConfig battery2 = new BatteryConfig(1, R.drawable.ic_galaxy_buds_l, R.string.left_earbud);
final BatteryConfig battery3 = new BatteryConfig(2, R.drawable.ic_galaxy_buds_r, R.string.right_earbud);

View File

@ -25,9 +25,8 @@ import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCapabilities;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCoordinator;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
public class SonyWFSP800NCoordinator extends SonyHeadphonesCoordinator {
@Override
@ -36,7 +35,7 @@ public class SonyWFSP800NCoordinator extends SonyHeadphonesCoordinator {
}
@Override
public BatteryConfig[] getBatteryConfig() {
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
final BatteryConfig battery1 = new BatteryConfig(0, R.drawable.ic_sony_wf_800n_case, R.string.battery_case);
final BatteryConfig battery2 = new BatteryConfig(1, R.drawable.ic_sony_wf_800n_left, R.string.left_earbud);
final BatteryConfig battery3 = new BatteryConfig(2, R.drawable.ic_sony_wf_800n_right, R.string.right_earbud);

View File

@ -58,7 +58,7 @@ public class SoundcoreLiberty3ProCoordinator extends AbstractDeviceCoordinator {
}
@Override
public BatteryConfig[] getBatteryConfig() {
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
BatteryConfig battery1 = new BatteryConfig(0, R.drawable.ic_buds_pro_case, R.string.battery_case);
BatteryConfig battery2 = new BatteryConfig(1, R.drawable.ic_nothing_ear_l, R.string.left_earbud);
BatteryConfig battery3 = new BatteryConfig(2, R.drawable.ic_nothing_ear_r, R.string.right_earbud);

View File

@ -518,9 +518,9 @@ public class TestDeviceCoordinator extends AbstractDeviceCoordinator {
}
@Override
public BatteryConfig[] getBatteryConfig() {
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
if (getBatteryCount() == 1) {
return super.getBatteryConfig();
return super.getBatteryConfig(device);
}
final BatteryConfig[] ret = new BatteryConfig[getBatteryCount()];

View File

@ -64,7 +64,6 @@ public class GBDevice implements Parcelable {
public static final short BATTERY_UNKNOWN = -1;
public static final short BATTERY_ICON_DEFAULT = -1;
public static final short BATTERY_LABEL_DEFAULT = -1;
private static final short BATTERY_THRESHOLD_PERCENT = 10;
public static final String EXTRA_DEVICE = "device";
public static final String EXTRA_UUID = "extraUUID";
public static final String EXTRA_UPDATE_SUBJECT = "EXTRA_UPDATE_SUBJECT";
@ -88,7 +87,6 @@ public class GBDevice implements Parcelable {
// multiple battery support: at this point we support up to three batteries
private int[] mBatteryLevel = {BATTERY_UNKNOWN, BATTERY_UNKNOWN, BATTERY_UNKNOWN};
private float[] mBatteryVoltage = {BATTERY_UNKNOWN, BATTERY_UNKNOWN, BATTERY_UNKNOWN};
private short mBatteryThresholdPercent = BATTERY_THRESHOLD_PERCENT;
private BatteryState[] mBatteryState = {UNKNOWN, UNKNOWN, UNKNOWN};
private int[] mBatteryIcons = {BATTERY_ICON_DEFAULT, BATTERY_ICON_DEFAULT, BATTERY_ICON_DEFAULT};
private int[] mBatteryLabels = {BATTERY_LABEL_DEFAULT, BATTERY_LABEL_DEFAULT, BATTERY_LABEL_DEFAULT};
@ -136,7 +134,6 @@ public class GBDevice implements Parcelable {
mState = State.values()[in.readInt()];
mBatteryLevel = in.createIntArray();
mBatteryVoltage = in.createFloatArray();
mBatteryThresholdPercent = (short) in.readInt();
mBatteryState = ordinalsToEnums(in.createIntArray());
mBatteryIcons = in.createIntArray();
mBatteryLabels = in.createIntArray();
@ -166,7 +163,6 @@ public class GBDevice implements Parcelable {
mState = device.mState;
mBatteryLevel = device.mBatteryLevel;
mBatteryVoltage = device.mBatteryVoltage;
mBatteryThresholdPercent = device.mBatteryThresholdPercent;
mBatteryState = device.mBatteryState;
mBatteryIcons = device.mBatteryIcons;
mBatteryLabels = device.mBatteryLabels;
@ -193,7 +189,6 @@ public class GBDevice implements Parcelable {
dest.writeInt(mState.ordinal());
dest.writeIntArray(mBatteryLevel);
dest.writeFloatArray(mBatteryVoltage);
dest.writeInt(mBatteryThresholdPercent);
dest.writeIntArray(enumsToOrdinals(mBatteryState));
dest.writeIntArray(mBatteryIcons);
dest.writeIntArray(mBatteryLabels);
@ -612,14 +607,6 @@ public class GBDevice implements Parcelable {
this.mBatteryState[index] = mBatteryState;
}
public short getBatteryThresholdPercent() {
return mBatteryThresholdPercent;
}
public void setBatteryThresholdPercent(short batteryThresholdPercent) {
this.mBatteryThresholdPercent = batteryThresholdPercent;
}
public int getBatteryIcon(int index) {
return this.mBatteryIcons[index];
}

View File

@ -19,16 +19,29 @@ package nodomain.freeyourgadget.gadgetbridge.model;
import java.util.Objects;
public class BatteryConfig {
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
public class BatteryConfig {
private final int batteryIndex;
private final int batteryIcon;
private final int batteryLabel;
private final int defaultLowThreshold;
private final int defaultFullThreshold;
public BatteryConfig(int batteryIndex) {
this(batteryIndex, GBDevice.BATTERY_ICON_DEFAULT, GBDevice.BATTERY_LABEL_DEFAULT);
}
public BatteryConfig(int batteryIndex, int batteryIcon, int batteryLabel) {
this(batteryIndex, batteryIcon, batteryLabel, 10, 100);
}
public BatteryConfig(final int batteryIndex, final int batteryIcon, final int batteryLabel, final int defaultLowThreshold, final int defaultFullThreshold) {
this.batteryIndex = batteryIndex;
this.batteryIcon = batteryIcon;
this.batteryLabel = batteryLabel;
this.defaultLowThreshold = defaultLowThreshold;
this.defaultFullThreshold = defaultFullThreshold;
}
public int getBatteryIndex() {
@ -43,6 +56,14 @@ public class BatteryConfig {
return batteryLabel;
}
public int getDefaultLowThreshold() {
return defaultLowThreshold;
}
public int getDefaultFullThreshold() {
return defaultFullThreshold;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View File

@ -92,6 +92,7 @@ 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.BatteryConfig;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
@ -112,6 +113,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.PendingIntentUtils;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import nodomain.freeyourgadget.gadgetbridge.util.SilentMode;
import nodomain.freeyourgadget.gadgetbridge.util.preferences.DevicePrefs;
import static nodomain.freeyourgadget.gadgetbridge.util.GB.NOTIFICATION_CHANNEL_HIGH_PRIORITY_ID;
@ -529,36 +531,54 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
gbDevice.setBatteryState(deviceEvent.state);
gbDevice.setBatteryVoltage(deviceEvent.voltage, deviceEvent.batteryIndex);
final DevicePrefs devicePrefs = GBApplication.getDevicePrefs(gbDevice.getAddress());
final BatteryConfig batteryConfig = gbDevice.getDeviceCoordinator().getBatteryConfig(gbDevice)[deviceEvent.batteryIndex];
if (deviceEvent.level == GBDevice.BATTERY_UNKNOWN) {
// no level available, just "high" or "low"
if (BatteryState.BATTERY_LOW.equals(deviceEvent.state)) {
GB.updateBatteryNotification(context.getString(R.string.notif_battery_low, gbDevice.getAliasOrName()),
GB.removeBatteryFullNotification(context);
if (devicePrefs.getBatteryNotifyLowEnabled(batteryConfig) && BatteryState.BATTERY_LOW.equals(deviceEvent.state)) {
GB.updateBatteryLowNotification(context.getString(R.string.notif_battery_low, gbDevice.getAliasOrName()),
deviceEvent.extendedInfoAvailable() ?
context.getString(R.string.notif_battery_low_extended, gbDevice.getAliasOrName(),
context.getString(R.string.notif_battery_low_bigtext_last_charge_time, DateFormat.getDateTimeInstance().format(deviceEvent.lastChargeTime.getTime())) +
context.getString(R.string.notif_battery_low_bigtext_number_of_charges, String.valueOf(deviceEvent.numCharges)))
: ""
, context);
} else if (devicePrefs.getBatteryNotifyFullEnabled(batteryConfig) && BatteryState.BATTERY_CHARGING_FULL.equals(deviceEvent.state)) {
GB.removeBatteryLowNotification(context);
GB.updateBatteryFullNotification(context.getString(R.string.notif_battery_full, gbDevice.getAliasOrName()), "", context);
} else {
GB.removeBatteryNotification(context);
GB.removeBatteryLowNotification(context);
GB.removeBatteryFullNotification(context);
}
} else {
createStoreTask("Storing battery data", context, deviceEvent).execute();
final boolean batteryNotifyLowEnabled = devicePrefs.getBatteryNotifyLowEnabled(batteryConfig);
final boolean isBatteryLow = deviceEvent.level <= devicePrefs.getBatteryNotifyLowThreshold(batteryConfig) &&
(BatteryState.BATTERY_LOW.equals(deviceEvent.state) || BatteryState.BATTERY_NORMAL.equals(deviceEvent.state));
final boolean batteryNotifyFullEnabled = devicePrefs.getBatteryNotifyFullEnabled(batteryConfig);
final boolean isBatteryFull = deviceEvent.level >= devicePrefs.getBatteryNotifyFullThreshold(batteryConfig) &&
(BatteryState.BATTERY_CHARGING.equals(deviceEvent.state) || BatteryState.BATTERY_CHARGING_FULL.equals(deviceEvent.state));
//show the notification if the battery level is below threshold and only if not connected to charger
if (deviceEvent.level <= gbDevice.getBatteryThresholdPercent() &&
(BatteryState.BATTERY_LOW.equals(deviceEvent.state) ||
BatteryState.BATTERY_NORMAL.equals(deviceEvent.state))
) {
GB.updateBatteryNotification(context.getString(R.string.notif_battery_low_percent, gbDevice.getAliasOrName(), String.valueOf(deviceEvent.level)),
if (batteryNotifyLowEnabled && isBatteryLow) {
GB.removeBatteryFullNotification(context);
GB.updateBatteryLowNotification(context.getString(R.string.notif_battery_low_percent, gbDevice.getAliasOrName(), String.valueOf(deviceEvent.level)),
deviceEvent.extendedInfoAvailable() ?
context.getString(R.string.notif_battery_low_percent, gbDevice.getAliasOrName(), String.valueOf(deviceEvent.level)) + "\n" +
context.getString(R.string.notif_battery_low_bigtext_last_charge_time, DateFormat.getDateTimeInstance().format(deviceEvent.lastChargeTime.getTime())) +
context.getString(R.string.notif_battery_low_bigtext_number_of_charges, String.valueOf(deviceEvent.numCharges))
: ""
, context);
} else if (batteryNotifyFullEnabled && isBatteryFull) {
GB.removeBatteryLowNotification(context);
GB.updateBatteryFullNotification(context.getString(R.string.notif_battery_full, gbDevice.getAliasOrName()), "", context);
} else {
GB.removeBatteryNotification(context);
GB.removeBatteryLowNotification(context);
GB.removeBatteryFullNotification(context);
}
}

View File

@ -334,7 +334,6 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
gbDevice.setState(GBDevice.State.INITIALIZING);
gbDevice.sendDeviceUpdateIntent(getContext());
gbDevice.setBatteryThresholdPercent((short) 15);
rxCharacteristic = getCharacteristic(BangleJSConstants.UUID_CHARACTERISTIC_NORDIC_UART_RX);
txCharacteristic = getCharacteristic(BangleJSConstants.UUID_CHARACTERISTIC_NORDIC_UART_TX);

View File

@ -19,7 +19,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands.GetBatteryLevelCommand;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.LefunDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.OperationStatus;
@ -40,9 +39,6 @@ public class GetBatteryLevelRequest extends Request {
GetBatteryLevelCommand cmd = new GetBatteryLevelCommand();
cmd.deserialize(data);
GBDevice device = getSupport().getDevice();
device.setBatteryThresholdPercent((short)15);
GBDeviceEventBatteryInfo batteryInfo = new GBDeviceEventBatteryInfo();
batteryInfo.level = (short)((int)cmd.getBatteryLevel() & 0xff);
getSupport().evaluateGBDeviceEvent(batteryInfo);

View File

@ -16,12 +16,6 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.qc35;
import android.net.Uri;
import java.util.ArrayList;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
import nodomain.freeyourgadget.gadgetbridge.service.serial.AbstractSerialDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread;
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
@ -32,7 +26,6 @@ public class QC35BaseSupport extends AbstractSerialDeviceSupport {
public boolean connect() {
getDeviceProtocol();
getDeviceIOThread().start();
getDevice().setBatteryThresholdPercent((short)25);
return true;
}

View File

@ -783,8 +783,6 @@ public class QHybridSupport extends QHybridBaseSupport {
short level = characteristic.getValue()[0];
gbDevice.setBatteryLevel(level);
gbDevice.setBatteryThresholdPercent((short) 2);
GBDeviceEventBatteryInfo batteryInfo = new GBDeviceEventBatteryInfo();
batteryInfo.level = gbDevice.getBatteryLevel();
batteryInfo.state = BatteryState.BATTERY_NORMAL;

View File

@ -169,8 +169,6 @@ public class MisfitWatchAdapter extends WatchAdapter {
short level = characteristic.getValue()[0];
gbDevice.setBatteryLevel(level);
gbDevice.setBatteryThresholdPercent((short) 2);
GBDeviceEventBatteryInfo batteryInfo = new GBDeviceEventBatteryInfo();
batteryInfo.level = gbDevice.getBatteryLevel();
batteryInfo.state = BatteryState.BATTERY_NORMAL;

View File

@ -59,7 +59,6 @@ public class ConfigurationGetRequest extends FileEncryptedLookupAndGetRequest im
}else if(item instanceof ConfigurationPutRequest.BatteryConfigItem){
device.setBatteryLevel((short) ((ConfigurationPutRequest.BatteryConfigItem) item).getBatteryPercentage());
device.setBatteryVoltage(((ConfigurationPutRequest.BatteryConfigItem) item).getBatteryVoltage() / 1000f);
device.setBatteryThresholdPercent((short) 10);
GBDeviceEventBatteryInfo batteryInfo = new GBDeviceEventBatteryInfo();
batteryInfo.level = (short) ((ConfigurationPutRequest.BatteryConfigItem) item).getBatteryPercentage();

View File

@ -194,7 +194,7 @@ public class DeviceHelper {
DeviceType deviceType = DeviceType.fromName(dbDevice.getTypeName());
GBDevice gbDevice = new GBDevice(dbDevice.getIdentifier(), dbDevice.getName(), dbDevice.getAlias(), dbDevice.getParentFolder(), deviceType);
DeviceCoordinator coordinator = gbDevice.getDeviceCoordinator();
for (BatteryConfig batteryConfig : coordinator.getBatteryConfig()) {
for (BatteryConfig batteryConfig : coordinator.getBatteryConfig(gbDevice)) {
gbDevice.setBatteryIcon(batteryConfig.getBatteryIcon(), batteryConfig.getBatteryIndex());
gbDevice.setBatteryLabel(batteryConfig.getBatteryLabel(), batteryConfig.getBatteryIndex());
}

View File

@ -49,6 +49,7 @@ import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -62,6 +63,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
import nodomain.freeyourgadget.gadgetbridge.util.preferences.DevicePrefs;
public class GB {
public static final String ACTION_ACTIVITY_SYNC = "nodomain.freeyourgadget.gadgetbridge.action.ACTIVITY_SYNC_FINISH";
@ -72,6 +74,7 @@ public class GB {
public static final String NOTIFICATION_CHANNEL_HIGH_PRIORITY_ID = "gadgetbridge_high_priority";
public static final String NOTIFICATION_CHANNEL_ID_TRANSFER = "gadgetbridge transfer";
public static final String NOTIFICATION_CHANNEL_ID_LOW_BATTERY = "low_battery";
public static final String NOTIFICATION_CHANNEL_ID_FULL_BATTERY = "full_battery";
public static final String NOTIFICATION_CHANNEL_ID_GPS = "gps";
public static final int NOTIFICATION_ID = 1;
@ -82,6 +85,7 @@ public class GB {
public static final int NOTIFICATION_ID_PHONE_FIND = 6;
public static final int NOTIFICATION_ID_GPS = 7;
public static final int NOTIFICATION_ID_SCAN = 8;
public static final int NOTIFICATION_ID_FULL_BATTERY = 9;
public static final int NOTIFICATION_ID_ERROR = 42;
private static final Logger LOG = LoggerFactory.getLogger(GB.class);
@ -147,6 +151,12 @@ public class GB {
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channelLowBattery);
NotificationChannel channelFullBattery = new NotificationChannel(
NOTIFICATION_CHANNEL_ID_FULL_BATTERY,
context.getString(R.string.notification_channel_full_battery_name),
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channelFullBattery);
NotificationChannel channelGps = new NotificationChannel(
NOTIFICATION_CHANNEL_ID_GPS,
context.getString(R.string.notification_channel_gps),
@ -183,9 +193,8 @@ public class GB {
GBDevice device = devices.get(0);
String deviceName = device.getAliasOrName();
String text = device.getStateString();
if (device.getBatteryLevel() != GBDevice.BATTERY_UNKNOWN) {
text += ": " + context.getString(R.string.battery) + " " + device.getBatteryLevel() + "%";
}
text += buildDeviceBatteryString(context, device);
boolean connected = device.isInitialized();
builder.setContentTitle(deviceName)
@ -230,9 +239,7 @@ public class GB {
String deviceName = device.getAliasOrName();
String text = device.getStateString();
if (device.getBatteryLevel() != GBDevice.BATTERY_UNKNOWN) {
text += ": " + context.getString(R.string.battery) + " " + device.getBatteryLevel() + "%";
}
text += buildDeviceBatteryString(context, device);
contentText.append(deviceName).append(" (").append(text).append(")<br>");
}
@ -271,6 +278,29 @@ public class GB {
return builder.build();
}
public static String buildDeviceBatteryString(final Context context, final GBDevice device) {
final DevicePrefs devicePrefs = GBApplication.getDevicePrefs(device.getAddress());
final List<Integer> batteryLevels = new ArrayList<>();
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < 3; i++) {
if (devicePrefs.getBatteryShowInNotification(i) && device.getBatteryLevel(i) != GBDevice.BATTERY_UNKNOWN) {
batteryLevels.add(device.getBatteryLevel(i));
}
}
if (!batteryLevels.isEmpty()) {
sb.append(": ").append(context.getString(R.string.battery)).append(" ");
for (int i = 0; i < batteryLevels.size(); i++) {
sb.append(batteryLevels.get(i)).append("%");
if (i + 1 < batteryLevels.size()) {
sb.append(", ");
}
}
}
return sb.toString();
}
public static Notification createNotification(String text, Context context) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID_CONNECTION_STATUS);
builder.setTicker(text)
@ -532,7 +562,7 @@ public class GB {
notify(NOTIFICATION_ID_INSTALL, notification, context);
}
private static Notification createBatteryNotification(String text, String bigText, Context context) {
private static Notification createBatteryLowNotification(String text, String bigText, Context context) {
Intent notificationIntent = new Intent(context, ControlCenterv2.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
@ -554,18 +584,52 @@ public class GB {
return nb.build();
}
public static void updateBatteryNotification(String text, String bigText, Context context) {
private static Notification createBatteryFullNotification(String text, String bigText, Context context) {
Intent notificationIntent = new Intent(context, ControlCenterv2.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntentUtils.getActivity(context, 0,
notificationIntent, 0, false);
NotificationCompat.Builder nb = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID_FULL_BATTERY)
.setContentTitle(context.getString(R.string.notif_battery_full_title))
.setContentText(text)
.setContentIntent(pendingIntent)
.setSmallIcon(R.drawable.ic_notification_full_battery)
.setPriority(Notification.PRIORITY_HIGH)
.setOngoing(false);
if (bigText != null) {
nb.setStyle(new NotificationCompat.BigTextStyle().bigText(bigText));
}
return nb.build();
}
public static void updateBatteryLowNotification(String text, String bigText, Context context) {
if (GBEnvironment.env().isLocalTest()) {
return;
}
Notification notification = createBatteryNotification(text, bigText, context);
Notification notification = createBatteryLowNotification(text, bigText, context);
notify(NOTIFICATION_ID_LOW_BATTERY, notification, context);
}
public static void removeBatteryNotification(Context context) {
public static void removeBatteryLowNotification(Context context) {
removeNotification(NOTIFICATION_ID_LOW_BATTERY, context);
}
public static void updateBatteryFullNotification(String text, String bigText, Context context) {
if (GBEnvironment.env().isLocalTest()) {
return;
}
Notification notification = createBatteryFullNotification(text, bigText, context);
notify(NOTIFICATION_ID_FULL_BATTERY, notification, context);
}
public static void removeBatteryFullNotification(Context context) {
removeNotification(NOTIFICATION_ID_FULL_BATTERY, context);
}
public static Notification createExportFailedNotification(String text, Context context) {
Intent notificationIntent = new Intent(context, SettingsActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK

View File

@ -0,0 +1,34 @@
package nodomain.freeyourgadget.gadgetbridge.util.preferences;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.*;
import android.content.SharedPreferences;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class DevicePrefs extends Prefs {
public DevicePrefs(final SharedPreferences preferences) {
super(preferences);
}
public boolean getBatteryShowInNotification(final int batteryIndex) {
return getBoolean(PREF_BATTERY_SHOW_IN_NOTIFICATION + batteryIndex, true);
}
public boolean getBatteryNotifyLowEnabled(final BatteryConfig batteryConfig) {
return getBoolean(PREF_BATTERY_NOTIFY_LOW_ENABLED + batteryConfig.getBatteryIndex(), true);
}
public int getBatteryNotifyLowThreshold(final BatteryConfig batteryConfig) {
return getInt(PREF_BATTERY_NOTIFY_LOW_THRESHOLD + batteryConfig.getBatteryIndex(), batteryConfig.getDefaultLowThreshold());
}
public boolean getBatteryNotifyFullEnabled(final BatteryConfig batteryConfig) {
return getBoolean(PREF_BATTERY_NOTIFY_FULL_ENABLED + batteryConfig.getBatteryIndex(), true);
}
public int getBatteryNotifyFullThreshold(final BatteryConfig batteryConfig) {
return getInt(PREF_BATTERY_NOTIFY_FULL_THRESHOLD + batteryConfig.getBatteryIndex(), batteryConfig.getDefaultFullThreshold());
}
}

View File

@ -0,0 +1,40 @@
package nodomain.freeyourgadget.gadgetbridge.util.preferences;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.preference.EditTextPreference;
import androidx.preference.Preference;
/**
* Like the EditTextPreference.SimpleSummaryProvider, but with a customizable not-set string.
*/
public final class GBSimpleSummaryProvider implements Preference.SummaryProvider<EditTextPreference> {
private final String defaultText;
@StringRes
private final int templateString;
public GBSimpleSummaryProvider(final String defaultText) {
this(defaultText, 0);
}
public GBSimpleSummaryProvider(final String defaultText, final int templateString) {
this.defaultText = defaultText;
this.templateString = templateString;
}
@Nullable
@Override
public CharSequence provideSummary(@NonNull final EditTextPreference preference) {
if (TextUtils.isEmpty(preference.getText())) {
return defaultText;
} else if (templateString != 0) {
return preference.getContext().getString(templateString, preference.getText());
} else {
return preference.getText();
}
}
}

View File

@ -0,0 +1,59 @@
package nodomain.freeyourgadget.gadgetbridge.util.preferences;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.widget.EditText;
import nodomain.freeyourgadget.gadgetbridge.R;
public class MinMaxTextWatcher implements TextWatcher {
private final EditText editText;
private final int min;
private final int max;
private final boolean allowEmpty;
public MinMaxTextWatcher(final EditText editText, final int min, final int max) {
this(editText, min, max, false);
}
public MinMaxTextWatcher(final EditText editText, final int min, final int max, final boolean allowEmpty) {
this.editText = editText;
this.min = min;
this.max = max;
this.allowEmpty = allowEmpty;
}
@Override
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
}
@Override
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
}
@Override
public void afterTextChanged(final Editable editable) {
if (TextUtils.isEmpty(editable.toString()) && allowEmpty) {
editText.getRootView().findViewById(android.R.id.button1)
.setEnabled(true);
return;
}
try {
final int val = Integer.parseInt(editable.toString());
editText.getRootView().findViewById(android.R.id.button1)
.setEnabled(val >= min && val <= max);
if (val < min) {
editText.setError(editText.getContext().getString(R.string.min_val, min));
} else if (val > max) {
editText.setError(editText.getContext().getString(R.string.max_val, max));
} else {
editText.setError(null);
}
} catch (final NumberFormatException e) {
editText.getRootView().findViewById(android.R.id.button1)
.setEnabled(false);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#7E7E7E"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V5.33C17,4.6 16.4,4 15.67,4z" />
</vector>

View File

@ -827,10 +827,12 @@
<string name="pbw_install_handler_hw_revision_mismatch">Unable to install the given firmware: It doesn\'t match your Pebble\'s hardware revision.</string>
<string name="installer_activity_wait_while_determining_status">Please wait while determining the installation status…</string>
<string name="notif_battery_low_title">Gadget battery Low!</string>
<string name="notif_battery_full_title">Gadget battery Full!</string>
<string name="notif_battery_low_percent">%1$s battery left: %2$s%%</string>
<string name="notif_battery_low_bigtext_last_charge_time">Last charge: %s \n</string>
<string name="notif_battery_low_bigtext_number_of_charges">Number of charges: %s</string>
<string name="notif_battery_low">%1$s battery low</string>
<string name="notif_battery_full">%1$s battery full</string>
<string name="notif_battery_low_extended">%1$s battery low: %2$s</string>
<string name="notif_export_failed_title">Export database failed! Please check your settings.</string>
<string name="prefs_charts_tabs">Charts tabs</string>
@ -1603,6 +1605,7 @@
<string name="notification_channel_high_priority_name">High-priority</string>
<string name="notification_channel_transfer_name">Data transfer</string>
<string name="notification_channel_low_battery_name">Low battery</string>
<string name="notification_channel_full_battery_name">Full battery</string>
<string name="notification_channel_gps">GPS tracking</string>
<string name="notification_gps_title">Gadgetbridge GPS</string>
<string name="notification_gps_text">Sending GPS location to %1$d devices</string>
@ -2214,6 +2217,7 @@
<string name="prefs_switch_control_left">Switch control left</string>
<string name="prefs_switch_control_right">Switch control right</string>
<string name="prefs_galaxy_touch_options">Touch Options</string>
<string name="battery_i">Battery %d</string>
<string name="battery_case">Battery case</string>
<string name="left_earbud">Left earbud</string>
<string name="right_earbud">Right earbud</string>
@ -2900,4 +2904,11 @@
<string name="unsupported">Unsupported</string>
<string name="min_val">Minimum: %d</string>
<string name="max_val">Maximum: %d</string>
<string name="show_in_notification">Show in notification</string>
<string name="battery_low_notify_enabled">Notify on low battery</string>
<string name="battery_low_threshold">Low battery threshold</string>
<string name="battery_full_notify_enabled">Notify on full battery</string>
<string name="battery_full_threshold">Full battery threshold</string>
<string name="default_percentage">Default (%1$d%%)</string>
<string name="battery_percentage_str">%1$s%%</string>
</resources>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceScreen
android:icon="@drawable/ic_battery"
android:key="pref_screen_battery"
android:persistent="false"
android:title="@string/battery">
</PreferenceScreen>
</androidx.preference.PreferenceScreen>