diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsUtils.java index fc83cd343..effdd5788 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsUtils.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsUtils.java @@ -28,9 +28,10 @@ import androidx.preference.Preference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; @@ -49,6 +50,13 @@ public final class DeviceSettingsUtils { return String.format(Locale.ROOT, "%s_possible_values", key); } + /** + * Returns the preference key where to save the list of entry labels for a preference, comma-separated. + */ + public static String getPrefPossibleValueLabelsKey(final String key) { + return String.format(Locale.ROOT, "%s_possible_value_labels", key); + } + /** * Returns the preference key where to that a config was reported as supported (boolean). */ @@ -57,12 +65,11 @@ public final class DeviceSettingsUtils { } /** - * Removes all unsupported elements from a list preference. If they are not known, the preference - * is hidden. + * Populates a list preference, or hides it if no known supported values are known. */ - public static void removeUnsupportedElementsFromListPreference(final String prefKey, - final DeviceSpecificSettingsHandler handler, - final Prefs prefs) { + public static void populateOrHideListPreference(final String prefKey, + final DeviceSpecificSettingsHandler handler, + final Prefs prefs) { final Preference pref = handler.findPreference(prefKey); if (pref == null) { return; @@ -92,19 +99,40 @@ public final class DeviceSettingsUtils { return; } - final List prefValues = new ArrayList<>(originalValues.length); - for (final CharSequence entryValue : originalValues) { - prefValues.add(entryValue.toString()); + final Map entryNames = new HashMap<>(); + final List knownLabels = prefs.getList(getPrefPossibleValueLabelsKey(prefKey), null); + if (knownLabels != null) { + // We got some known labels from the watch + if (knownLabels.size() != possibleValues.size()) { + LOG.warn( + "Number of possible values ({}) and labels ({}) for {} differs - this should never happen", + possibleValues.size(), + knownLabels.size(), + prefKey + ); + + // Abort and hide preference - we can't safely recover from this + pref.setVisible(false); + return; + } + + for (int i = 0; i < knownLabels.size(); i++) { + entryNames.put(possibleValues.get(i), knownLabels.get(i)); + } + } else { + for (int i = 0; i < originalEntries.length; i++) { + entryNames.put(originalValues[i], originalEntries[i]); + } } final CharSequence[] entries = new CharSequence[possibleValues.size()]; final CharSequence[] values = new CharSequence[possibleValues.size()]; for (int i = 0; i < possibleValues.size(); i++) { final String possibleValue = possibleValues.get(i); - final int idxPrefValue = prefValues.indexOf(possibleValue); + final CharSequence knownLabel = entryNames.get(possibleValue); - if (idxPrefValue >= 0) { - entries[i] = originalEntries[idxPrefValue]; + if (knownLabel != null) { + entries[i] = knownLabel; } else { entries[i] = handler.getContext().getString(R.string.menuitem_unknown_app, possibleValue); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/Huami2021SettingsCustomizer.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/Huami2021SettingsCustomizer.java index c68be2a4a..7f3c55f09 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/Huami2021SettingsCustomizer.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huami/Huami2021SettingsCustomizer.java @@ -17,16 +17,12 @@ package nodomain.freeyourgadget.gadgetbridge.devices.huami; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsUtils.hidePrefIfNoneVisible; -import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsUtils.removeUnsupportedElementsFromListPreference; +import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsUtils.populateOrHideListPreference; import android.os.Parcel; -import android.text.InputFilter; -import android.text.InputType; -import android.text.Spanned; import androidx.preference.EditTextPreference; import androidx.preference.ListPreference; -import androidx.preference.MultiSelectListPreference; import androidx.preference.Preference; import org.slf4j.Logger; @@ -65,13 +61,13 @@ public class Huami2021SettingsCustomizer extends HuamiSettingsCustomizer { super.customizeSettings(handler, prefs); // These are not reported by the normal configs - removeUnsupportedElementsFromListPreference(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE, handler, prefs); - removeUnsupportedElementsFromListPreference(HuamiConst.PREF_SHORTCUTS_SORTABLE, handler, prefs); - removeUnsupportedElementsFromListPreference(HuamiConst.PREF_CONTROL_CENTER_SORTABLE, handler, prefs); - removeUnsupportedElementsFromListPreference(DeviceSettingsPreferenceConst.SHORTCUT_CARDS_SORTABLE, handler, prefs); - removeUnsupportedElementsFromListPreference(DeviceSettingsPreferenceConst.PREF_WATCHFACE, handler, prefs); - removeUnsupportedElementsFromListPreference(DeviceSettingsPreferenceConst.MORNING_UPDATES_CATEGORIES_SORTABLE, handler, prefs); - removeUnsupportedElementsFromListPreference(DeviceSettingsPreferenceConst.PREF_VOICE_SERVICE_LANGUAGE, handler, prefs); + populateOrHideListPreference(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE, handler, prefs); + populateOrHideListPreference(HuamiConst.PREF_SHORTCUTS_SORTABLE, handler, prefs); + populateOrHideListPreference(HuamiConst.PREF_CONTROL_CENTER_SORTABLE, handler, prefs); + populateOrHideListPreference(DeviceSettingsPreferenceConst.SHORTCUT_CARDS_SORTABLE, handler, prefs); + populateOrHideListPreference(DeviceSettingsPreferenceConst.PREF_WATCHFACE, handler, prefs); + populateOrHideListPreference(DeviceSettingsPreferenceConst.MORNING_UPDATES_CATEGORIES_SORTABLE, handler, prefs); + populateOrHideListPreference(DeviceSettingsPreferenceConst.PREF_VOICE_SERVICE_LANGUAGE, handler, prefs); for (final ZeppOsConfigService.ConfigArg config : ZeppOsConfigService.ConfigArg.values()) { if (config.getPrefKey() == null) { @@ -88,7 +84,7 @@ public class Huami2021SettingsCustomizer extends HuamiSettingsCustomizer { case BYTE_LIST: case STRING_LIST: // For list preferences, remove the unsupported items - removeUnsupportedElementsFromListPreference(config.getPrefKey(), handler, prefs); + populateOrHideListPreference(config.getPrefKey(), handler, prefs); break; case SHORT: case INT: diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiSettingsCustomizer.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiSettingsCustomizer.java index c973e197f..c0c6f1b1b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiSettingsCustomizer.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiSettingsCustomizer.java @@ -16,6 +16,8 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.devices.xiaomi; +import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsUtils.populateOrHideListPreference; + import android.os.Parcel; import androidx.preference.Preference; @@ -26,6 +28,7 @@ import java.util.Set; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsHandler; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class XiaomiSettingsCustomizer implements DeviceSpecificSettingsCustomizer { @@ -39,6 +42,8 @@ public class XiaomiSettingsCustomizer implements DeviceSpecificSettingsCustomize if (activityMonitoringPref != null) { activityMonitoringPref.setVisible(false); } + + populateOrHideListPreference(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE, handler, prefs); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiPreferences.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiPreferences.java index e683d550b..e4d5109dc 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiPreferences.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiPreferences.java @@ -61,13 +61,6 @@ public final class XiaomiPreferences { return calendar.getTime(); } - /** - * Returns the preference key where to save the list of possible value for a preference, comma-separated. - */ - public static String getPrefPossibleValuesKey(final String key) { - return String.format(Locale.ROOT, "%s_possible_values", key); - } - public static boolean keepActivityDataOnDevice(final GBDevice gbDevice) { final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress())); return prefs.getBoolean("keep_activity_data_on_device", false); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiSystemService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiSystemService.java index 1d7361936..58275705e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiSystemService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiSystemService.java @@ -32,6 +32,7 @@ import java.util.TimeZone; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; +import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsUtils; import nodomain.freeyourgadget.gadgetbridge.capabilities.password.PasswordCapabilityImpl; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone; @@ -321,13 +322,28 @@ public class XiaomiSystemService extends AbstractXiaomiService implements Xiaomi private void setDisplayItems() { final Prefs prefs = getDevicePrefs(); - final List allScreens = new ArrayList<>(prefs.getList(XiaomiPreferences.getPrefPossibleValuesKey(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE), Collections.emptyList())); + final List allScreens = new ArrayList<>(prefs.getList(DeviceSettingsUtils.getPrefPossibleValuesKey(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE), Collections.emptyList())); + final List allLabels = new ArrayList<>(prefs.getList(DeviceSettingsUtils.getPrefPossibleValueLabelsKey(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE), Collections.emptyList())); final List enabledScreens = new ArrayList<>(prefs.getList(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE, Collections.emptyList())); if (allScreens.isEmpty()) { LOG.warn("No list of all screens"); return; } + if (allScreens.size() != allLabels.size()) { + LOG.warn( + "Mismatched allScreens ({}) and allLabels ({}) sizes - this should never happen", + allScreens.size(), + allLabels.size() + ); + return; + } + + final Map labelsMap = new HashMap<>(); + for (int i = 0; i < allScreens.size(); i++) { + labelsMap.put(allScreens.get(i), allLabels.get(i)); + } + LOG.debug("Setting display items: {}", enabledScreens); if (!enabledScreens.contains("setting")) { @@ -344,7 +360,7 @@ public class XiaomiSystemService extends AbstractXiaomiService implements Xiaomi final XiaomiProto.DisplayItem.Builder displayItem = XiaomiProto.DisplayItem.newBuilder() .setCode(enabledScreen) - .setName(DISPLAY_ITEM_NAMES.get(enabledScreen)) + .setName(labelsMap.get(enabledScreen)) .setUnknown5(1); if (inMoreSection) { @@ -365,7 +381,7 @@ public class XiaomiSystemService extends AbstractXiaomiService implements Xiaomi final XiaomiProto.DisplayItem.Builder displayItem = XiaomiProto.DisplayItem.newBuilder() .setCode(screen) - .setName(DISPLAY_ITEM_NAMES.get(screen)) + .setName(labelsMap.get(screen)) .setDisabled(true) .setUnknown5(1); @@ -386,10 +402,12 @@ public class XiaomiSystemService extends AbstractXiaomiService implements Xiaomi LOG.debug("Got {} display items", displayItems.getDisplayItemCount()); final List allScreens = new ArrayList<>(); + final List allScreensLabels = new ArrayList<>(); final List mainScreens = new ArrayList<>(); final List moreScreens = new ArrayList<>(); for (final XiaomiProto.DisplayItem displayItem : displayItems.getDisplayItemList()) { allScreens.add(displayItem.getCode()); + allScreensLabels.add(displayItem.getName().replace(",", "")); if (!displayItem.getDisabled()) { if (displayItem.getInMoreSection()) { moreScreens.add(displayItem.getCode()); @@ -405,11 +423,16 @@ public class XiaomiSystemService extends AbstractXiaomiService implements Xiaomi enabledScreens.addAll(moreScreens); } + allScreens.add("more"); + allScreensLabels.add(getSupport().getContext().getString(R.string.menuitem_more)); + final String allScreensPrefValue = StringUtils.join(",", allScreens.toArray(new String[0])).toString(); + final String allScreensLabelsPrefValue = StringUtils.join(",", allScreensLabels.toArray(new String[0])).toString(); final String prefValue = StringUtils.join(",", enabledScreens.toArray(new String[0])).toString(); final GBDeviceEventUpdatePreferences eventUpdatePreferences = new GBDeviceEventUpdatePreferences() - .withPreference(XiaomiPreferences.getPrefPossibleValuesKey(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE), allScreensPrefValue) + .withPreference(DeviceSettingsUtils.getPrefPossibleValuesKey(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE), allScreensPrefValue) + .withPreference(DeviceSettingsUtils.getPrefPossibleValueLabelsKey(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE), allScreensLabelsPrefValue) .withPreference(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE, prefValue); getSupport().evaluateGBDeviceEvent(eventUpdatePreferences); @@ -515,34 +538,4 @@ public class XiaomiSystemService extends AbstractXiaomiService implements Xiaomi LOG.error("Failed to update progress notification", e); } } - - // TODO do we even need this? also prevent NPE when unknown - private static final Map DISPLAY_ITEM_NAMES = new HashMap() {{ - put("today_act", "Stats"); - put("sport", "Workout"); - put("sport_record", "Activity"); - put("sport_course", "Running"); - put("sport_state", "Status"); - put("heart", "Heart rate"); - put("pai", "Vitality"); - put("blood_ox", "SpO₂"); - put("sleep", "Sleep"); - put("press", "Stress"); - put("weather", "Weather"); - put("alarm", "Alarm"); - put("setting", "Settings"); - put("event_reminder", "Alerts"); - put("schedule", "Events"); - put("breath", "Breathing"); - put("stopwatch", "Stopwatch"); - put("music", "Music"); - put("find_phone", "Find phone"); - put("world_clock", "World clock"); - put("phone_mute", "Silence phone"); - put("phone_remote", "Camera"); - put("count_down", "Timer"); - put("focus", "Focus"); - put("flash_light", "Flashlight"); - put("fm_health", "Cycles"); - }}; } diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 2de3ca53b..476aed6a6 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -1022,66 +1022,6 @@ headphone - - @string/menuitem_stats - @string/menuitem_workout - @string/menuitem_activity - @string/menuitem_running - @string/menuitem_status - @string/menuitem_hr - @string/menuitem_pai - @string/menuitem_spo2 - @string/menuitem_sleep - @string/menuitem_stress - @string/menuitem_weather - @string/menuitem_alarm - @string/menuitem_settings - @string/menuitem_more - @string/menuitem_alerts - @string/menuitem_events - @string/menuitem_breathing - @string/menuitem_female_health - @string/menuitem_stopwatch - @string/menuitem_music - @string/menuitem_findphone - @string/menuitem_worldclock - @string/menuitem_mutephone - @string/menuitem_takephoto - @string/menuitem_timer - @string/menuitem_flashlight - @string/menuitem_pomodoro - - - - today_act - sport - sport_record - sport_course - sport_state - heart - pai - blood_ox - sleep - press - weather - alarm - setting - more - schedule - event_reminder - breath - fm_health - stopwatch - music - find_phone - world_clock - phone_mute - phone_remote - count_down - flash_light - focus - - @string/activity_type_outdoor_running @string/activity_type_walking diff --git a/app/src/main/res/xml/devicesettings_xiaomi_displayitems.xml b/app/src/main/res/xml/devicesettings_xiaomi_displayitems.xml index 08ad3f301..1ca0247c7 100644 --- a/app/src/main/res/xml/devicesettings_xiaomi_displayitems.xml +++ b/app/src/main/res/xml/devicesettings_xiaomi_displayitems.xml @@ -3,8 +3,8 @@