mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-28 12:56:49 +01:00
Xiaomi: refactor WidgetManager for Redmi Watch 4
The Redmi Watch 4 reports both an unsupported widget type and layout style: - The firmware supports a screen layout for a single full screens widget, which is defined by layout ID 128; - A full screen widget is a single 2x2 part, which is not supported. This commit adds support for both the new layout and the new widget type. Furthermore, this commit refactors the XiaomiWidgetManager. Previously, the supported layouts were determined by the types of parts supported by the device. However, the supported layouts are reported by the device through a bitfield in the widget capabilities message of which the purpose was unknown, which is now used to determine the supported layouts.
This commit is contained in:
parent
796f26f74f
commit
0b731611b9
@ -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;
|
||||
|
@ -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
|
||||
|
@ -20,5 +20,6 @@ public enum WidgetType {
|
||||
SMALL, // 1x1
|
||||
TALL, // 1x2
|
||||
WIDE, // 2x1
|
||||
LARGE, // 2x2
|
||||
;
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
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<WidgetLayout> getSupportedWidgetLayouts() {
|
||||
final List<WidgetLayout> layouts = new ArrayList<>();
|
||||
final Set<WidgetType> 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<WidgetPartSubtype> convertWorkoutTypesToPartSubtypes(final Collection<XiaomiWorkoutType> workoutTypes) {
|
||||
final List<WidgetPartSubtype> 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<WidgetPart> getSupportedWidgetParts(final WidgetType targetWidgetType) {
|
||||
final List<WidgetPart> parts = new LinkedList<>();
|
||||
@ -94,41 +108,29 @@ public class XiaomiWidgetManager implements WidgetManager {
|
||||
final Set<String> seenNames = new HashSet<>();
|
||||
final Set<String> duplicatedNames = new HashSet<>();
|
||||
|
||||
// get supported workout types and convert to subtypes for workout widgets
|
||||
final Collection<WidgetPartSubtype> 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<XiaomiWorkoutType> 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<WidgetPartSubtype> 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<WidgetScreen> getWidgetScreens() {
|
||||
final XiaomiProto.WidgetScreens rawWidgetScreens = getRawWidgetScreens();
|
||||
|
||||
final List<WidgetScreen> ret = new ArrayList<>(rawWidgetScreens.getWidgetScreenCount());
|
||||
final List<WidgetScreen> convertedScreens = new ArrayList<>(rawWidgetScreens.getWidgetScreenCount());
|
||||
final Collection<WidgetPartSubtype> workoutTypes = convertWorkoutTypesToPartSubtypes(XiaomiWorkoutType.getWorkoutTypesSupportedByDevice(getDevice()));
|
||||
|
||||
final List<XiaomiWorkoutType> 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<WidgetPart> convertedParts = new ArrayList<>(rawScreen.getWidgetPartCount());
|
||||
|
||||
final List<WidgetPart> 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<XiaomiWorkoutType> 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<XiaomiWorkoutType> 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();
|
||||
|
@ -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<XiaomiWorkoutType> getWorkoutTypesSupportedByDevice(final GBDevice device) {
|
||||
final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(device.getAddress()));
|
||||
final List<String> codes = prefs.getList(XiaomiPreferences.PREF_WORKOUT_TYPES, Collections.emptyList());
|
||||
final List<XiaomiWorkoutType> 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;
|
||||
}
|
||||
}
|
||||
|
@ -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<XiaomiWorkoutType> getWorkoutTypes(final GBDevice gbDevice) {
|
||||
final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
|
||||
final List<String> codes = prefs.getList(PREF_WORKOUT_TYPES, Collections.emptyList());
|
||||
final List<XiaomiWorkoutType> 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;
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -2707,6 +2707,8 @@
|
||||
<string name="widget_move_down">Move down</string>
|
||||
<string name="widget_missing_parts">Please select all widgets</string>
|
||||
<string name="widget_unknown_workout">Unknown workout - %s</string>
|
||||
<string name="widget_name_colored_tile">%1$s (colored tile)</string>
|
||||
<string name="widget_name_untitled">Untitled widget (%1$s)</string>
|
||||
<string name="pref_title_fossil_hr_navigation_instructions">Navigation instructions</string>
|
||||
<string name="pref_summary_fossil_hr_navigation_instructions">Configure on-watch navigation app behavior</string>
|
||||
<string name="pref_title_fossil_hr_nav_foreground">Come to foreground</string>
|
||||
|
Loading…
Reference in New Issue
Block a user