1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-27 20:36:51 +01:00

Casio GW-B5600: watch settings

This commit is contained in:
Johannes Krude 2023-09-02 14:40:53 +02:00 committed by José Rebelo
parent b155a13d17
commit 21bfc81b35
18 changed files with 786 additions and 4 deletions

View File

@ -62,6 +62,9 @@ public class DeviceSettingsPreferenceConst {
public static final String PREF_DEVICE_REGION = "device_region";
public static final String PREF_DEVICE_NAME = "pref_device_name";
public static final String PREF_DATEFORMAT = "dateformat";
public static final String PREF_DATEFORMAT_AUTO = "auto";
public static final String PREF_DATEFORMAT_DAY_MONTH = "day_month";
public static final String PREF_DATEFORMAT_MONTH_DAY = "month_day";
public static final String PREF_TIMEFORMAT = "timeformat";
public static final String PREF_TIMEFORMAT_24H = "24h";
public static final String PREF_TIMEFORMAT_12H = "am/pm";
@ -79,6 +82,7 @@ public class DeviceSettingsPreferenceConst {
public static final String PREF_RESERVER_REMINDERS_CALENDAR = "reserve_reminders_calendar";
public static final String PREF_ALLOW_HIGH_MTU = "allow_high_mtu";
public static final String PREF_SYNC_CALENDAR = "sync_calendar";
public static final String PREF_TIME_SYNC = "time_sync";
public static final String PREF_USE_CUSTOM_DEVICEICON = "use_custom_deviceicon";
public static final String PREF_BUTTON_1_FUNCTION_SHORT = "button_1_function_short";
public static final String PREF_BUTTON_2_FUNCTION_SHORT = "button_2_function_short";
@ -202,6 +206,7 @@ public class DeviceSettingsPreferenceConst {
public static final String PREF_AUTOHEARTRATE_END = "pref_autoheartrate_end";
public static final String PREF_POWER_MODE = "power_mode";
public static final String PREF_CONNECTION_DURATION = "connection_duration";
public static final String PREF_BUTTON_BP_CALIBRATE = "prefs_sensors_button_bp_calibration";
public static final String PREF_ALTITUDE_CALIBRATE = "pref_sensors_altitude";
public static final String PREF_DO_NOT_DISTURB_NOAUTO = "do_not_disturb_no_auto";
@ -257,6 +262,7 @@ public class DeviceSettingsPreferenceConst {
public static final String PREF_CASIO_ALERT_OTHER = "casio_alert_other";
public static final String PREF_CASIO_ALERT_SMS = "casio_alert_sms";
public static final String PREF_LIGHT_DURATION_LONGER = "light_duration_longer";
public static final String PREF_AUTOREMOVE_MESSAGE = "autoremove_message";
public static final String PREF_SEND_APP_NOTIFICATIONS = "send_app_notifications";
public static final String PREF_NOTIFICATION_WAKE_ON_OPEN = "notification_wake_on_open";

View File

@ -520,6 +520,8 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
addPreferenceHandlerFor(PREF_BUTTON_3_FUNCTION_DOUBLE);
addPreferenceHandlerFor(PREF_VIBRATION_STRENGH_PERCENTAGE);
addPreferenceHandlerFor(PREF_POWER_MODE);
addPreferenceHandlerFor(PREF_POWER_SAVING);
addPreferenceHandlerFor(PREF_CONNECTION_DURATION);
addPreferenceHandlerFor(PREF_LIFTWRIST_NOSHED);
addPreferenceHandlerFor(PREF_DISCONNECTNOTIF_NOSHED);
addPreferenceHandlerFor(PREF_BUTTON_BP_CALIBRATE);
@ -569,6 +571,7 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
addPreferenceHandlerFor(PREF_FIND_PHONE);
addPreferenceHandlerFor(PREF_FIND_PHONE_DURATION);
addPreferenceHandlerFor(PREF_AUTOLIGHT);
addPreferenceHandlerFor(PREF_LIGHT_DURATION_LONGER);
addPreferenceHandlerFor(PREF_AUTOREMOVE_MESSAGE);
addPreferenceHandlerFor(PREF_AUTOREMOVE_NOTIFICATIONS);
addPreferenceHandlerFor(PREF_PREVIEW_MESSAGE_IN_TITLE);
@ -596,6 +599,7 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
addPreferenceHandlerFor(PREF_BATTERY_POLLING_ENABLE);
addPreferenceHandlerFor(PREF_BATTERY_POLLING_INTERVAL);
addPreferenceHandlerFor(PREF_TIME_SYNC);
addPreferenceHandlerFor(PREF_BLUETOOTH_CALLS_ENABLED);
addPreferenceHandlerFor(PREF_DISPLAY_CALLER);

View File

@ -26,6 +26,7 @@ import androidx.annotation.NonNull;
import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
@ -50,6 +51,43 @@ public class CasioGWB5600DeviceCoordinator extends CasioDeviceCoordinator {
return BONDING_STYLE_BOND;
}
@Override
public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
return new int[]{
R.xml.devicesettings_timeformat,
R.xml.devicesettings_dateformat_day_month_order,
R.xml.devicesettings_operating_sounds,
R.xml.devicesettings_hourly_chime_enable,
R.xml.devicesettings_autolight,
R.xml.devicesettings_light_duration_longer,
R.xml.devicesettings_power_saving,
R.xml.devicesettings_casio_connection_duration,
R.xml.devicesettings_time_sync,
// alarms
// timer
// reminder
// world time
};
}
@Override
public String[] getSupportedLanguageSettings(GBDevice device) {
return new String[]{
"auto",
"en_US",
"es_ES",
"fr_FR",
"de_DE",
"it_IT",
"ru_RU",
};
}
// all further methods are boring since they do nothing
@Override
public Class<? extends Activity> getPairingActivity() {
return null;

View File

@ -19,23 +19,61 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.casio;
import java.time.ZonedDateTime;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.widget.Toast;
import android.content.Intent;
import android.content.SharedPreferences;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import java.util.UUID;
import java.util.Arrays;
import java.util.List;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.Logging;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.Logging;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.casio.CasioConstants;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_LANGUAGE;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_LANGUAGE_AUTO;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_TIMEFORMAT;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_TIMEFORMAT_AUTO;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_TIMEFORMAT_12H;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_TIMEFORMAT_24H;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DATEFORMAT;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DATEFORMAT_AUTO;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DATEFORMAT_DAY_MONTH;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DATEFORMAT_MONTH_DAY;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_OPERATING_SOUNDS;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_HOURLY_CHIME_ENABLE;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_AUTOLIGHT;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_LIGHT_DURATION_LONGER;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_POWER_SAVING;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_CONNECTION_DURATION;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_TIME_SYNC;
// this class is for those Casio watches which request reads on the 2C characteristic and write on the 2D characteristic
@ -77,6 +115,12 @@ public abstract class Casio2C2DSupport extends CasioSupport {
return super.connect();
}
@Override
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
initializeDeviceSettings(builder);
return builder;
}
public void writeAllFeatures(TransactionBuilder builder, byte[] arr) {
if (!requests.isEmpty()) {
LOG.warn("writing while waiting for a response may lead to incorrect received responses");
@ -92,8 +136,21 @@ public abstract class Casio2C2DSupport extends CasioSupport {
void handle(byte[] response);
}
public class FeatureResponses extends HashMap<FeatureRequest, byte[]> {
public byte[][] get(FeatureRequest[] requests) {
byte[][] result = new byte[requests.length][];
for (int i = 0; i < requests.length; i++) {
byte[] response = get(requests[i]);
if (response == null)
return null;
result[i] = response;
}
return result;
}
}
public interface ResponsesHandler {
void handle(Map<FeatureRequest, byte[]> responses);
void handle(FeatureResponses responses);
}
public static class FeatureRequest {
@ -107,6 +164,19 @@ public abstract class Casio2C2DSupport extends CasioSupport {
data = new byte[] {arg0, arg1};
}
public static FeatureRequest parse(String str) {
byte[] data = RequestWithData.parseData(str);
if (data == null)
return null;
if (data.length == 1) {
return new FeatureRequest(data[0]);
} else if (data.length == 2) {
return new FeatureRequest(data[0], data[1]);
} else {
return null;
}
}
public byte[] getData() {
return data.clone();
}
@ -148,6 +218,37 @@ public abstract class Casio2C2DSupport extends CasioSupport {
}
}
private static class RequestWithData {
public FeatureRequest request;
public byte[] data;
public RequestWithData(FeatureRequest request, byte[] data) {
this.request = request;
this.data = data;
}
public static RequestWithData parse(String str) {
String[] kv = str.split(";");
if (kv.length != 2)
return null;
FeatureRequest request = FeatureRequest.parse(kv[0]);
byte[] data = parseData(kv[1]);
if (request == null || data == null)
return null;
return new RequestWithData(request, data);
}
public static byte[] parseData(String str) {
if (!str.matches("\\A\\[[0-9]+(, [0-9]+)*\\]\\z"))
return null;
String[] strings = str.replace("[", "").replace("]", "").split(", ");
byte[] result = new byte[strings.length];
for (int i = 0; i < result.length; i++)
result[i] = (byte) Integer.parseInt(strings[i]);
return result;
}
}
private static class RequestWithHandler {
public FeatureRequest request;
public ResponseHandler handler;
@ -165,7 +266,7 @@ public abstract class Casio2C2DSupport extends CasioSupport {
}
public void requestFeatures(TransactionBuilder builder, Set<FeatureRequest> requests, ResponsesHandler handler) {
HashMap<FeatureRequest, byte[]> responses = new HashMap();
FeatureResponses responses = new FeatureResponses();
HashSet<FeatureRequest> missing = new HashSet();
for (FeatureRequest request: requests) {
@ -214,4 +315,435 @@ public abstract class Casio2C2DSupport extends CasioSupport {
writeAllFeatures(builder, arr);
}
FeatureCache featureCache = new FeatureCache();
public class FeatureCache {
Map<FeatureRequest, byte[]> values = null;
// can not be done on initialization, since the SharedPreferences are not yet available
void load() {
values = new HashMap();
Set<String> serialized = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()).getStringSet("casio_features_current_values", new HashSet());
if (serialized == null)
return;
for (String str: serialized) {
if (str == null)
continue;
RequestWithData entry = RequestWithData.parse(str);
if (entry == null) {
LOG.warn("invalid casio_features_current_values entry: " + str);
continue;
}
values.put(entry.request, entry.data);
}
}
public void save(SharedPreferences.Editor editor) {
if (values == null)
return;
Set<String> serialized = new HashSet();
for (Map.Entry<FeatureRequest, byte[]> entry: values.entrySet()) {
serialized.add(Arrays.toString(entry.getKey().getData()) + ";" + Arrays.toString(entry.getValue()));
}
editor.putStringSet("casio_features_current_values", serialized);
}
public byte[] get(FeatureRequest request) {
if (values == null)
load();
return values.get(request);
}
public byte[][] get(FeatureRequest[] requests) {
byte[][] result = new byte[requests.length][];
for (int i = 0; i < requests.length; i++) {
byte[] response = get(requests[i]);
if (response == null)
return null;
result[i] = response;
}
return result;
}
public void add(Map<FeatureRequest, byte[]> entries, SharedPreferences.Editor editor) {
if (values == null)
load();
for (Map.Entry<FeatureRequest, byte[]> entry: entries.entrySet()) {
values.put(entry.getKey(), entry.getValue());
}
save(editor);
}
}
public abstract class DeviceSetting {
// which features to request
public abstract FeatureRequest[] getFeatureRequests();
// compares and updates watch data, cached previous data and GB state, returns true if data was changed
public abstract boolean mergeValues(byte[][] data, byte[][] previous, SharedPreferences.Editor editor);
};
ArrayList<DeviceSetting> deviceSettings = new ArrayList();
HashMap<String, DevicePreference> devicePreferenceByName = new HashMap();
{
for (DevicePreference pref: supportedDevicePreferences()) {
deviceSettings.add(pref);
devicePreferenceByName.put(pref.getName(), pref);
}
}
void initializeDeviceSettings(TransactionBuilder builder) {
Set<FeatureRequest> deviceSettingFeatures = new LinkedHashSet();
for (DeviceSetting ds: deviceSettings)
deviceSettingFeatures.addAll(Arrays.asList(ds.getFeatureRequests()));
requestFeatures(builder, deviceSettingFeatures, responses -> {
LinkedHashSet<FeatureRequest> override = new LinkedHashSet();
SharedPreferences.Editor editor = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()).edit();
for (DeviceSetting ds: deviceSettings) {
FeatureRequest[] requests = ds.getFeatureRequests();
byte[][] data = responses.get(requests);
if (data == null)
continue;
byte[][] previous = featureCache.get(requests);
if (ds.mergeValues(data, previous, editor)) {
override.addAll(Arrays.asList(requests));
}
}
featureCache.add(responses, editor);
editor.apply();
if (!override.isEmpty()) {
ArrayList<byte[]> updatedSettings = new ArrayList();
for (FeatureRequest fr: override) {
updatedSettings.add(responses.get(fr));
}
sendSettingsToDevice(updatedSettings.toArray(new byte[][] {}));
}
});
}
void sendSettingsToDevice(byte[][] settings) {
TransactionBuilder builder = createTransactionBuilder("DeviceSetting.write");
for (byte[] data: settings) {
writeAllFeatures(builder, data);
}
builder.run((gatt) -> GB.toast(getContext(), getContext().getString(R.string.user_feedback_set_settings_ok), Toast.LENGTH_SHORT, GB.INFO));
builder.queue(getQueue());
}
public abstract class DevicePreference extends DeviceSetting {
byte feature;
public final FeatureRequest getFeatureRequest() {
return new FeatureRequest(feature);
};
@Override
public final FeatureRequest[] getFeatureRequests() {
return new FeatureRequest[] {getFeatureRequest()};
};
String name;
public final String getName() {
return name;
}
public abstract void updateValue(byte[] data);
@Override
public final boolean mergeValues(byte[][] data, byte[][] previous, SharedPreferences.Editor editor) {
boolean needsUpdating = false;
// check if GB state has changed
if (previous != null) {
byte[] copy = previous[0].clone();
updateValue(copy);
if (!Arrays.equals(previous[0], copy)) {
needsUpdating = true;
}
}
// update GB state and check if data needs change
if (!needsUpdating) {
needsUpdating = readValue(data[0], editor);
}
// maybe update data
if (needsUpdating) {
updateValue(data[0]);
return true;
}
return false;
}
public abstract boolean readValue(byte[] data, SharedPreferences.Editor editor);
protected Prefs getPrefs() {
return new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
}
protected GBPrefs getGBPrefs() {
return new GBPrefs(getPrefs());
}
};
public abstract Casio2C2DSupport.DevicePreference[] supportedDevicePreferences();
@Override
public void onSendConfiguration(String config) {
DevicePreference pref = devicePreferenceByName.get(config);
if (pref == null) {
LOG.warn("received configuration change for unsupported setting " + config);
return;
}
if (!isInitialized()) {
return;
}
byte[] currentValue = featureCache.get(pref.getFeatureRequest());
if (currentValue == null) {
LOG.error("unknown current watch value for config " + config);
return;
}
pref.updateValue(currentValue);
SharedPreferences.Editor editor = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()).edit();
featureCache.save(editor);
editor.apply();
sendSettingsToDevice(new byte[][] {currentValue});
}
public class UnsignedByteDevicePreference extends DevicePreference {
int index;
@Override
public void updateValue(byte[] data) {
data[index] = (byte) getGBValue();
}
@Override
public boolean readValue(byte[] data, SharedPreferences.Editor editor) {
return setGBValue(editor, data[index] & 0xff);
}
public int getGBValue() {
return getPrefs().getInt(name, -1);
}
public boolean setGBValue(SharedPreferences.Editor editor, int value) {
if (value != getGBValue()) {
editor.putString(name, Integer.toString(value));
}
return false;
}
}
public class BoolDevicePreference extends DevicePreference {
int index;
byte mask;
@Override
public void updateValue(byte[] data) {
if (getGBValue()) {
data[index] &= ~mask;
} else {
data[index] |= mask;
}
}
@Override
public boolean readValue(byte[] data, SharedPreferences.Editor editor) {
if ((data[index] & mask) == 0) {
return setGBValue(editor, true);
} else {
return setGBValue(editor, false);
}
}
public boolean getGBValue() {
return getPrefs().getBoolean(name, false);
}
public boolean setGBValue(SharedPreferences.Editor editor, boolean value) {
if (value != getGBValue()) {
editor.putBoolean(name, value);
}
return false;
}
}
public class InvertedBoolDevicePreference extends BoolDevicePreference {
@Override
public void updateValue(byte[] data) {
if (getGBValue()) {
data[index] |= mask;
} else {
data[index] &= ~mask;
}
}
@Override
public boolean readValue(byte[] data, SharedPreferences.Editor editor) {
if ((data[index] & mask) == 0) {
return setGBValue(editor, false);
} else {
return setGBValue(editor, true);
}
}
}
interface AutoGetter {
public String get(GBPrefs gbPrefs);
}
public class AutoBoolDevicePreference extends BoolDevicePreference {
AutoGetter getter;
String autoValue;
String trueValue;
String falseValue;
@Override
public boolean getGBValue() {
return getter.get(getGBPrefs()).equals(trueValue);
}
@Override
public boolean setGBValue(SharedPreferences.Editor editor, boolean value) {
String strValue = value ? trueValue : falseValue;
if (!getter.get(getGBPrefs()).equals(strValue)) {
if (getPrefs().getString(name, autoValue).equals(autoValue)) {
return true;
} else {
editor.putString(name, strValue);
}
}
return false;
}
}
public class TimeSyncPreference extends BoolDevicePreference {
{ name = PREF_TIME_SYNC; }
{ feature = FEATURE_SETTING_FOR_BLE; }
{ index = 12; mask = (byte) (0x80 & 0xff); }
}
public class ConnectionDurationPreference extends UnsignedByteDevicePreference {
{ name = PREF_CONNECTION_DURATION; }
{ feature = FEATURE_SETTING_FOR_BLE; }
{ index = 14; }
@Override
public int getGBValue() {
return getPrefs().getInt(name, -1);
}
@Override
public boolean setGBValue(SharedPreferences.Editor editor, int value) {
if (value != getGBValue()) {
editor.putString(name, Integer.toString(value));
}
return false;
}
}
public class TimeFormatPreference extends AutoBoolDevicePreference {
{ name = PREF_TIMEFORMAT; }
{ feature = FEATURE_SETTING_FOR_BASIC; }
{ index = 1; mask = 0x01; }
{ getter = gbPrefs -> gbPrefs.getTimeFormat(); }
{ autoValue = PREF_TIMEFORMAT_AUTO; }
{ trueValue = PREF_TIMEFORMAT_12H; }
{ falseValue = PREF_TIMEFORMAT_24H; }
}
public class OperatingSoundPreference extends BoolDevicePreference {
{ name = PREF_OPERATING_SOUNDS; }
{ feature = FEATURE_SETTING_FOR_BASIC; }
{ index = 1; mask = 0x02; }
}
public class AutoLightPreference extends BoolDevicePreference {
{ name = PREF_AUTOLIGHT; }
{ feature = FEATURE_SETTING_FOR_BASIC; }
{ index = 1; mask = 0x04; }
}
public class PowerSavingPreference extends BoolDevicePreference {
{ name = PREF_POWER_SAVING; }
{ feature = FEATURE_SETTING_FOR_BASIC; }
{ index = 1; mask = 0x10; }
}
public class LongerLightDurationPreference extends InvertedBoolDevicePreference {
{ name = PREF_LIGHT_DURATION_LONGER; }
{ feature = FEATURE_SETTING_FOR_BASIC; }
{ index = 2; mask = 0x01; }
}
public class DayMonthOrderPreference extends AutoBoolDevicePreference {
{ name = PREF_DATEFORMAT; }
{ feature = FEATURE_SETTING_FOR_BASIC; }
{ index = 4; mask = 0x01; }
{ getter = gbPrefs -> gbPrefs.getDateFormatDayMonthOrder(); }
{ autoValue = PREF_DATEFORMAT_AUTO; }
{ trueValue = PREF_DATEFORMAT_MONTH_DAY; }
{ falseValue = PREF_DATEFORMAT_DAY_MONTH; }
}
public class LanguagePreference extends UnsignedByteDevicePreference {
{ name = PREF_LANGUAGE; }
{ feature = FEATURE_SETTING_FOR_BASIC; }
{ index = 5; }
String[] languages = { "en_US", "es_ES", "fr_FR"," de_DE", "it_IT", "ru_RU" };
@Override
public int getGBValue() {
String value = getPrefs().getString(name, PREF_LANGUAGE_AUTO);
int number = 0;
if (value.equals(PREF_LANGUAGE_AUTO)) {
String lang = Locale.getDefault().getLanguage() + "_";
for (int i=0; i < languages.length; i++) {
if (languages[i].startsWith(lang)) {
number = i;
break;
}
}
} else {
for (int i=0; i < languages.length; i++) {
if (value.equals(languages[i])) {
number = i;
break;
}
}
}
return number;
}
@Override
public boolean setGBValue(SharedPreferences.Editor editor, int value) {
if (getGBValue() != value) {
if (getPrefs().getString(name, PREF_LANGUAGE_AUTO).equals(PREF_LANGUAGE_AUTO)) {
return true;
} else {
if (value < languages.length) {
editor.putString(name, languages[value]);
} else {
editor.putString(name, "unknown");
}
}
}
return false;
}
}
public class HourlyChimePreference extends InvertedBoolDevicePreference {
{ name = PREF_HOURLY_CHIME_ENABLE; }
{ feature = FEATURE_SETTING_FOR_ALM; }
{ index = 1; mask = (byte) (0x80 & 0xff); }
}
}

View File

@ -94,6 +94,12 @@ public class CasioGBX100DeviceSupport extends Casio2C2DSupport implements Shared
super(LOG);
}
@Override
public DeviceSetting[] supportedDeviceSettings() {
return new DeviceSetting[] {
};
}
@Override
public boolean useAutoConnect() {
return true;

View File

@ -49,6 +49,22 @@ public class CasioGWB5600DeviceSupport extends Casio2C2DSupport {
super(LOG);
}
@Override
public DeviceSetting[] supportedDeviceSettings() {
return new DeviceSetting[] {
new LanguageSetting(),
new TimeFormatSetting(),
new DayMonthOrderSetting(),
new OperatingSoundSetting(),
new HourlyChimeSetting(),
new AutoLightSetting(),
new LongerLightDurationSetting(),
new PowerSavingSetting(),
new ConnectionDurationSetting(),
new TimeSyncSetting(),
};
}
@Override
public boolean useAutoConnect() {
return false;
@ -75,6 +91,8 @@ public class CasioGWB5600DeviceSupport extends Casio2C2DSupport {
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
super.initializeDevice(builder);
// which button was pressed?
requestFeature(builder, new FeatureRequest(FEATURE_BLE_FEATURES), data -> {
if (data.length > 8 && data[8] == CasioConstants.CONNECT_FIND) {

View File

@ -33,6 +33,7 @@ import androidx.core.app.ActivityCompat;
import java.text.ParseException;
import java.time.LocalTime;
import java.util.Date;
import java.util.Locale;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
@ -133,6 +134,29 @@ public class GBPrefs extends Prefs {
return timeFormat;
}
public String getDateFormatDayMonthOrder() {
String dateFormat = getString(DeviceSettingsPreferenceConst.PREF_DATEFORMAT, DeviceSettingsPreferenceConst.PREF_DATEFORMAT_AUTO);
if (DeviceSettingsPreferenceConst.PREF_TIMEFORMAT_AUTO.equals(dateFormat)) {
String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), "dM");
boolean quoted = false;
for (char c: pattern.toCharArray()) {
if (c == '\'') {
quoted = !quoted;
continue;
}
if (quoted)
continue;
if (c == 'd')
return DeviceSettingsPreferenceConst.PREF_DATEFORMAT_DAY_MONTH;
if (c == 'M' || c == 'L')
return DeviceSettingsPreferenceConst.PREF_DATEFORMAT_MONTH_DAY;
}
return DeviceSettingsPreferenceConst.PREF_DATEFORMAT_DAY_MONTH;
}
return dateFormat;
}
public float[] getLongLat(Context context) {
float latitude = getFloat("location_latitude", 0);
float longitude = getFloat("location_longitude", 0);

View File

@ -0,0 +1,10 @@
<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="#000000"
android:pathData="M12 4.002233V1L7.998977 5.00093 12 9.00186V6.001674c3.309286 0 6.000512 2.689117 6.000512 6.000373 0 1.00893 -0.251727 1.968744 -0.699924 2.799627l1.459197 1.459163C19.539524 15.03293 20 13.571721 20 12.002047 20 7.581581 16.418521 4.000186 11.997953 4.000186Zm0 13.998139c-3.311333 0 -6.000512 -2.689116 -6.000512 -6.000372 0 -1.00893 0.249681 -1.968744 0.699924 -2.799628L5.2381683 7.741209C4.4604758 8.969116 4 10.430326 4 12c0 4.420465 3.579432 8.00186 8 8.00186V23L15.998977 19.001116 12 15.000186Z" />
</vector>

View File

@ -283,6 +283,17 @@
<item>MM/DD/YYYY</item>
</string-array>
<string-array name="dateformat_day_month_order_entries">
<item>@string/automatic</item>
<item>@string/dateformat_day_month</item>
<item>@string/dateformat_month_day</item>
</string-array>
<string-array name="dateformat_day_month_order_values">
<item>@string/p_dateformat_auto</item>
<item>@string/p_dateformat_day_month</item>
<item>@string/p_dateformat_month_day</item>
</string-array>
<string-array name="do_not_disturb_no_auto">
<item>@string/mi2_dnd_off</item>
<item>@string/mi2_dnd_scheduled</item>
@ -2716,6 +2727,58 @@
<item>3600</item>
</string-array>
<string-array name="pref_casio_connection_duration">
<item name="1">@string/minutes_1</item>
<item name="2">@string/minutes_2</item>
<item name="3">@string/minutes_3</item>
<item name="4">@string/minutes_4</item>
<item name="5">@string/minutes_5</item>
<item name="6">@string/minutes_6</item>
<item name="7">@string/minutes_7</item>
<item name="8">@string/minutes_8</item>
<item name="9">@string/minutes_9</item>
<item name="10">@string/minutes_10</item>
<item name="15">@string/minutes_15</item>
<item name="20">@string/minutes_20</item>
<item name="30">@string/minutes_30</item>
<item name="45">@string/minutes_45</item>
<item name="60">@string/minutes_60</item>
<item name="75">@string/minutes_75</item>
<item name="90">@string/minutes_90</item>
<item name="120">@string/minutes_120</item>
<item name="150">@string/minutes_150</item>
<item name="180">@string/minutes_180</item>
<item name="210">@string/minutes_210</item>
<item name="240">@string/minutes_240</item>
<item name="255">@string/minutes_255</item>
</string-array>
<string-array name="pref_casio_connection_duration_values">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
<item>15</item>
<item>20</item>
<item>30</item>
<item>45</item>
<item>60</item>
<item>75</item>
<item>90</item>
<item>120</item>
<item>150</item>
<item>180</item>
<item>210</item>
<item>240</item>
<item>255</item>
</string-array>
<string-array name="notifications_timeout">
<item>@string/no_limit</item>
<item>@string/seconds_5</item>

View File

@ -340,6 +340,7 @@
<string name="pref_summary_sunrise_sunset">Send sunrise and sunset times based on the location to the Pebble timeline</string>
<string name="pref_title_enable_calendar_sync">Sync calendar</string>
<string name="pref_summary_enable_calendar_sync">Send calendar events to the timeline</string>
<string name="pref_time_sync">Automatic time sync</string>
<string name="pref_title_custom_deviceicon">Show device specific notification icon</string>
<string name="pref_summary_custom_deviceicon">Show a device specific Android notification icon instead the Gadgetbridge icon when connected</string>
<string name="pref_title_preview_message_in_title">Show a preview of the message in the title</string>
@ -803,6 +804,7 @@
<string name="alarm_snooze">Snooze</string>
<string name="user_feedback_miband_set_alarms_failed">There was an error setting the alarms, please try again.</string>
<string name="user_feedback_miband_set_alarms_ok">Alarms sent to device.</string>
<string name="user_feedback_set_settings_ok">Settings sent to device.</string>
<string name="chart_no_data_synchronize">No data. Synchronize device?</string>
<string name="chart_no_active_data">No activities detected.</string>
<string name="chart_get_active_and_synchronize">Do some activity and synchronize device.</string>
@ -924,11 +926,28 @@
<string name="seconds_25">25 seconds</string>
<string name="seconds_30">30 seconds</string>
<string name="minutes_1">1 minute</string>
<string name="minutes_2">2 minutes</string>
<string name="minutes_3">3 minutes</string>
<string name="minutes_4">4 minutes</string>
<string name="minutes_5">5 minutes</string>
<string name="minutes_6">6 minutes</string>
<string name="minutes_7">7 minutes</string>
<string name="minutes_8">8 minutes</string>
<string name="minutes_9">9 minutes</string>
<string name="minutes_10">10 minutes</string>
<string name="minutes_15">15 minutes</string>
<string name="minutes_20">20 minutes</string>
<string name="minutes_30">30 minutes</string>
<string name="minutes_45">45 minutes</string>
<string name="minutes_60">60 minutes</string>
<string name="minutes_75">75 minutes</string>
<string name="minutes_90">90 minutes</string>
<string name="minutes_120">120 minutes</string>
<string name="minutes_150">150 minutes</string>
<string name="minutes_180">180 minutes</string>
<string name="minutes_210">210 minutes</string>
<string name="minutes_240">240 minutes</string>
<string name="minutes_255">255 minutes</string>
<string name="liveactivity_live_activity">Live activity</string>
<string name="weeksteps_today_steps_description">Steps today, target: %1$s</string>
<string name="lack_of_step">Lack of steps: %1$d</string>
@ -1248,6 +1267,8 @@
<string name="unit_imperial">Imperial</string>
<string name="timeformat_24h">24H</string>
<string name="timeformat_am_pm">AM/PM</string>
<string name="dateformat_day_month">Day, Month</string>
<string name="dateformat_month_day">Month, Day</string>
<string name="pref_screen_notification_profile_alarm_clock">Alarm clock</string>
<string name="activity_web_view">Web View Activity</string>
<string name="StringUtils_sender"> (%1$s)</string>
@ -2245,6 +2266,7 @@
<item quantity="other">%d hours</item>
</plurals>
<string name="prefs_autolight">Automatic light</string>
<string name="prefs_light_duration_longer">Longer light duration</string>
<string name="prefs_key_vibration">Key Vibration</string>
<string name="prefs_operating_sounds">Operating Sounds</string>
<string name="prefs_fake_ring_duration">Fake continuous ringing</string>
@ -2821,6 +2843,7 @@
<string name="pref_app_logs_summary">Enable logs from watch apps</string>
<string name="pref_app_logs_start_summary">Start logging from watch apps</string>
<string name="pref_app_logs_stop_summary">Stop logging from watch apps</string>
<string name="pref_app_connection_duration">App connection duration</string>
<string name="title">Title</string>
<string name="description">Description</string>
<string name="preview_image">Preview image</string>

View File

@ -10,8 +10,11 @@
<item name="p_ring" type="string">ring</item>
<item name="p_alarm_clock" type="string">alarm_clock</item>
<item name="p_dateformat_auto" type="string">auto</item>
<item name="p_dateformat_time" type="string">dateformat_time</item>
<item name="p_dateformat_datetime" type="string">dateformat_datetime</item>
<item name="p_dateformat_day_month" type="string">day_month</item>
<item name="p_dateformat_month_day" type="string">month_day</item>
<item name="p_clock" type="string">clock</item>
<item name="p_steps" type="string">steps</item>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<ListPreference
android:icon="@drawable/ic_sync"
android:defaultValue="2"
android:entries="@array/pref_casio_connection_duration"
android:entryValues="@array/pref_casio_connection_duration_values"
android:key="connection_duration"
android:summary="%s"
android:title="@string/pref_app_connection_duration" />
</androidx.preference.PreferenceScreen>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<ListPreference
android:defaultValue="auto"
android:icon="@drawable/ic_access_time"
android:entries="@array/dateformat_day_month_order_entries"
android:entryValues="@array/dateformat_day_month_order_values"
android:key="dateformat"
android:summary="%s"
android:title="@string/miband2_prefs_dateformat" />
</androidx.preference.PreferenceScreen>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreference
android:defaultValue="false"
android:icon="@drawable/ic_beep"
android:key="hourly_chime_enable"
android:title="@string/prefs_hourly_chime" />
</androidx.preference.PreferenceScreen>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreference
android:defaultValue="false"
android:icon="@drawable/ic_wb_sunny"
android:key="light_duration_longer"
android:title="@string/prefs_light_duration_longer" />
</androidx.preference.PreferenceScreen>

View File

@ -2,8 +2,8 @@
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreferenceCompat
android:defaultValue="false"
android:icon="@drawable/ic_radio"
android:icon="@drawable/ic_beep"
android:key="operating_sounds"
android:layout="@layout/preference_checkbox"
android:title="@string/prefs_operating_sounds" />
</androidx.preference.PreferenceScreen>
</androidx.preference.PreferenceScreen>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreference
android:defaultValue="true"
android:icon="@drawable/ic_power_settings_new"
android:key="power_saving"
android:title="@string/power_saving" />
</androidx.preference.PreferenceScreen>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreference
android:defaultValue="true"
android:icon="@drawable/ic_sync"
android:key="time_sync"
android:title="@string/pref_time_sync" />
</androidx.preference.PreferenceScreen>