From a16b90f6aabcc316045621bedcf10e93d8ea99e9 Mon Sep 17 00:00:00 2001 From: MrYoranimo <1333535+MrYoranimo@users.noreply.github.com> Date: Fri, 15 May 2026 01:11:06 +0200 Subject: [PATCH] Xiaomi-protobuf: combine installed apps and watchface cache when reporting installed apps Because the list of installed apps and the list of installed faces are requested from Xiaomi devices separately, a race condition will occur if the lists are not combined: when processing the AppInfo event, all previously known installed apps are removed from the app manager cache, which will cause either all apps or all faces to get forgotten. --- .../service/devices/xiaomi/XiaomiSupport.java | 8 ++++++++ .../xiaomi/services/XiaomiRpkService.java | 12 +++++++++--- .../xiaomi/services/XiaomiWatchfaceService.java | 16 ++++++++++++---- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiSupport.java index 681a53d6c3..e9e5fa61a1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/XiaomiSupport.java @@ -441,6 +441,14 @@ public class XiaomiSupport extends AbstractDeviceSupport { return this.healthService; } + public XiaomiRpkService getRpkService() { + return this.rpkService; + } + + public XiaomiWatchfaceService getWatchfaceService() { + return this.watchfaceService; + } + @Override public String customStringFilter(final String inputString) { return StringUtils.replaceEach(inputString, EMOJI_SOURCE, EMOJI_TARGET); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiRpkService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiRpkService.java index ed0a1ba939..d858324291 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiRpkService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiRpkService.java @@ -22,11 +22,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.R; @@ -154,8 +154,10 @@ public class XiaomiRpkService extends AbstractXiaomiService implements XiaomiDat GBDeviceApp gbDeviceApp = new GBDeviceApp(UUID.nameUUIDFromBytes(packageName.getBytes()), appName, packageName, "", GBDeviceApp.Type.APP_GENERIC); apps.add(gbDeviceApp); } + final List appsAndFaces = new ArrayList<>(apps); + appsAndFaces.addAll(getSupport().getWatchfaceService().getInstalledFacesCache()); final GBDeviceEventAppInfo appInfoCmd = new GBDeviceEventAppInfo(); - appInfoCmd.apps = apps.toArray(new GBDeviceApp[0]); + appInfoCmd.apps = appsAndFaces.toArray(new GBDeviceApp[0]); getSupport().evaluateGBDeviceEvent(appInfoCmd); } @@ -205,4 +207,8 @@ public class XiaomiRpkService extends AbstractXiaomiService implements XiaomiDat device.sendDeviceUpdateIntent(getSupport().getContext()); } } + + public Collection getInstalledAppsCache() { + return Collections.unmodifiableList(apps); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiWatchfaceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiWatchfaceService.java index 860c09b960..0d8fa3d1f2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiWatchfaceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiWatchfaceService.java @@ -20,6 +20,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -45,6 +47,7 @@ public class XiaomiWatchfaceService extends AbstractXiaomiService implements Xia private final Set allWatchfaces = new HashSet<>(); private final Set userWatchfaces = new HashSet<>(); + private final List facesCache = new ArrayList<>(); private UUID activeWatchface = null; // Not null if we're installing a firmware @@ -102,10 +105,9 @@ public class XiaomiWatchfaceService extends AbstractXiaomiService implements Xia allWatchfaces.clear(); userWatchfaces.clear(); + facesCache.clear(); activeWatchface = null; - final List gbDeviceApps = new ArrayList<>(); - for (final XiaomiProto.WatchfaceInfo watchface : watchfaceList.getWatchfaceList()) { final UUID uuid = toWatchfaceUUID(watchface.getId()); allWatchfaces.add(uuid); @@ -123,11 +125,13 @@ public class XiaomiWatchfaceService extends AbstractXiaomiService implements Xia "", GBDeviceApp.Type.WATCHFACE ); - gbDeviceApps.add(gbDeviceApp); + facesCache.add(gbDeviceApp); } + final List appsAndFaces = new ArrayList<>(facesCache); + appsAndFaces.addAll(getSupport().getRpkService().getInstalledAppsCache()); final GBDeviceEventAppInfo appInfoCmd = new GBDeviceEventAppInfo(); - appInfoCmd.apps = gbDeviceApps.toArray(new GBDeviceApp[0]); + appInfoCmd.apps = appsAndFaces.toArray(new GBDeviceApp[0]); getSupport().evaluateGBDeviceEvent(appInfoCmd); } @@ -281,4 +285,8 @@ public class XiaomiWatchfaceService extends AbstractXiaomiService implements Xia device.sendDeviceUpdateIntent(getSupport().getContext()); } } + + public Collection getInstalledFacesCache() { + return Collections.unmodifiableList(facesCache); + } }