1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-12-25 18:15:49 +01:00

Mi Band 7: Enable app support

This commit is contained in:
José Rebelo 2022-09-07 21:11:21 +01:00 committed by Gitea
parent 230cbe964b
commit f915ab5ebd
23 changed files with 373 additions and 538 deletions

View File

@ -16,6 +16,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.activities.devicesettings;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.preference.Preference;
@ -70,4 +72,11 @@ public interface DeviceSpecificSettingsHandler {
* @return the {@link GBDevice}.
*/
GBDevice getDevice();
/**
* Get the current {@link Context}.
*
* @return the {@link Context}.
*/
Context getContext();
}

View File

@ -22,7 +22,12 @@ import android.net.Uri;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.capabilities.HeartRateCapability;
import nodomain.freeyourgadget.gadgetbridge.capabilities.password.PasswordCapabilityImpl;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
@ -102,11 +107,95 @@ public abstract class Huami2021Coordinator extends HuamiCoordinator {
return false;
}
@Override
public boolean supportsSmartWakeup(final GBDevice device) {
return true;
}
@Override
public int getReminderSlotCount() {
return 50;
}
@Override
public String[] getSupportedLanguageSettings(GBDevice device) {
return new String[]{
"auto",
"de_DE",
"en_US",
"es_ES",
"fr_FR",
"it_IT",
"nl_NL",
"pt_PT",
"tr_TR",
};
}
@Override
public PasswordCapabilityImpl.Mode getPasswordCapability() {
return PasswordCapabilityImpl.Mode.NUMBERS_6;
}
@Override
public List<HeartRateCapability.MeasurementInterval> getHeartRateMeasurementIntervals() {
return Arrays.asList(
HeartRateCapability.MeasurementInterval.OFF,
HeartRateCapability.MeasurementInterval.SMART,
HeartRateCapability.MeasurementInterval.MINUTES_1,
HeartRateCapability.MeasurementInterval.MINUTES_10,
HeartRateCapability.MeasurementInterval.MINUTES_30
);
}
@Override
public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
return new int[]{
R.xml.devicesettings_header_time,
//R.xml.devicesettings_timeformat,
R.xml.devicesettings_dateformat_2,
// TODO R.xml.devicesettings_world_clocks,
R.xml.devicesettings_header_display,
R.xml.devicesettings_huami2021_displayitems,
R.xml.devicesettings_huami2021_shortcuts,
R.xml.devicesettings_nightmode,
R.xml.devicesettings_liftwrist_display_sensitivity,
R.xml.devicesettings_password,
R.xml.devicesettings_always_on_display,
R.xml.devicesettings_screen_timeout_5_to_15,
R.xml.devicesettings_screen_brightness,
R.xml.devicesettings_header_health,
R.xml.devicesettings_heartrate_sleep_alert_activity_stress_spo2,
R.xml.devicesettings_inactivity_dnd_no_threshold,
R.xml.devicesettings_goal_notification,
R.xml.devicesettings_header_workout,
R.xml.devicesettings_workout_start_on_phone,
R.xml.devicesettings_workout_send_gps_to_band,
R.xml.devicesettings_header_notifications,
R.xml.devicesettings_vibrationpatterns,
R.xml.devicesettings_donotdisturb_withauto_and_always,
R.xml.devicesettings_screen_on_on_notifications,
R.xml.devicesettings_autoremove_notifications,
R.xml.devicesettings_canned_reply_16,
R.xml.devicesettings_transliteration,
R.xml.devicesettings_header_calendar,
R.xml.devicesettings_sync_calendar,
R.xml.devicesettings_header_other,
R.xml.devicesettings_device_actions_without_not_wear,
R.xml.devicesettings_header_connection,
R.xml.devicesettings_expose_hr_thirdparty,
R.xml.devicesettings_bt_connected_advertisement,
R.xml.devicesettings_high_mtu,
};
}
@Override
public int[] getSupportedDeviceSpecificAuthenticationSettings() {
return new int[]{
@ -114,6 +203,11 @@ public abstract class Huami2021Coordinator extends HuamiCoordinator {
};
}
@Override
public DeviceSpecificSettingsCustomizer getDeviceSpecificSettingsCustomizer(final GBDevice device) {
return new Huami2021SettingsCustomizer(device);
}
@Override
public int getBondingStyle() {
return BONDING_STYLE_REQUIRE_KEY;

View File

@ -0,0 +1,103 @@
/* Copyright (C) 2022 José Rebelo
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.huami;
import android.os.Parcel;
import android.text.InputType;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import com.mobeta.android.dslv.DragSortListPreference;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021MenuType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiVibrationPatternNotificationType;
import nodomain.freeyourgadget.gadgetbridge.util.MapUtils;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class Huami2021SettingsCustomizer extends HuamiSettingsCustomizer {
public Huami2021SettingsCustomizer(final GBDevice device) {
super(device);
}
@Override
public void customizeSettings(final DeviceSpecificSettingsHandler handler, final Prefs prefs) {
super.customizeSettings(handler, prefs);
setupDisplayItemsPref(
HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE,
HuamiConst.PREF_ALL_DISPLAY_ITEMS,
Huami2021MenuType.displayItemNameLookup,
handler,
prefs
);
setupDisplayItemsPref(
HuamiConst.PREF_SHORTCUTS_SORTABLE,
HuamiConst.PREF_ALL_SHORTCUTS,
Huami2021MenuType.shortcutsNameLookup,
handler,
prefs
);
}
private void setupDisplayItemsPref(final String prefKey,
final String allItemsPrefKey,
final Map<String, Integer> nameLookup,
final DeviceSpecificSettingsHandler handler,
final Prefs prefs) {
final DragSortListPreference pref = handler.findPreference(prefKey);
if (pref == null) {
return;
}
final List<String> allDisplayItems = prefs.getList(allItemsPrefKey, null);
if (allDisplayItems == null || allDisplayItems.isEmpty()) {
return;
}
final CharSequence[] entries = new CharSequence[allDisplayItems.size()];
final CharSequence[] values = new CharSequence[allDisplayItems.size()];
for (int i = 0; i < allDisplayItems.size(); i++) {
final String screenId = allDisplayItems.get(i);
final String screenName;
if (screenId.equals("more")) {
screenName = handler.getContext().getString(R.string.menuitem_more);
} else if (nameLookup.containsKey(screenId)) {
screenName = handler.getContext().getString(nameLookup.get(screenId));
} else {
screenName = handler.getContext().getString(R.string.menuitem_unknown_app, screenId);
}
entries[i] = screenName;
values[i] = screenId;
}
pref.setEntries(entries);
pref.setEntryValues(values);
}
}

View File

@ -60,9 +60,11 @@ public class HuamiConst {
public static final String XIAOMI_SMART_BAND7_NAME = "Xiaomi Smart Band 7";
public static final String PREF_DISPLAY_ITEMS = "display_items";
public static final String PREF_ALL_DISPLAY_ITEMS = "all_display_items";
public static final String PREF_DISPLAY_ITEMS_SORTABLE = "display_items_sortable";
public static final String PREF_WORKOUT_ACTIVITY_TYPES_SORTABLE = "workout_activity_types_sortable";
public static final String PREF_SHORTCUTS = "shortcuts";
public static final String PREF_ALL_SHORTCUTS = "all_shortcuts";
public static final String PREF_SHORTCUTS_SORTABLE = "shortcuts_sortable";
public static final String PREF_EXPOSE_HR_THIRDPARTY = "expose_hr_thirdparty";
public static final String PREF_USE_CUSTOM_FONT = "use_custom_font";

View File

@ -75,6 +75,9 @@ public abstract class HuamiFWHelper extends AbstractMiBandFWHelper {
case WATCHFACE:
resId = R.string.kind_watchface;
break;
case APP:
resId = R.string.kind_app;
break;
case INVALID:
// fall through
}

View File

@ -45,7 +45,7 @@ public class HuamiSettingsCustomizer implements DeviceSpecificSettingsCustomizer
}
@Override
public void customizeSettings(final DeviceSpecificSettingsHandler handler, Prefs prefs) {
public void customizeSettings(final DeviceSpecificSettingsHandler handler, final Prefs prefs) {
for (HuamiVibrationPatternNotificationType notificationType : HuamiVibrationPatternNotificationType.values()) {
final String typeKey = notificationType.name().toLowerCase(Locale.ROOT);

View File

@ -25,16 +25,9 @@ import androidx.annotation.NonNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.capabilities.HeartRateCapability;
import nodomain.freeyourgadget.gadgetbridge.capabilities.password.PasswordCapabilityImpl;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.huami.Huami2021Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
@ -67,88 +60,4 @@ public class AmazfitGTS3Coordinator extends Huami2021Coordinator {
final AmazfitGTS3FWInstallHandler handler = new AmazfitGTS3FWInstallHandler(uri, context);
return handler.isValid() ? handler : null;
}
@Override
public boolean supportsSmartWakeup(final GBDevice device) {
return true;
}
@Override
public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
return new int[]{
R.xml.devicesettings_header_time,
//R.xml.devicesettings_timeformat,
R.xml.devicesettings_dateformat_2,
// TODO R.xml.devicesettings_world_clocks,
R.xml.devicesettings_header_display,
R.xml.devicesettings_amazfitgts3_displayitems,
R.xml.devicesettings_amazfitgts3_shortcuts,
R.xml.devicesettings_nightmode,
R.xml.devicesettings_liftwrist_display_sensitivity,
R.xml.devicesettings_password,
R.xml.devicesettings_always_on_display,
R.xml.devicesettings_screen_timeout_5_to_15,
R.xml.devicesettings_screen_brightness,
R.xml.devicesettings_header_health,
R.xml.devicesettings_heartrate_sleep_alert_activity_stress_spo2,
R.xml.devicesettings_inactivity_dnd_no_threshold,
R.xml.devicesettings_goal_notification,
R.xml.devicesettings_header_workout,
R.xml.devicesettings_workout_start_on_phone,
R.xml.devicesettings_workout_send_gps_to_band,
R.xml.devicesettings_header_notifications,
R.xml.devicesettings_vibrationpatterns,
R.xml.devicesettings_donotdisturb_withauto_and_always,
R.xml.devicesettings_screen_on_on_notifications,
R.xml.devicesettings_autoremove_notifications,
R.xml.devicesettings_canned_reply_16,
R.xml.devicesettings_transliteration,
R.xml.devicesettings_header_calendar,
R.xml.devicesettings_sync_calendar,
R.xml.devicesettings_header_other,
R.xml.devicesettings_device_actions_without_not_wear,
R.xml.devicesettings_header_connection,
R.xml.devicesettings_expose_hr_thirdparty,
R.xml.devicesettings_bt_connected_advertisement,
R.xml.devicesettings_high_mtu,
};
}
@Override
public String[] getSupportedLanguageSettings(GBDevice device) {
return new String[]{
"auto",
"de_DE",
"en_US",
"es_ES",
"fr_FR",
"it_IT",
"nl_NL",
"pt_PT",
"tr_TR",
};
}
@Override
public PasswordCapabilityImpl.Mode getPasswordCapability() {
return PasswordCapabilityImpl.Mode.NUMBERS_6;
}
@Override
public List<HeartRateCapability.MeasurementInterval> getHeartRateMeasurementIntervals() {
return Arrays.asList(
HeartRateCapability.MeasurementInterval.OFF,
HeartRateCapability.MeasurementInterval.SMART,
HeartRateCapability.MeasurementInterval.MINUTES_1,
HeartRateCapability.MeasurementInterval.MINUTES_10,
HeartRateCapability.MeasurementInterval.MINUTES_30
);
}
}

View File

@ -25,16 +25,9 @@ import androidx.annotation.NonNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.capabilities.HeartRateCapability;
import nodomain.freeyourgadget.gadgetbridge.capabilities.password.PasswordCapabilityImpl;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.huami.Huami2021Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
@ -67,88 +60,4 @@ public class MiBand7Coordinator extends Huami2021Coordinator {
final MiBand7FWInstallHandler handler = new MiBand7FWInstallHandler(uri, context);
return handler.isValid() ? handler : null;
}
@Override
public boolean supportsSmartWakeup(final GBDevice device) {
return true;
}
@Override
public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
return new int[]{
R.xml.devicesettings_header_time,
//R.xml.devicesettings_timeformat,
R.xml.devicesettings_dateformat_2,
// TODO R.xml.devicesettings_world_clocks,
R.xml.devicesettings_header_display,
R.xml.devicesettings_miband7_displayitems,
R.xml.devicesettings_miband7_shortcuts,
R.xml.devicesettings_nightmode,
R.xml.devicesettings_liftwrist_display_sensitivity,
R.xml.devicesettings_password,
R.xml.devicesettings_always_on_display,
R.xml.devicesettings_screen_timeout_5_to_15,
R.xml.devicesettings_screen_brightness,
R.xml.devicesettings_header_health,
R.xml.devicesettings_heartrate_sleep_alert_activity_stress_spo2,
R.xml.devicesettings_inactivity_dnd_no_threshold,
R.xml.devicesettings_goal_notification,
R.xml.devicesettings_header_workout,
R.xml.devicesettings_workout_start_on_phone,
R.xml.devicesettings_workout_send_gps_to_band,
R.xml.devicesettings_header_notifications,
R.xml.devicesettings_vibrationpatterns,
R.xml.devicesettings_donotdisturb_withauto_and_always,
R.xml.devicesettings_screen_on_on_notifications,
R.xml.devicesettings_autoremove_notifications,
R.xml.devicesettings_canned_reply_16,
R.xml.devicesettings_transliteration,
R.xml.devicesettings_header_calendar,
R.xml.devicesettings_sync_calendar,
R.xml.devicesettings_header_other,
R.xml.devicesettings_device_actions_without_not_wear,
R.xml.devicesettings_header_connection,
R.xml.devicesettings_expose_hr_thirdparty,
R.xml.devicesettings_bt_connected_advertisement,
R.xml.devicesettings_high_mtu,
};
}
@Override
public String[] getSupportedLanguageSettings(GBDevice device) {
return new String[]{
"auto",
"de_DE",
"en_US",
"es_ES",
"fr_FR",
"it_IT",
"nl_NL",
"pt_PT",
"tr_TR",
};
}
@Override
public PasswordCapabilityImpl.Mode getPasswordCapability() {
return PasswordCapabilityImpl.Mode.NUMBERS_6;
}
@Override
public List<HeartRateCapability.MeasurementInterval> getHeartRateMeasurementIntervals() {
return Arrays.asList(
HeartRateCapability.MeasurementInterval.OFF,
HeartRateCapability.MeasurementInterval.SMART,
HeartRateCapability.MeasurementInterval.MINUTES_1,
HeartRateCapability.MeasurementInterval.MINUTES_10,
HeartRateCapability.MeasurementInterval.MINUTES_30
);
}
}

View File

@ -102,8 +102,13 @@ public abstract class Huami2021FirmwareInfo extends AbstractHuamiFirmwareInfo {
}
final String appType = getAppType();
if ("watchface".equals(appType)) {
return HuamiFirmwareType.WATCHFACE;
switch(appType) {
case "watchface":
return HuamiFirmwareType.WATCHFACE;
case "app":
return HuamiFirmwareType.APP;
default:
LOG.warn("Unknown app type {}", appType);
}
return HuamiFirmwareType.INVALID;
@ -126,11 +131,17 @@ public abstract class Huami2021FirmwareInfo extends AbstractHuamiFirmwareInfo {
case FIRMWARE:
return getFirmwareVersion(getBytes());
case WATCHFACE:
final String appName = getAppName();
if (appName == null) {
final String watchfaceName = getAppName();
if (watchfaceName == null) {
return "(unknown watchface)";
}
return String.format("%s (watchface)", appName);
return String.format("%s (watchface)", watchfaceName);
case APP:
final String appName = getAppName();
if (appName == null) {
return "(unknown app)";
}
return String.format("%s (app)", appName);
}
return null;
@ -204,7 +215,7 @@ public abstract class Huami2021FirmwareInfo extends AbstractHuamiFirmwareInfo {
// TODO Show preview icon?
final String appName = jsonObject.getJSONObject("app").getString("appName");
return String.format("%s (watchface)", appName);
return String.format("%s", appName);
} catch (final Exception e) {
LOG.error("Failed to parse app.json", e);
}

View File

@ -19,55 +19,57 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.huami;
import java.util.HashMap;
import java.util.Map;
import nodomain.freeyourgadget.gadgetbridge.R;
public class Huami2021MenuType {
/**
* These somewhat match the ones in {@link HuamiMenuType}, but not all. The band sends and
* receives those as 8-digit upper case hex strings.
*/
public static final Map<String, Integer> displayItemIdLookup = new HashMap<String, Integer>() {{
put("personal_activity_intelligence", 0x01);
put("hr", 0x02);
put("workout", 0x03);
put("weather", 0x04);
put("alarm", 0x09);
put("worldclock", 0x1A);
put("music", 0x0B);
put("stopwatch", 0x0C);
put("countdown", 0x0D);
put("findphone", 0x0E);
put("mutephone", 0x0F);
put("settings", 0x13);
put("workout_history", 0x14);
put("eventreminder", 0x15);
put("pai", 0x19);
put("takephoto", 0x0A);
put("stress", 0x1C);
put("female_health", 0x1D);
put("workout_status", 0x1E);
put("sleep", 0x23);
put("spo2", 0x24);
put("events", 0x26);
put("breathing", 0x33);
put("pomodoro", 0x38);
put("flashlight", 0x0102);
public static final Map<String, Integer> displayItemNameLookup = new HashMap<String, Integer>() {{
put("00000001", R.string.menuitem_personal_activity_intelligence);
put("00000002", R.string.menuitem_hr);
put("00000003", R.string.menuitem_workout);
put("00000004", R.string.menuitem_weather);
put("00000009", R.string.menuitem_alarm);
put("0000001A", R.string.menuitem_worldclock);
put("0000000B", R.string.menuitem_music);
put("0000000C", R.string.menuitem_stopwatch);
put("0000000D", R.string.menuitem_countdown);
put("0000000E", R.string.menuitem_findphone);
put("0000000F", R.string.menuitem_mutephone);
put("00000013", R.string.menuitem_settings);
put("00000014", R.string.menuitem_workout_history);
put("00000015", R.string.menuitem_eventreminder);
put("00000019", R.string.menuitem_pai);
put("0000000A", R.string.menuitem_takephoto);
put("0000001C", R.string.menuitem_stress);
put("0000001D", R.string.menuitem_female_health);
put("0000001E", R.string.menuitem_workout_status);
put("00000023", R.string.menuitem_sleep);
put("00000024", R.string.menuitem_spo2);
put("00000026", R.string.menuitem_events);
put("00000033", R.string.menuitem_breathing);
put("00000038", R.string.menuitem_pomodoro);
put("00000102", R.string.menuitem_flashlight);
}};
public static final Map<String, Integer> shortcutsIdLookup = new HashMap<String, Integer>() {{
put("hr", 0x01);
put("workout", 0x0A);
put("workout_status", 0x0C);
put("weather", 0x02);
put("worldclock", 0x1A);
put("alarm", 0x16);
put("music", 0x04);
put("activity", 0x20);
put("eventreminder", 0x21);
put("female_health", 0x11);
put("pai", 0x03);
put("stress", 0x0F);
put("sleep", 0x05);
put("spo2", 0x13);
put("events", 0x18);
put("breathing", 0x12);
public static final Map<String, Integer> shortcutsNameLookup = new HashMap<String, Integer>() {{
put("00000001", R.string.menuitem_hr);
put("0000000A", R.string.menuitem_workout);
put("0000000C", R.string.menuitem_workout_status);
put("00000002", R.string.menuitem_weather);
put("0000001A", R.string.menuitem_worldclock);
put("00000016", R.string.menuitem_alarm);
put("00000004", R.string.menuitem_music);
put("00000020", R.string.menuitem_activity);
put("00000021", R.string.menuitem_eventreminder);
put("00000011", R.string.menuitem_female_health);
put("00000003", R.string.menuitem_pai);
put("0000000F", R.string.menuitem_stress);
put("00000005", R.string.menuitem_sleep);
put("00000013", R.string.menuitem_spo2);
put("00000018", R.string.menuitem_events);
put("00000012", R.string.menuitem_breathing);
}};
}

View File

@ -103,9 +103,12 @@ import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
@ -1235,98 +1238,43 @@ public abstract class Huami2021Support extends HuamiSupport {
@Override
protected Huami2021Support setDisplayItems(final TransactionBuilder builder) {
setDisplayItems2021(builder, false, getAllDisplayItems(), getDefaultDisplayItems());
setDisplayItems2021(builder, false);
return this;
}
@Override
protected Huami2021Support setShortcuts(final TransactionBuilder builder) {
setDisplayItems2021(builder, true, getAllShortcutItems(), getDefaultShortcutItems());
setDisplayItems2021(builder, true);
return this;
}
/**
* Get the array of all possible display items.
*/
protected int getAllDisplayItems() {
return 0;
}
/**
* Get the array of default display items.
*/
protected int getDefaultDisplayItems() {
return 0;
}
/**
* Get the array of all possible shortcuts.
*/
protected int getAllShortcutItems() {
return 0;
}
/**
* Get the array of default shortcuts.
*/
protected int getDefaultShortcutItems() {
return 0;
}
private Huami2021Support setDisplayItems2021(final TransactionBuilder builder,
final boolean isShortcuts, final int allSettings, final int defaultSettings) {
if (allSettings == 0) {
LOG.warn("List of all display items is missing");
return this;
}
final SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress());
final String pages;
private void setDisplayItems2021(final TransactionBuilder builder,
final boolean isShortcuts) {
final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
final List<String> allSettings;
List<String> enabledList;
final byte menuType;
final Map<String, Integer> idLookup;
if (isShortcuts) {
menuType = Huami2021Service.DISPLAY_ITEMS_SHORTCUTS;
pages = prefs.getString(HuamiConst.PREF_SHORTCUTS_SORTABLE, null);
idLookup = Huami2021MenuType.shortcutsIdLookup;
allSettings = prefs.getList(HuamiConst.PREF_ALL_SHORTCUTS, Collections.<String>emptyList());
enabledList = prefs.getList(HuamiConst.PREF_SHORTCUTS_SORTABLE, Collections.<String>emptyList());
LOG.info("Setting shortcuts");
} else {
menuType = Huami2021Service.DISPLAY_ITEMS_MENU;
pages = prefs.getString(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE, null);
idLookup = Huami2021MenuType.displayItemIdLookup;
allSettings = prefs.getList(HuamiConst.PREF_ALL_DISPLAY_ITEMS, Collections.<String>emptyList());
enabledList = prefs.getList(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE, Collections.<String>emptyList());
LOG.info("Setting menu items");
}
final List<String> allSettingsList = new ArrayList<>(Arrays.asList(getContext().getResources().getStringArray(allSettings)));
List<String> enabledList;
if (pages != null) {
enabledList = new ArrayList<>(Arrays.asList(pages.split(",")));
} else if (defaultSettings != 0) {
enabledList = new ArrayList<>(Arrays.asList(getContext().getResources().getStringArray(defaultSettings)));
} else {
enabledList = new ArrayList<>();
if (allSettings.isEmpty()) {
LOG.warn("List of all display items is missing");
return;
}
// Remove unknown items, so that we can configure even if some are unknown
for (int i = 0; i < allSettingsList.size(); i++) {
final String key = allSettingsList.get(i);
if (!idLookup.containsKey(key) && !key.equals("more")) {
LOG.warn("Unknown display item {}, ignoring", key);
allSettingsList.remove(i--);
}
}
for (int i = 0; i < enabledList.size(); i++) {
final String key = enabledList.get(i);
if (!idLookup.containsKey(key) && !key.equals("more")) {
LOG.warn("Unknown display item {}, ignoring", key);
enabledList.remove(i--);
}
}
if (!isShortcuts && !enabledList.contains("settings")) {
if (!isShortcuts && !enabledList.contains("00000013")) {
// Settings can't be disabled
enabledList.add("settings");
enabledList.add("00000013");
}
if (isShortcuts && enabledList.size() > 10) {
@ -1337,7 +1285,7 @@ public abstract class Huami2021Support extends HuamiSupport {
LOG.info("Setting display items (shortcuts={}): {}", isShortcuts, enabledList);
int numItems = allSettingsList.size();
int numItems = allSettings.size();
if (!isShortcuts) {
// Exclude the "more" item from the main menu, since it's not a real item
numItems--;
@ -1354,19 +1302,13 @@ public abstract class Huami2021Support extends HuamiSupport {
byte pos = 0;
boolean inMoreSection = false;
for (final String key : enabledList) {
if (key.equals("more")) {
for (final String id : enabledList) {
if (id.equals("more")) {
inMoreSection = true;
pos = 0;
continue;
}
final Integer id = idLookup.get(key);
if (id == null) {
LOG.error("Invalid id {} for {}", id, key);
return this;
}
final byte sectionKey;
if (inMoreSection) {
// In more section
@ -1377,37 +1319,29 @@ public abstract class Huami2021Support extends HuamiSupport {
}
// Screen IDs are sent as literal hex strings
buf.put(String.format("%08X", id).getBytes(StandardCharsets.UTF_8));
buf.put(id.getBytes(StandardCharsets.UTF_8));
buf.put((byte) 0);
buf.put(sectionKey);
buf.put(pos++);
buf.put((byte) (key.equals("settings") ? 1 : 0));
buf.put((byte) (id.equals("00000013") ? 1 : 0));
}
// Set all disabled items
pos = 0;
for (final String key : allSettingsList) {
if (enabledList.contains(key) || key.equals("more")) {
for (final String id : allSettings) {
if (enabledList.contains(id) || id.equals("more")) {
continue;
}
final Integer id = idLookup.get(key);
if (id == null) {
LOG.error("Invalid id {} for {}", id, key);
return this;
}
// Screen IDs are sent as literal hex strings
buf.put(String.format("%08X", id).getBytes(StandardCharsets.UTF_8));
buf.put(id.getBytes(StandardCharsets.UTF_8));
buf.put((byte) 0);
buf.put(DISPLAY_ITEMS_SECTION_DISABLED);
buf.put(pos++);
buf.put((byte) (key.equals("settings") ? 1 : 0));
buf.put((byte) (id.equals("00000013") ? 1 : 0));
}
writeToChunked2021(builder, CHUNKED2021_ENDPOINT_DISPLAY_ITEMS, buf.array(), true);
return this;
}
@Override
@ -1687,7 +1621,7 @@ public abstract class Huami2021Support extends HuamiSupport {
}
@Override
protected Huami2021Support requestDisplayItems(final TransactionBuilder builder) {
public Huami2021Support requestDisplayItems(final TransactionBuilder builder) {
LOG.info("Requesting display items");
writeToChunked2021(
@ -2141,17 +2075,17 @@ public abstract class Huami2021Support extends HuamiSupport {
return;
}
final Map<Integer, String> idMap;
final String allScreensPrefKey;
final String prefKey;
switch (payload[1]) {
case DISPLAY_ITEMS_MENU:
LOG.info("Got {} display items", numberScreens);
idMap = MapUtils.reverse(Huami2021MenuType.displayItemIdLookup);
allScreensPrefKey = HuamiConst.PREF_ALL_DISPLAY_ITEMS;
prefKey = HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE;
break;
case DISPLAY_ITEMS_SHORTCUTS:
LOG.info("Got {} shortcuts", numberScreens);
idMap = MapUtils.reverse(Huami2021MenuType.shortcutsIdLookup);
allScreensPrefKey = HuamiConst.PREF_ALL_SHORTCUTS;
prefKey = HuamiConst.PREF_SHORTCUTS_SORTABLE;
break;
default:
@ -2161,15 +2095,17 @@ public abstract class Huami2021Support extends HuamiSupport {
final String[] mainScreensArr = new String[numberScreens];
final String[] moreScreensArr = new String[numberScreens];
final List<String> allScreens = new LinkedList<>();
if (payload[1] == DISPLAY_ITEMS_MENU) {
// The band doesn't report the "more" screen, so we add it
allScreens.add("more");
}
for (int i = 0; i < numberScreens; i++) {
// Screen IDs are sent as literal hex strings
final Integer screenId = Integer.parseInt(new String(subarray(payload, 4 + i * 12, 4 + i * 12 + 8)), 16);
final String screenKey = idMap.get(screenId);
if (screenKey == null) {
LOG.warn("Unknown screen {}, ignoring", String.format("0x%08X", screenId));
continue;
}
final String screenId = new String(subarray(payload, 4 + i * 12, 4 + i * 12 + 8));
allScreens.add(screenId);
final int screenSectionVal = payload[4 + i * 12 + 9];
final int screenPosition = payload[4 + i * 12 + 10];
@ -2185,14 +2121,14 @@ public abstract class Huami2021Support extends HuamiSupport {
LOG.warn("Duplicate position {} for main section", screenPosition);
}
//LOG.debug("mainScreensArr[{}] = {}", screenPosition, screenKey);
mainScreensArr[screenPosition] = screenKey;
mainScreensArr[screenPosition] = screenId;
break;
case DISPLAY_ITEMS_SECTION_MORE:
if (moreScreensArr[screenPosition] != null) {
LOG.warn("Duplicate position {} for more section", screenPosition);
}
//LOG.debug("moreScreensArr[{}] = {}", screenPosition, screenKey);
moreScreensArr[screenPosition] = screenKey;
moreScreensArr[screenPosition] = screenId;
break;
case DISPLAY_ITEMS_SECTION_DISABLED:
// Ignore disabled screens
@ -2210,8 +2146,11 @@ public abstract class Huami2021Support extends HuamiSupport {
}
screens.removeAll(Collections.singleton(null));
final String allScrensPrefValue = StringUtils.join(",", allScreens.toArray(new String[0])).toString();
final String prefValue = StringUtils.join(",", screens.toArray(new String[0])).toString();
final GBDeviceEventUpdatePreferences eventUpdatePreferences = new GBDeviceEventUpdatePreferences(prefKey, prefValue);
final GBDeviceEventUpdatePreferences eventUpdatePreferences = new GBDeviceEventUpdatePreferences()
.withPreference(allScreensPrefKey, allScrensPrefValue)
.withPreference(prefKey, prefValue);
evaluateGBDeviceEvent(eventUpdatePreferences);
}

View File

@ -29,6 +29,7 @@ public enum HuamiFirmwareType {
AGPS_UIHH((byte) -4),
GPS_ALMANAC((byte) 5),
WATCHFACE((byte) 8),
APP((byte) 8),
FONT_LATIN((byte) 11),
INVALID(Byte.MIN_VALUE);

View File

@ -3973,7 +3973,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements
return this;
}
protected HuamiSupport requestDisplayItems(TransactionBuilder builder) {
public HuamiSupport requestDisplayItems(TransactionBuilder builder) {
LOG.warn("Function not implemented");
return this;
}

View File

@ -36,24 +36,4 @@ public class AmazfitGTS3Support extends Huami2021Support {
public HuamiFWHelper createFWHelper(Uri uri, Context context) throws IOException {
return new AmazfitGTS3FWHelper(uri, context);
}
@Override
protected int getAllDisplayItems() {
return R.array.pref_miband7_display_items_values;
}
@Override
protected int getDefaultDisplayItems() {
return R.array.pref_miband7_display_items_default;
}
@Override
protected int getAllShortcutItems() {
return R.array.pref_miband7_shortcuts_values;
}
@Override
protected int getDefaultShortcutItems() {
return R.array.pref_miband7_shortcuts_default;
}
}

View File

@ -36,24 +36,4 @@ public class MiBand7Support extends Huami2021Support {
public HuamiFWHelper createFWHelper(Uri uri, Context context) throws IOException {
return new MiBand7FWHelper(uri, context);
}
@Override
protected int getAllDisplayItems() {
return R.array.pref_miband7_display_items_values;
}
@Override
protected int getDefaultDisplayItems() {
return R.array.pref_miband7_display_items_default;
}
@Override
protected int getAllShortcutItems() {
return R.array.pref_miband7_shortcuts_values;
}
@Override
protected int getDefaultShortcutItems() {
return R.array.pref_miband7_shortcuts_default;
}
}

View File

@ -21,9 +21,13 @@ import android.net.Uri;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiFirmwareType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport;
import nodomain.freeyourgadget.gadgetbridge.util.ArrayUtils;
public class UpdateFirmwareOperation2021 extends UpdateFirmwareOperation2020 {
private static final Logger LOG = LoggerFactory.getLogger(UpdateFirmwareOperation2021.class);
@ -37,4 +41,22 @@ public class UpdateFirmwareOperation2021 extends UpdateFirmwareOperation2020 {
// Disable 2021 chunked reads, otherwise firmware upgrades get interrupted
builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_CHUNKEDTRANSFER_2021_READ), enable);
}
@Override
protected void handleNotificationNotif(byte[] value) {
super.handleNotificationNotif(value);
if (ArrayUtils.startsWith(value, new byte[]{HuamiService.RESPONSE, COMMAND_FINALIZE_UPDATE, HuamiService.SUCCESS})) {
if (getFirmwareInfo().getFirmwareType() == HuamiFirmwareType.APP) {
// After an app is installed, request the display items from the band (new app will be at the end)
try {
TransactionBuilder builder = performInitialized("request display items");
getSupport().requestDisplayItems(builder);
builder.queue(getQueue());
} catch (final IOException e) {
LOG.error("Failed to request display items after app install", e);
}
}
}
}
}

View File

@ -19,7 +19,9 @@ package nodomain.freeyourgadget.gadgetbridge.util;
import android.content.SharedPreferences;
import android.util.Log;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
@ -152,6 +154,21 @@ public class Prefs {
}
}
/**
* Returns the preference saved under the given key as a list of strings.
* The preference is assumed to be a string, with each value separated by a comma.
* @param key the preference key
* @param defaultValue the default value to return if the preference value is unset
* @return the saved preference value or the given defaultValue
*/
public List<String> getList(final String key, final List<String> defaultValue) {
final String stringValue = preferences.getString(key, null);
if (stringValue == null) {
return defaultValue;
}
return Arrays.asList(stringValue.split(","));
}
private void logReadError(String key, Exception ex) {
Log.e(TAG, "Error reading preference value: " + key + "; returning default value", ex); // log the first exception
}

View File

@ -624,134 +624,12 @@
<item>@string/p_menuitem_music</item>
</string-array>
<string-array name="pref_miband7_display_items">
<item>@string/menuitem_personal_activity_intelligence</item>
<item>@string/menuitem_hr</item>
<item>@string/menuitem_workout</item>
<item>@string/menuitem_weather</item>
<item>@string/menuitem_alarm</item>
<item>@string/menuitem_music</item>
<item>@string/menuitem_stopwatch</item>
<item>@string/menuitem_countdown</item>
<item>@string/menuitem_findphone</item>
<item>@string/menuitem_mutephone</item>
<item>@string/menuitem_settings</item>
<item>@string/menuitem_more</item>
<item>@string/menuitem_workout_history</item>
<item>@string/menuitem_eventreminder</item>
<item>@string/menuitem_pai</item>
<item>@string/menuitem_stress</item>
<item>@string/menuitem_female_health</item>
<item>@string/menuitem_workout_status</item>
<item>@string/menuitem_sleep</item>
<item>@string/menuitem_spo2</item>
<item>@string/menuitem_events</item>
<item>@string/menuitem_breathing</item>
<item>@string/menuitem_pomodoro</item>
<item>@string/menuitem_flashlight</item>
<item>@string/menuitem_takephoto</item>
<item>@string/menuitem_worldclock</item>
<string-array name="pref_huami2021_display_items">
<!-- empty array, will be requested from band -->
</string-array>
<string-array name="pref_miband7_display_items_values">
<item>@string/p_menuitem_personal_activity_intelligence</item>
<item>@string/p_menuitem_hr</item>
<item>@string/p_menuitem_workout</item>
<item>@string/p_menuitem_weather</item>
<item>@string/p_menuitem_alarm</item>
<item>@string/p_menuitem_music</item>
<item>@string/p_menuitem_stopwatch</item>
<item>@string/p_menuitem_countdown</item>
<item>@string/p_menuitem_findphone</item>
<item>@string/p_menuitem_mutephone</item>
<item>@string/p_menuitem_settings</item>
<item>@string/p_menuitem_more</item>
<item>@string/p_menuitem_workout_history</item>
<item>@string/p_menuitem_eventreminder</item>
<item>@string/p_menuitem_pai</item>
<item>@string/p_menuitem_stress</item>
<item>@string/p_menuitem_female_health</item>
<item>@string/p_menuitem_workout_status</item>
<item>@string/p_menuitem_sleep</item>
<item>@string/p_menuitem_spo2</item>
<item>@string/p_menuitem_events</item>
<item>@string/p_menuitem_breathing</item>
<item>@string/p_menuitem_pomodoro</item>
<item>@string/p_menuitem_flashlight</item>
<item>@string/p_menuitem_takephoto</item>
<item>@string/p_menuitem_worldclock</item>
</string-array>
<string-array name="pref_miband7_display_items_default">
<item>@string/p_menuitem_workout</item>
<item>@string/p_menuitem_alarm</item>
<item>@string/p_menuitem_weather</item>
<item>@string/p_menuitem_stopwatch</item>
<item>@string/p_menuitem_countdown</item>
<item>@string/p_menuitem_events</item>
<item>@string/p_menuitem_eventreminder</item>
<item>@string/p_menuitem_findphone</item>
<item>@string/p_menuitem_mutephone</item>
<item>@string/p_menuitem_flashlight</item>
<item>@string/p_menuitem_more</item>
<item>@string/p_menuitem_hr</item>
<item>@string/p_menuitem_spo2</item>
<item>@string/p_menuitem_sleep</item>
<item>@string/p_menuitem_stress</item>
<item>@string/p_menuitem_workout_status</item>
<item>@string/p_menuitem_workout_history</item>
<item>@string/p_menuitem_pai</item>
<item>@string/p_menuitem_personal_activity_intelligence</item>
<item>@string/p_menuitem_female_health</item>
<item>@string/p_menuitem_breathing</item>
<item>@string/p_menuitem_pomodoro</item>
<item>@string/p_menuitem_music</item>
<item>@string/p_menuitem_worldclock</item>
<item>@string/p_menuitem_takephoto</item>
<item>@string/p_menuitem_settings</item>
</string-array>
<string-array name="pref_miband7_shortcuts">
<item>@string/menuitem_hr</item>
<item>@string/menuitem_workout</item>
<item>@string/menuitem_workout_status</item>
<item>@string/menuitem_weather</item>
<item>@string/menuitem_alarm</item>
<item>@string/menuitem_music</item>
<item>@string/menuitem_activity</item>
<item>@string/menuitem_eventreminder</item>
<item>@string/menuitem_female_health</item>
<item>@string/menuitem_pai</item>
<item>@string/menuitem_stress</item>
<item>@string/menuitem_sleep</item>
<item>@string/menuitem_spo2</item>
<item>@string/menuitem_events</item>
<item>@string/menuitem_breathing</item>
<item>@string/menuitem_worldclock</item>
</string-array>
<string-array name="pref_miband7_shortcuts_values">
<item>@string/p_menuitem_hr</item>
<item>@string/p_menuitem_workout</item>
<item>@string/p_menuitem_workout_status</item>
<item>@string/p_menuitem_weather</item>
<item>@string/p_menuitem_alarm</item>
<item>@string/p_menuitem_music</item>
<item>@string/p_menuitem_activity</item>
<item>@string/p_menuitem_eventreminder</item>
<item>@string/p_menuitem_female_health</item>
<item>@string/p_menuitem_pai</item>
<item>@string/p_menuitem_stress</item>
<item>@string/p_menuitem_sleep</item>
<item>@string/p_menuitem_spo2</item>
<item>@string/p_menuitem_events</item>
<item>@string/p_menuitem_breathing</item>
<item>@string/p_menuitem_worldclock</item>
</string-array>
<string-array name="pref_miband7_shortcuts_default">
<item>@string/p_menuitem_weather</item>
<item>@string/p_menuitem_music</item>
<string-array name="pref_huami2021_shortcuts">
<!-- empty array, will be requested from band -->
</string-array>
<string-array name="pref_miband5_workout_activity_types">

View File

@ -1049,6 +1049,7 @@
<string name="kind_agps_bundle">AGPS Bundle</string>
<string name="kind_resources">Resources</string>
<string name="kind_watchface">Watchface</string>
<string name="kind_app">App</string>
<string name="devicetype_unknown">Unknown Device</string>
<string name="devicetype_test">Test Device</string>
<string name="add_test_device">Add test device</string>
@ -1178,6 +1179,7 @@
<string name='menuitem_workout_history'>Workout History</string>
<string name='menuitem_female_health'>Female Health</string>
<string name='menuitem_workout_status'>Workout Status</string>
<string name="menuitem_unknown_app">Unknown (%s)</string>
<string name="watch9_time_minutes">Minutes:</string>
<string name="watch9_time_hours">Hours:</string>
<string name="watch9_time_seconds">Seconds:</string>

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<com.mobeta.android.dslv.DragSortListPreference
android:defaultValue="@array/pref_miband7_display_items_default"
android:defaultValue="@array/pref_huami2021_display_items"
android:dialogTitle="@string/mi2_prefs_display_items"
android:entries="@array/pref_miband7_display_items"
android:entryValues="@array/pref_miband7_display_items_values"
android:entries="@array/pref_huami2021_display_items"
android:entryValues="@array/pref_huami2021_display_items"
android:icon="@drawable/ic_widgets"
android:key="display_items_sortable"
android:persistent="true"

View File

@ -2,10 +2,10 @@
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<com.mobeta.android.dslv.DragSortListPreference
android:icon="@drawable/ic_shortcut"
android:defaultValue="@array/pref_miband7_shortcuts_default"
android:defaultValue="@array/pref_huami2021_shortcuts"
android:dialogTitle="@string/bip_prefs_shortcuts"
android:entries="@array/pref_miband7_shortcuts"
android:entryValues="@array/pref_miband7_shortcuts_values"
android:entries="@array/pref_huami2021_shortcuts"
android:entryValues="@array/pref_huami2021_shortcuts"
android:key="shortcuts_sortable"
android:persistent="true"
android:summary="@string/bip_prefs_shotcuts_summary"

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<com.mobeta.android.dslv.DragSortListPreference
android:defaultValue="@array/pref_miband7_display_items_default"
android:dialogTitle="@string/mi2_prefs_display_items"
android:entries="@array/pref_miband7_display_items"
android:entryValues="@array/pref_miband7_display_items_values"
android:icon="@drawable/ic_widgets"
android:key="display_items_sortable"
android:persistent="true"
android:summary="@string/mi2_prefs_display_items_summary"
android:title="@string/mi2_prefs_display_items" />
</androidx.preference.PreferenceScreen>

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<com.mobeta.android.dslv.DragSortListPreference
android:icon="@drawable/ic_shortcut"
android:defaultValue="@array/pref_miband7_shortcuts_default"
android:dialogTitle="@string/bip_prefs_shortcuts"
android:entries="@array/pref_miband7_shortcuts"
android:entryValues="@array/pref_miband7_shortcuts_values"
android:key="shortcuts_sortable"
android:persistent="true"
android:summary="@string/bip_prefs_shotcuts_summary"
android:title="@string/bip_prefs_shortcuts" />
</androidx.preference.PreferenceScreen>