Garmin / Zepp OS: Add experimental settings

This commit is contained in:
José Rebelo
2025-12-21 17:01:44 +00:00
parent 794166d2b1
commit 8a4bc18c03
16 changed files with 116 additions and 14 deletions
@@ -1595,12 +1595,25 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
);
}
}
if(BuildConfig.DEBUG) {
if (BuildConfig.DEBUG) {
deviceSpecificSettings.addRootScreen(
DeviceSpecificSettingsScreen.DEVELOPER,
R.xml.devicesettings_stress_test
);
}
if (GBApplication.getPrefs().experimentalSettings()) {
final int[] experimentalSettings = coordinator.getSupportedDeviceSpecificExperimentalSettings(device);
if (experimentalSettings != null && experimentalSettings.length > 0) {
deviceSpecificSettings.addRootScreen(
DeviceSpecificSettingsScreen.EXPERIMENTAL,
R.xml.devicesettings_experimental_warning
);
deviceSpecificSettings.addRootScreen(
DeviceSpecificSettingsScreen.EXPERIMENTAL,
experimentalSettings
);
}
}
}
final DeviceSpecificSettingsCustomizer deviceSpecificSettingsCustomizer = coordinator.getDeviceSpecificSettingsCustomizer(device);
@@ -40,6 +40,7 @@ public enum DeviceSpecificSettingsScreen {
HEALTH("pref_screen_health", R.xml.devicesettings_root_health),
TOUCH_OPTIONS("pref_screen_touch_options", R.xml.devicesettings_root_touch_options),
SOUND("pref_screen_sound", R.xml.devicesettings_root_sound),
EXPERIMENTAL("pref_screen_experimental", R.xml.devicesettings_root_experimental),
;
private final String key;
@@ -957,6 +957,15 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
return new int[0];
}
@Override
public int[] getSupportedDeviceSpecificExperimentalSettings(final GBDevice device) {
return new int[0];
}
public boolean experimentalSettingEnabled(final GBDevice device, final String key) {
return GBApplication.getPrefs().experimentalSettings() && GBApplication.getDevicePrefs(device).getBoolean(key, false);
}
@Nullable
@Override
public DeviceSpecificSettingsCustomizer getDeviceSpecificSettingsCustomizer(GBDevice device) {
@@ -804,6 +804,12 @@ public interface DeviceCoordinator {
*/
int[] getSupportedDeviceSpecificAuthenticationSettings();
/**
* Returns device specific experimental settings. This screen is only shown when the global experimental settings
* is enabled.
*/
int[] getSupportedDeviceSpecificExperimentalSettings(final GBDevice device);
/**
* Indicates which device specific settings the device supports (not per device type or family, but unique per device).
*
@@ -223,6 +223,11 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
return new int[]{R.xml.devicesettings_garmin_fake_oauth};
}
@Override
public int[] getSupportedDeviceSpecificExperimentalSettings(final GBDevice device) {
return new int[]{R.xml.devicesettings_garmin_experimental};
}
@Override
public DeviceSpecificSettings getDeviceSpecificSettings(final GBDevice device) {
final DeviceSpecificSettings deviceSpecificSettings = new DeviceSpecificSettings();
@@ -307,9 +312,8 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
@Override
public boolean supportsAppsManagement(@NonNull final GBDevice device) {
// FIXME: disabled until better polished
//return supports(device, GarminCapability.CONNECTIQ_APP_MANAGEMENT);
return false;
// FIXME: experimental until better polished
return experimentalSettingEnabled(device, "garmin_experimental_app_management");
}
@Override
@@ -278,7 +278,7 @@ public abstract class ZeppOsCoordinator extends HuamiCoordinator {
@Override
public boolean supportsAppsManagement(@NonNull final GBDevice device) {
return experimentalFeatures(device);
return experimentalSettingEnabled(device, "zepp_os_experimental_app_management");
}
@Override
@@ -388,6 +388,11 @@ public abstract class ZeppOsCoordinator extends HuamiCoordinator {
);
}
@Override
public int[] getSupportedDeviceSpecificExperimentalSettings(final GBDevice device) {
return new int[]{R.xml.devicesettings_zeppos_experimental};
}
/**
* Returns a superset of all settings supported by Zepp OS Devices. Unsupported settings are removed
* by {@link ZeppOsSettingsCustomizer}.
@@ -659,7 +664,7 @@ public abstract class ZeppOsCoordinator extends HuamiCoordinator {
}
public boolean supportsAssistant(final GBDevice device) {
return experimentalFeatures(device) && ZeppOsAssistantService.isSupported(getPrefs(device));
return experimentalSettingEnabled(device, "zepp_os_experimental_assistant") && ZeppOsAssistantService.isSupported(getPrefs(device));
}
public boolean supportsMaps(final GBDevice device) {
@@ -687,10 +692,6 @@ public abstract class ZeppOsCoordinator extends HuamiCoordinator {
.contains(service);
}
public static boolean experimentalFeatures(final GBDevice device) {
return getPrefs(device).getBoolean("zepp_os_experimental_features", false);
}
@Override
public boolean validateAuthKey(final String authKey) {
final byte[] authKeyBytes = authKey.trim().getBytes();
@@ -103,8 +103,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitWeather;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.ConfigurationMessage;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.DownloadRequestMessage;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.FitDataMessage;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.FitDefinitionMessage;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.GFDIMessage;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.MusicControlEntityUpdateMessage;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.ProtobufMessage;
@@ -516,11 +514,18 @@ public class GarminSupport extends AbstractBTLESingleDeviceSupport implements IC
@Override
public void onAppStart(final UUID uuid, final boolean start) {
if (!getCoordinator().experimentalSettingEnabled(getDevice(), "garmin_experimental_app_management")) {
LOG.warn("Experimental app management not enabled");
}
}
@Override
public void onAppDelete(final UUID uuid) {
if (!getCoordinator().experimentalSettingEnabled(getDevice(), "garmin_experimental_app_management")) {
LOG.warn("Experimental app management not enabled");
return;
}
final GdiInstalledAppsService.InstalledAppsService.InstalledApp app = installedApps.get(uuid);
if (app == null) {
@@ -201,6 +201,11 @@ public class ZeppOsAppsService extends AbstractZeppOsService {
public void deleteApp(final int appId) {
LOG.info("Delete app {}", String.format("0x%08x", appId));
if (!getCoordinator().experimentalSettingEnabled(getSupport().getDevice(), "zepp_os_experimental_app_management")) {
LOG.warn("Experimental app management not enabled");
return;
}
final ByteBuffer buf = ByteBuffer.allocate(20).order(ByteOrder.LITTLE_ENDIAN);
buf.put(CMD_APPS);
@@ -206,7 +206,7 @@ public class ZeppOsAssistantService extends AbstractZeppOsService {
}
voiceBuffer.clear();
if (ZeppOsCoordinator.experimentalFeatures(getSupport().getDevice())) {
if (getCoordinator().experimentalSettingEnabled(getSupport().getDevice(), "zepp_os_experimental_assistant")) {
requestCapabilities(builder);
}
}
@@ -187,4 +187,8 @@ public class GBPrefs extends Prefs {
public boolean refreshOnSwipe() {
return getBoolean("pref_refresh_on_swipe", true);
}
public boolean experimentalSettings() {
return getBoolean("experimental_settings", false);
}
}
+2
View File
@@ -739,6 +739,8 @@
<string name="title_activity_sleepmonitor">Sleep monitor</string>
<string name="pref_write_logfiles">Write log files</string>
<string name="pref_cache_weather">Cache weather information</string>
<string name="pref_experimental_settings_title">Experimental settings</string>
<string name="pref_experimental_settings_summary">Experimental settings might be unstable or not work as expected. Proceed at your own risk.</string>
<string name="pref_cache_weather_summary">Weather information will be cached across application restarts.</string>
<string name="pref_write_logfiles_not_available">File logging initialization failed, writing log files is currently not available. Restart the application to attempt to initialize the log files again.</string>
<string name="initializing">Initializing</string>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<Preference
android:icon="@drawable/ic_warning"
android:key="pref_experimental_warning"
android:summary="@string/pref_experimental_settings_summary" />
</androidx.preference.PreferenceScreen>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreferenceCompat
android:defaultValue="false"
android:icon="@drawable/ic_settings_applications"
android:key="garmin_experimental_app_management"
android:layout="@layout/preference_checkbox"
android:summary="Allow installed app management from Gadgetbridge. Not heavily tested. Uninstalling system apps might be dangerous."
android:title="App management" />
</androidx.preference.PreferenceScreen>
@@ -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_warning_gray"
android:key="pref_screen_experimental"
android:persistent="false"
android:title="@string/pref_experimental_settings_title">
</PreferenceScreen>
</androidx.preference.PreferenceScreen>
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreferenceCompat
android:defaultValue="false"
android:icon="@drawable/ic_settings_applications"
android:key="zepp_os_experimental_app_management"
android:layout="@layout/preference_checkbox"
android:summary="Allow installed app management from Gadgetbridge. Not heavily tested. Uninstalling system apps might be dangerous."
android:title="App management" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:icon="@drawable/ic_voice"
android:key="zepp_os_experimental_assistant"
android:layout="@layout/preference_checkbox"
android:summary="Enable Alexa / Zepp Flow manual debug options and voice receiving. Not yet functional."
android:title="Assistant service" />
</androidx.preference.PreferenceScreen>
+8
View File
@@ -463,6 +463,14 @@
app:iconSpaceReserved="false" />
</PreferenceCategory>
</PreferenceScreen>
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="experimental_settings"
android:layout="@layout/preference_checkbox"
android:summary="@string/pref_experimental_settings_summary"
android:title="@string/pref_experimental_settings_title"
app:iconSpaceReserved="false" />
</PreferenceScreen>
<PreferenceScreen