diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/widgets/WidgetScreenDetailsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/widgets/WidgetScreenDetailsActivity.java
index 8245be60a..14e60489e 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/widgets/WidgetScreenDetailsActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/widgets/WidgetScreenDetailsActivity.java
@@ -194,7 +194,8 @@ public class WidgetScreenDetailsActivity extends AbstractGBActivity {
updateWidget(cardWidgetBotLeft, labelWidgetBotLeft, 2);
updateWidget(cardWidgetBotRight, labelWidgetBotRight, 3);
break;
- case SINGLE:
+ case ONE_BY_TWO_SINGLE:
+ case TWO_BY_TWO_SINGLE:
updateWidget(cardWidgetTopLeft, labelWidgetTopLeft, -1);
updateWidget(cardWidgetTopRight, labelWidgetTopRight, -1);
updateWidget(cardWidgetCenter, labelWidgetCenter, 0);
@@ -202,9 +203,9 @@ public class WidgetScreenDetailsActivity extends AbstractGBActivity {
updateWidget(cardWidgetBotRight, labelWidgetBotRight, -1);
break;
case TWO:
- updateWidget(cardWidgetTopLeft, labelWidgetTopLeft, 0);
- updateWidget(cardWidgetTopRight, labelWidgetTopRight, 1);
- updateWidget(cardWidgetCenter, labelWidgetCenter, -1);
+ updateWidget(cardWidgetTopLeft, labelWidgetTopLeft, -1);
+ updateWidget(cardWidgetTopRight, labelWidgetTopRight, 0);
+ updateWidget(cardWidgetCenter, labelWidgetCenter, 1);
updateWidget(cardWidgetBotLeft, labelWidgetBotLeft, -1);
updateWidget(cardWidgetBotRight, labelWidgetBotRight, -1);
break;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/capabilities/widgets/WidgetLayout.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/capabilities/widgets/WidgetLayout.java
index 06341d38c..bc677be2c 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/capabilities/widgets/WidgetLayout.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/capabilities/widgets/WidgetLayout.java
@@ -21,11 +21,17 @@ import androidx.annotation.StringRes;
import nodomain.freeyourgadget.gadgetbridge.R;
public enum WidgetLayout {
+ // Square screen layouts, 2x2
TOP_1_BOT_2(R.string.widget_layout_top_1_bot_2, WidgetType.WIDE, WidgetType.SMALL, WidgetType.SMALL),
TOP_2_BOT_1(R.string.widget_layout_top_2_bot_1, WidgetType.SMALL, WidgetType.SMALL, WidgetType.SMALL),
TOP_2_BOT_2(R.string.widget_layout_top_2_bot_2, WidgetType.SMALL, WidgetType.SMALL, WidgetType.SMALL, WidgetType.SMALL),
- SINGLE(R.string.widget_layout_single, WidgetType.TALL),
+ TWO_BY_TWO_SINGLE(R.string.widget_layout_single, WidgetType.LARGE),
+
+ // Narrow screen layouts, 2x1
+ ONE_BY_TWO_SINGLE(R.string.widget_layout_single, WidgetType.TALL),
TWO(R.string.widget_layout_two, WidgetType.SMALL, WidgetType.SMALL),
+
+ // TODO Portrait screen layouts, 2x3
;
@StringRes
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/capabilities/widgets/WidgetType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/capabilities/widgets/WidgetType.java
index 53612a359..93823d20e 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/capabilities/widgets/WidgetType.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/capabilities/widgets/WidgetType.java
@@ -20,5 +20,6 @@ public enum WidgetType {
SMALL, // 1x1
TALL, // 1x2
WIDE, // 2x1
+ LARGE, // 2x2
;
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiWidgetManager.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiWidgetManager.java
index 63649618f..e99d5261b 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiWidgetManager.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiWidgetManager.java
@@ -16,6 +16,8 @@
along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.devices.xiaomi;
+import android.text.TextUtils;
+
import androidx.annotation.Nullable;
import com.google.protobuf.InvalidProtocolBufferException;
@@ -25,6 +27,7 @@ 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.LinkedList;
@@ -60,31 +63,42 @@ public class XiaomiWidgetManager implements WidgetManager {
@Override
public List getSupportedWidgetLayouts() {
final List layouts = new ArrayList<>();
- final Set partTypes = new HashSet<>();
- final XiaomiProto.WidgetParts rawWidgetParts = getRawWidgetParts();
-
- for (final XiaomiProto.WidgetPart widgetPart : rawWidgetParts.getWidgetPartList()) {
- partTypes.add(fromRawWidgetType(widgetPart.getType()));
+ final XiaomiProto.WidgetScreens widgetScreens = getRawWidgetScreens();
+ if (!widgetScreens.hasWidgetsCapabilities() || !widgetScreens.getWidgetsCapabilities().hasSupportedLayoutStyles()) {
+ return Collections.emptyList();
}
- if (partTypes.contains(WidgetType.WIDE) && partTypes.contains(WidgetType.SMALL)) {
- layouts.add(WidgetLayout.TOP_1_BOT_2);
- layouts.add(WidgetLayout.TOP_2_BOT_1);
- layouts.add(WidgetLayout.TOP_2_BOT_2);
- }
+ final int supportedBitmap = getRawWidgetScreens().getWidgetsCapabilities().getSupportedLayoutStyles();
- if (partTypes.contains(WidgetType.TALL)) {
- layouts.add(WidgetLayout.SINGLE);
-
- if (partTypes.contains(WidgetType.SMALL)) {
- layouts.add(WidgetLayout.TWO);
+ // highest known layout style is 0x4000 (1 << 14)
+ for (int i = 0; i < 15; i++) {
+ final int layoutStyleId = 1 << i;
+ if ((supportedBitmap & layoutStyleId) != 0) {
+ layouts.add(fromRawLayout(layoutStyleId));
}
}
return layouts;
}
+ private static Collection convertWorkoutTypesToPartSubtypes(final Collection workoutTypes) {
+ final List subtypes = new ArrayList<>(workoutTypes.size());
+
+ // convert workout types to subtypes
+ for (final XiaomiWorkoutType workoutType : workoutTypes) {
+ subtypes.add(new WidgetPartSubtype(
+ String.valueOf(workoutType.getCode()),
+ workoutType.getName()
+ ));
+ }
+
+ // sort by name before returning
+ Collections.sort(subtypes, (it, other) -> it.getName().compareToIgnoreCase(other.getName()));
+
+ return subtypes;
+ }
+
@Override
public List getSupportedWidgetParts(final WidgetType targetWidgetType) {
final List parts = new LinkedList<>();
@@ -94,41 +108,29 @@ public class XiaomiWidgetManager implements WidgetManager {
final Set seenNames = new HashSet<>();
final Set duplicatedNames = new HashSet<>();
+ // get supported workout types and convert to subtypes for workout widgets
+ final Collection subtypes = convertWorkoutTypesToPartSubtypes(XiaomiWorkoutType.getWorkoutTypesSupportedByDevice(getDevice()));
+
for (final XiaomiProto.WidgetPart widgetPart : rawWidgetParts.getWidgetPartList()) {
- final WidgetType type = fromRawWidgetType(widgetPart.getType());
+ final WidgetPart convertedPart = fromRawWidgetPart(widgetPart, subtypes);
- if (type != null && type.equals(targetWidgetType)) {
- final WidgetPart newPart = new WidgetPart(
- String.valueOf(widgetPart.getId()),
- widgetPart.getTitle(),
- type
- );
-
- if (widgetPart.getFunction() == 16) {
- if (StringUtils.isBlank(newPart.getName())) {
- newPart.setName(GBApplication.getContext().getString(R.string.menuitem_workout));
- }
-
- final List workoutTypes = XiaomiPreferences.getWorkoutTypes(getDevice());
- for (final XiaomiWorkoutType workoutType : workoutTypes) {
- newPart.getSupportedSubtypes().add(
- new WidgetPartSubtype(
- String.valueOf(workoutType.getCode()),
- workoutType.getName()
- )
- );
- Collections.sort(newPart.getSupportedSubtypes(), (p1, p2) -> p1.getName().compareToIgnoreCase(p2.getName()));
- }
- }
-
- if (seenNames.contains(newPart.getFullName())) {
- duplicatedNames.add(newPart.getFullName());
- } else {
- seenNames.add(newPart.getFullName());
- }
-
- parts.add(newPart);
+ if (convertedPart == null) {
+ continue;
}
+
+ if (!convertedPart.getType().equals(targetWidgetType)) {
+ continue;
+ }
+
+ final String convertedPartName = convertedPart.getName();
+ if (seenNames.contains(convertedPartName)) {
+ duplicatedNames.add(convertedPartName);
+ } else {
+ seenNames.add(convertedPartName);
+ }
+
+ parts.add(convertedPart);
+ seenNames.add(convertedPart.getName());
}
// Ensure that all names are unique
@@ -138,66 +140,94 @@ public class XiaomiWidgetManager implements WidgetManager {
}
}
+ Collections.sort(parts, (it, other) -> it.getName().compareToIgnoreCase(other.getName()));
return parts;
}
+ private WidgetPart fromRawWidgetPart(final XiaomiProto.WidgetPart widgetPart, final Collection subtypes) {
+ final WidgetType type = fromRawWidgetType(widgetPart.getType());
+
+ if (type == null) {
+ LOG.warn("Unknown widget type {}", widgetPart.getType());
+ return null;
+ }
+
+ final String stringifiedId = String.valueOf(widgetPart.getId());
+ final WidgetPart convertedPart = new WidgetPart(
+ stringifiedId,
+ GBApplication.getContext().getString(R.string.widget_name_untitled, stringifiedId),
+ type
+ );
+
+ if (!TextUtils.isEmpty(widgetPart.getTitle())) {
+ convertedPart.setName(widgetPart.getTitle());
+ } else {
+ // some models do not provide the name of the widget in the screens list, resolve it here
+ final XiaomiProto.WidgetPart resolvedPart = findRawPart(widgetPart.getType(), widgetPart.getId());
+ if (resolvedPart != null) {
+ convertedPart.setName(resolvedPart.getTitle());
+ }
+ }
+
+ if (widgetPart.getFunction() == 16) {
+ if (StringUtils.isBlank(convertedPart.getName())) {
+ convertedPart.setName(GBApplication.getContext().getString(R.string.menuitem_workout));
+ }
+
+ if (subtypes != null) {
+ convertedPart.getSupportedSubtypes().addAll(subtypes);
+
+ if (widgetPart.getSubType() != 0) {
+ final String widgetSubtype = String.valueOf(widgetPart.getSubType());
+
+ for (final WidgetPartSubtype availableSubtype : subtypes) {
+ if (availableSubtype.getId().equals(widgetSubtype)) {
+ convertedPart.setSubtype(availableSubtype);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if ((widgetPart.getId() & 256) != 0) {
+ convertedPart.setName(GBApplication.getContext().getString(R.string.widget_name_colored_tile, convertedPart.getName()));
+ }
+
+ return convertedPart;
+ }
+
@Override
public List getWidgetScreens() {
final XiaomiProto.WidgetScreens rawWidgetScreens = getRawWidgetScreens();
- final List ret = new ArrayList<>(rawWidgetScreens.getWidgetScreenCount());
+ final List convertedScreens = new ArrayList<>(rawWidgetScreens.getWidgetScreenCount());
+ final Collection workoutTypes = convertWorkoutTypesToPartSubtypes(XiaomiWorkoutType.getWorkoutTypesSupportedByDevice(getDevice()));
- final List workoutTypes = XiaomiPreferences.getWorkoutTypes(getDevice());
+ for (final XiaomiProto.WidgetScreen rawScreen : rawWidgetScreens.getWidgetScreenList()) {
+ final WidgetLayout layout = fromRawLayout(rawScreen.getLayout());
- for (final XiaomiProto.WidgetScreen widgetScreen : rawWidgetScreens.getWidgetScreenList()) {
- final WidgetLayout layout = fromRawLayout(widgetScreen.getLayout());
+ final List convertedParts = new ArrayList<>(rawScreen.getWidgetPartCount());
- final List parts = new ArrayList<>(widgetScreen.getWidgetPartCount());
+ for (final XiaomiProto.WidgetPart rawPart : rawScreen.getWidgetPartList()) {
+ final WidgetPart convertedPart = fromRawWidgetPart(rawPart, workoutTypes);
- for (final XiaomiProto.WidgetPart widgetPart : widgetScreen.getWidgetPartList()) {
- final WidgetType type = fromRawWidgetType(widgetPart.getType());
-
- final WidgetPart newPart = new WidgetPart(
- String.valueOf(widgetPart.getId()),
- "Unknown (" + widgetPart.getId() + ")",
- type
- );
-
- // Find the name
- final XiaomiProto.WidgetPart rawPart1 = findRawPart(widgetPart.getType(), widgetPart.getId());
- if (rawPart1 != null) {
- newPart.setName(rawPart1.getTitle());
+ if (convertedPart == null) {
+ LOG.warn("Widget cannot be converted, result was null for following raw widget: {}", rawPart);
+ continue;
}
- if (widgetPart.getFunction() == 16) {
- if (StringUtils.isBlank(newPart.getName())) {
- newPart.setName(GBApplication.getContext().getString(R.string.menuitem_workout));
- }
- }
-
- // Get the proper subtype, if any
- if (widgetPart.getSubType() != 0) {
- for (final XiaomiWorkoutType workoutType : workoutTypes) {
- if (workoutType.getCode() == widgetPart.getSubType()) {
- newPart.setSubtype(new WidgetPartSubtype(
- String.valueOf(workoutType.getCode()),
- workoutType.getName()
- ));
- }
- }
- }
-
- parts.add(newPart);
+ convertedParts.add(convertedPart);
}
- ret.add(new WidgetScreen(
- String.valueOf(widgetScreen.getId()),
+ convertedScreens.add(new WidgetScreen(
+ String.valueOf(rawScreen.getId()),
layout,
- parts
+ convertedParts
));
}
- return ret;
+ return convertedScreens;
}
@Override
@@ -219,26 +249,9 @@ public class XiaomiWidgetManager implements WidgetManager {
public void saveScreen(final WidgetScreen widgetScreen) {
final XiaomiProto.WidgetScreens rawWidgetScreens = getRawWidgetScreens();
- final int layoutNum;
- switch (widgetScreen.getLayout()) {
- case TOP_2_BOT_2:
- layoutNum = 1;
- break;
- case TOP_1_BOT_2:
- layoutNum = 2;
- break;
- case TOP_2_BOT_1:
- layoutNum = 4;
- break;
- case TWO:
- layoutNum = 256;
- break;
- case SINGLE:
- layoutNum = 512;
- break;
- default:
- LOG.warn("Unknown widget screens layout {}", widgetScreen.getLayout());
- return;
+ final int layoutNum = toRawLayout(widgetScreen.getLayout());
+ if (layoutNum == -1) {
+ return;
}
XiaomiProto.WidgetScreen.Builder rawScreen = null;
@@ -265,6 +278,8 @@ public class XiaomiWidgetManager implements WidgetManager {
rawScreen.setLayout(layoutNum);
rawScreen.clearWidgetPart();
+ final Collection workoutTypes = XiaomiWorkoutType.getWorkoutTypesSupportedByDevice(getDevice());
+
for (final WidgetPart newPart : widgetScreen.getParts()) {
// Find the existing raw part
final XiaomiProto.WidgetPart knownRawPart = findRawPart(
@@ -274,14 +289,21 @@ public class XiaomiWidgetManager implements WidgetManager {
final XiaomiProto.WidgetPart.Builder newRawPartBuilder = XiaomiProto.WidgetPart.newBuilder(knownRawPart);
+ // TODO only support subtypes on widget with type 16
if (newPart.getSubtype() != null) {
- // Get the workout type as subtype
- final List workoutTypes = XiaomiPreferences.getWorkoutTypes(getDevice());
- for (final XiaomiWorkoutType workoutType : workoutTypes) {
- if (newPart.getSubtype().getId().equals(String.valueOf(workoutType.getCode()))) {
- newRawPartBuilder.setSubType(workoutType.getCode());
- break;
+ try {
+ final int rawSubtype = Integer.parseInt(newPart.getSubtype().getId());
+
+ // Get the workout type as subtype
+ for (final XiaomiWorkoutType workoutType : workoutTypes) {
+ if (rawSubtype == workoutType.getCode()) {
+ newRawPartBuilder.setSubType(workoutType.getCode());
+ break;
+ }
}
+ } catch (final NumberFormatException ex) {
+ LOG.error("Failed to convert workout type {} to a number, defaulting to 1", newPart.getSubtype());
+ newRawPartBuilder.setSubType(1);
}
}
@@ -355,6 +377,8 @@ public class XiaomiWidgetManager implements WidgetManager {
return WidgetType.WIDE;
case 3:
return WidgetType.TALL;
+ case 4:
+ return WidgetType.LARGE;
default:
LOG.warn("Unknown widget type {}", rawType);
return null;
@@ -369,6 +393,8 @@ public class XiaomiWidgetManager implements WidgetManager {
return 2;
case TALL:
return 3;
+ case LARGE:
+ return 4;
default:
throw new IllegalArgumentException("Unknown widget type " + widgetType);
}
@@ -377,22 +403,57 @@ public class XiaomiWidgetManager implements WidgetManager {
@Nullable
private WidgetLayout fromRawLayout(final int rawLayout) {
switch (rawLayout) {
- case 1:
+ case 1: // 2x2, top 2x small, bottom 2x small
return WidgetLayout.TOP_2_BOT_2;
- case 2:
+ case 2: // 2x2, top wide, bottom 2x small
return WidgetLayout.TOP_1_BOT_2;
- case 4:
+ case 4: // 2x2, top 2x small, bottom wide
return WidgetLayout.TOP_2_BOT_1;
- case 256:
+ case 128: // 2x2, full screen
+ return WidgetLayout.TWO_BY_TWO_SINGLE;
+ case 256: // 1x2, top small, bottom small
return WidgetLayout.TWO;
- case 512:
- return WidgetLayout.SINGLE;
+ case 512: // 1x2, full screen
+ return WidgetLayout.ONE_BY_TWO_SINGLE;
+ case 8: // 2x2, left tall, right 2x square
+ case 16: // 2x2, left 2x square, right tall
+ case 32: // 2x2, top wide, bottom wide
+ case 64: // 2x2, left tall, right tall
+ case 1024: // 2x3, top 2x square, bottom 2x2 square
+ case 2048: // 2x3, top 2x2 square, bottom 2x square
+ case 4096: // 2x3, top wide, bottom 2x2 square
+ case 8192: // 2x3, top 2x2 square, bottom wide
+ case 16384: // 2x3, full screen
default:
LOG.warn("Unknown widget screens layout {}", rawLayout);
return null;
}
}
+ private int toRawLayout(final WidgetLayout layout) {
+ if (layout == null) {
+ return -1;
+ }
+
+ switch (layout) {
+ case TOP_2_BOT_2:
+ return 1;
+ case TOP_1_BOT_2:
+ return 2;
+ case TOP_2_BOT_1:
+ return 4;
+ case TWO_BY_TWO_SINGLE:
+ return 128;
+ case TWO:
+ return 256;
+ case ONE_BY_TWO_SINGLE:
+ return 512;
+ default:
+ LOG.warn("Widget layout {} cannot be converted to raw variant", layout);
+ return -1;
+ }
+ }
+
@Nullable
private XiaomiProto.WidgetPart findRawPart(final int type, final int id) {
final XiaomiProto.WidgetParts rawWidgetParts = getRawWidgetParts();
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiWorkoutType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiWorkoutType.java
index 35fb453c0..0141710f4 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiWorkoutType.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xiaomi/XiaomiWorkoutType.java
@@ -18,7 +18,16 @@ package nodomain.freeyourgadget.gadgetbridge.devices.xiaomi;
import androidx.annotation.StringRes;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
+import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiPreferences;
+import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class XiaomiWorkoutType {
private final int code;
@@ -58,4 +67,23 @@ public class XiaomiWorkoutType {
return -1;
}
+
+ public static Collection getWorkoutTypesSupportedByDevice(final GBDevice device) {
+ final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(device.getAddress()));
+ final List codes = prefs.getList(XiaomiPreferences.PREF_WORKOUT_TYPES, Collections.emptyList());
+ final List ret = new ArrayList<>(codes.size());
+
+ for (final String code : codes) {
+ final int codeInt = Integer.parseInt(code);
+ final int codeNameStringRes = XiaomiWorkoutType.mapWorkoutName(codeInt);
+ ret.add(new XiaomiWorkoutType(
+ codeInt,
+ codeNameStringRes != -1 ?
+ GBApplication.getContext().getString(codeNameStringRes) :
+ GBApplication.getContext().getString(R.string.widget_unknown_workout, code)
+ ));
+ }
+
+ return ret;
+ }
}
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 d325b972a..556c9f451 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
@@ -91,22 +91,4 @@ public final class XiaomiPreferences {
final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
return prefs.getBoolean("keep_activity_data_on_device", false);
}
-
- // FIXME this function should not be here
- public static List getWorkoutTypes(final GBDevice gbDevice) {
- final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
- final List codes = prefs.getList(PREF_WORKOUT_TYPES, Collections.emptyList());
- final List ret = new ArrayList<>(codes.size());
- for (final String code : codes) {
- final int codeInt = Integer.parseInt(code);
- final int codeNameStringRes = XiaomiWorkoutType.mapWorkoutName(codeInt);
- ret.add(new XiaomiWorkoutType(
- codeInt,
- codeNameStringRes != -1 ?
- GBApplication.getContext().getString(codeNameStringRes) :
- GBApplication.getContext().getString(R.string.widget_unknown_workout, code)
- ));
- }
- return ret;
- }
}
diff --git a/app/src/main/proto/xiaomi.proto b/app/src/main/proto/xiaomi.proto
index fdc84a849..24c759f51 100644
--- a/app/src/main/proto/xiaomi.proto
+++ b/app/src/main/proto/xiaomi.proto
@@ -238,7 +238,13 @@ message WidgetScreens {
message WidgetsCapabilities {
optional uint32 minWidgets = 1; // 1
optional uint32 maxWidgets = 2; // 7
- optional uint32 unknown3 = 3; // 768
+
+ // bitmap:
+ // - 0b0000_0011_0000_0000 (768) on bands
+ // - 0b0000_0000_0000_0111 (7) on some square/round devices (Watch S1 Active)
+ // - 0b0000_0000_1000_0111 (135) on some square/round devices (Redmi Watch 4)
+ // - 0b0111_1100_0000_0000 (31744) on portrait devices (Band 8 Pro)
+ optional uint32 supportedLayoutStyles = 3;
}
message WidgetScreen {
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index fa5a87498..f85965d3f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -2707,6 +2707,8 @@
Move down
Please select all widgets
Unknown workout - %s
+ %1$s (colored tile)
+ Untitled widget (%1$s)
Navigation instructions
Configure on-watch navigation app behavior
Come to foreground