1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-09-01 03:55:47 +02:00

Add support for Mi Smart Scale 2

This commit is contained in:
Severin von Wnuck-Lipinski 2024-08-12 20:36:55 +02:00 committed by José Rebelo
parent 3be6ec0007
commit ef1d7171e8
9 changed files with 529 additions and 0 deletions

View File

@ -449,6 +449,9 @@ public class DeviceSettingsPreferenceConst {
public static final String PREF_MOONDROP_TOUCH_ANC_MODE_EARBUD = "pref_moondrop_touch_anc_mode_earbud"; public static final String PREF_MOONDROP_TOUCH_ANC_MODE_EARBUD = "pref_moondrop_touch_anc_mode_earbud";
public static final String PREF_MOONDROP_TOUCH_ANC_MODE_TRIGGER = "pref_moondrop_touch_anc_mode_trigger"; public static final String PREF_MOONDROP_TOUCH_ANC_MODE_TRIGGER = "pref_moondrop_touch_anc_mode_trigger";
public static final String PREF_MISCALE_WEIGHT_UNIT = "pref_miscale_weight_unit";
public static final String PREF_MISCALE_SMALL_OBJECTS = "pref_miscale_small_objects";
public static final String PREF_QC35_NOISE_CANCELLING_LEVEL = "qc35_noise_cancelling_level"; public static final String PREF_QC35_NOISE_CANCELLING_LEVEL = "qc35_noise_cancelling_level";
public static final String PREFS_ACTIVITY_IN_DEVICE_CARD = "prefs_activity_in_device_card"; public static final String PREFS_ACTIVITY_IN_DEVICE_CARD = "prefs_activity_in_device_card";

View File

@ -757,6 +757,9 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
addPreferenceHandlerFor(PREF_MOONDROP_TOUCH_ANC_MODE_EARBUD); addPreferenceHandlerFor(PREF_MOONDROP_TOUCH_ANC_MODE_EARBUD);
addPreferenceHandlerFor(PREF_MOONDROP_TOUCH_ANC_MODE_TRIGGER); addPreferenceHandlerFor(PREF_MOONDROP_TOUCH_ANC_MODE_TRIGGER);
addPreferenceHandlerFor(PREF_MISCALE_WEIGHT_UNIT);
addPreferenceHandlerFor(PREF_MISCALE_SMALL_OBJECTS);
addPreferenceHandlerFor(PREF_FEMOMETER_MEASUREMENT_MODE); addPreferenceHandlerFor(PREF_FEMOMETER_MEASUREMENT_MODE);
addPreferenceHandlerFor(PREF_QC35_NOISE_CANCELLING_LEVEL); addPreferenceHandlerFor(PREF_QC35_NOISE_CANCELLING_LEVEL);

View File

@ -0,0 +1,130 @@
/* Copyright (C) 2024 Severin von Wnuck-Lipinski
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 <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.miscale;
import androidx.annotation.NonNull;
import java.util.regex.Pattern;
import de.greenrobot.dao.query.QueryBuilder;
import nodomain.freeyourgadget.gadgetbridge.GBException;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.entities.MiScaleWeightSampleDao;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.WeightSample;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.miscale.MiSmartScaleDeviceSupport;
public class MiSmartScaleCoordinator extends AbstractBLEDeviceCoordinator {
@Override
public String getManufacturer() {
return "Huami";
}
@Override
protected Pattern getSupportedDeviceName() {
return Pattern.compile("MI SCALE2");
}
@Override
public int getDeviceNameResource() {
return R.string.devicetype_mismartscale;
}
@Override
public int getDefaultIconResource() {
return R.drawable.ic_device_miscale;
}
@Override
public int getDisabledIconResource() {
return R.drawable.ic_device_miscale_disabled;
}
@Override
public int getBatteryCount() {
return 0;
}
@Override
public int getBondingStyle() {
return BONDING_STYLE_NONE;
}
@Override
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
Long deviceId = device.getId();
QueryBuilder<?> qb = session.getMiScaleWeightSampleDao().queryBuilder();
qb.where(MiScaleWeightSampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
}
@Override
public DeviceSpecificSettings getDeviceSpecificSettings(final GBDevice device) {
final DeviceSpecificSettings settings = new DeviceSpecificSettings();
settings.addRootScreen(R.xml.devicesettings_mismartscale);
return settings;
}
@Override
public TimeSampleProvider<? extends WeightSample> getWeightSampleProvider(GBDevice device, DaoSession session) {
return new MiScaleSampleProvider(device, session);
}
@Override
public boolean supportsWeightMeasurement() {
return true;
}
@Override
public boolean supportsActivityTracking() {
return true;
}
@Override
public boolean supportsActivityTabs() {
return false;
}
@Override
public boolean supportsSleepMeasurement() {
return false;
}
@Override
public boolean supportsStepCounter() {
return false;
}
@Override
public boolean supportsSpeedzones() {
return false;
}
@NonNull
@Override
public Class<? extends DeviceSupport> getDeviceSupportClass() {
return MiSmartScaleDeviceSupport.class;
}
}

View File

@ -188,6 +188,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.mijia_lywsd.MijiaLywsd02Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.mijia_lywsd.MijiaLywsd02Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.mijia_lywsd.MijiaLywsd03Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.mijia_lywsd.MijiaLywsd03Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.mijia_lywsd.MijiaMhoC303Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.mijia_lywsd.MijiaMhoC303Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.miscale.MiSmartScaleCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.miscale.MiCompositionScaleCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.miscale.MiCompositionScaleCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.moondrop.MoondropSpaceTravelCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.moondrop.MoondropSpaceTravelCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.no1f1.No1F1Coordinator; import nodomain.freeyourgadget.gadgetbridge.devices.no1f1.No1F1Coordinator;
@ -355,6 +356,7 @@ public enum DeviceType {
CASIOGBX100(CasioGBX100DeviceCoordinator.class), CASIOGBX100(CasioGBX100DeviceCoordinator.class),
CASIOGWB5600(CasioGWB5600DeviceCoordinator.class), CASIOGWB5600(CasioGWB5600DeviceCoordinator.class),
CASIOGMWB5000(CasioGMWB5000DeviceCoordinator.class), CASIOGMWB5000(CasioGMWB5000DeviceCoordinator.class),
MISMARTSCALE(MiSmartScaleCoordinator.class),
MICOMPOSITIONSCALE(MiCompositionScaleCoordinator.class), MICOMPOSITIONSCALE(MiCompositionScaleCoordinator.class),
BFH16(BFH16DeviceCoordinator.class), BFH16(BFH16DeviceCoordinator.class),
MAKIBESHR3(MakibesHR3Coordinator.class), MAKIBESHR3(MakibesHR3Coordinator.class),

View File

@ -0,0 +1,266 @@
/* Copyright (C) 2024 Severin von Wnuck-Lipinski
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 <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.miscale;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.SharedPreferences;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService;
import nodomain.freeyourgadget.gadgetbridge.devices.miscale.MiScaleSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.MiScaleWeightSample;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfo;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfoProfile;
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.*;
public class MiSmartScaleDeviceSupport extends AbstractBTLEDeviceSupport {
private static final Logger LOG = LoggerFactory.getLogger(MiSmartScaleDeviceSupport.class);
private static final UUID UUID_CHARACTERISTIC_CONFIG = UUID.fromString("00001542-0000-3512-2118-0009af100700");
private static final UUID UUID_CHARACTERISTIC_WEIGHT_HISTORY = UUID.fromString("00002a2f-0000-3512-2118-0009af100700");
// There's unfortunately no way to query the config options, they can only be set
private static final byte CFG_WEIGHT_UNIT = (byte)0x04;
private static final byte CFG_SMALL_OBJECTS = (byte)0x10;
private static final byte CFG_RESET_HISTORY = (byte)0x12;
private static final byte CMD_HISTORY_START = (byte)0x01;
private static final byte CMD_HISTORY_QUERY = (byte)0x02;
private static final byte CMD_HISTORY_COMPLETE = (byte)0x03;
private static final byte CMD_HISTORY_END = (byte)0x04;
// Threshold for small objects
private static final int SMALL_OBJECT_MAX_WEIGHT = 10;
private long userId = -1;
private final DeviceInfoProfile<MiSmartScaleDeviceSupport> deviceInfoProfile;
public MiSmartScaleDeviceSupport() {
super(LOG);
// Get unique user ID for weight history querying
try (DBHandler db = GBApplication.acquireDB()) {
userId = DBHelper.getUser(db.getDaoSession()).getId();
} catch (Exception e) {
LOG.error("Error acquiring database", e);
}
deviceInfoProfile = new DeviceInfoProfile<>(this);
deviceInfoProfile.addListener(intent -> {
if (!DeviceInfoProfile.ACTION_DEVICE_INFO.equals(intent.getAction()))
return;
DeviceInfo info = intent.getParcelableExtra(DeviceInfoProfile.EXTRA_DEVICE_INFO);
if (info == null)
return;
GBDeviceEventVersionInfo event = new GBDeviceEventVersionInfo();
event.fwVersion = info.getSoftwareRevision();
event.hwVersion = info.getHardwareRevision();
handleGBDeviceEvent(event);
});
addSupportedService(GattService.UUID_SERVICE_GENERIC_ACCESS);
addSupportedService(GattService.UUID_SERVICE_GENERIC_ATTRIBUTE);
addSupportedService(GattService.UUID_SERVICE_DEVICE_INFORMATION);
addSupportedService(GattService.UUID_SERVICE_WEIGHT_SCALE);
addSupportedService(UUID.fromString(MiBandService.UUID_SERVICE_WEIGHT_SERVICE));
addSupportedProfile(deviceInfoProfile);
}
@Override
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
deviceInfoProfile.requestDeviceInfo(builder);
if (GBApplication.getPrefs().getBoolean("datetime_synconconnect", true))
setTime(builder);
builder.notify(getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_WEIGHT_MEASUREMENT), true);
builder.notify(getCharacteristic(UUID_CHARACTERISTIC_WEIGHT_HISTORY), true);
// Query weight measurements saved by the scale
sendHistoryCommand(builder, CMD_HISTORY_START, true);
sendHistoryCommand(builder, CMD_HISTORY_QUERY, false);
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()));
return builder;
}
@Override
public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
if (super.onCharacteristicChanged(gatt, characteristic))
return true;
UUID uuid = characteristic.getUuid();
if (!uuid.equals(GattCharacteristic.UUID_CHARACTERISTIC_WEIGHT_MEASUREMENT) &&
!uuid.equals(UUID_CHARACTERISTIC_WEIGHT_HISTORY))
return false;
byte[] data = characteristic.getValue();
if (data.length == 1 && data[0] == CMD_HISTORY_COMPLETE) {
TransactionBuilder builder = createTransactionBuilder("ack");
// Acknowledge weight history reception
sendHistoryCommand(builder, CMD_HISTORY_COMPLETE, false);
sendHistoryCommand(builder, CMD_HISTORY_END, true);
builder.notify(getCharacteristic(UUID_CHARACTERISTIC_WEIGHT_HISTORY), false);
builder.queue(getQueue());
} else {
ByteBuffer buf = ByteBuffer.wrap(characteristic.getValue());
List<WeightMeasurement> measurements = new ArrayList<>();
WeightMeasurement measurement = WeightMeasurement.decode(buf);
// Weight history characteristic often has two measurements in one packet
while (measurement != null) {
measurements.add(measurement);
measurement = WeightMeasurement.decode(buf);
}
saveMeasurements(measurements);
}
return true;
}
@Override
public void onReset(int flags) {
if ((flags & GBDeviceProtocol.RESET_FLAGS_FACTORY_RESET) == 0)
return;
try {
TransactionBuilder builder = performInitialized("reset");
setConfigValue(builder, CFG_RESET_HISTORY, (byte)0x00);
builder.queue(getQueue());
} catch (IOException e) {
LOG.error("Error", e);
}
}
@Override
public void onSendConfiguration(String config) {
SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress());
try {
TransactionBuilder builder = performInitialized("config");
if (config.equals(PREF_MISCALE_WEIGHT_UNIT)) {
int unit = Integer.parseInt(prefs.getString(PREF_MISCALE_WEIGHT_UNIT, "0"));
setConfigValue(builder, CFG_WEIGHT_UNIT, (byte)unit);
} else if (config.equals(PREF_MISCALE_SMALL_OBJECTS)) {
boolean enabled = prefs.getBoolean(PREF_MISCALE_SMALL_OBJECTS, false);
setConfigValue(builder, CFG_SMALL_OBJECTS, enabled ? (byte)0x01: (byte)0x00);
}
builder.queue(getQueue());
} catch (IOException e) {
LOG.error("Error", e);
}
}
@Override
public boolean useAutoConnect() {
return false;
}
private void setTime(TransactionBuilder builder) {
GregorianCalendar now = BLETypeConversions.createCalendar();
byte[] time = BLETypeConversions.calendarToCurrentTime(now, 0);
builder.write(getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_CURRENT_TIME), time);
}
private void setConfigValue(TransactionBuilder builder, byte config, byte value) {
byte[] data = new byte[] { (byte)0x06, config, (byte)0x00, value };
builder.write(getCharacteristic(UUID_CHARACTERISTIC_CONFIG), data);
}
private void sendHistoryCommand(TransactionBuilder builder, byte cmd, boolean includeUserId) {
ByteBuffer buf = ByteBuffer.allocate(includeUserId ? 5 : 1);
buf.put(cmd);
// The user ID is directly related to the account ID in the Zepp Life app
if (includeUserId)
buf.putInt((int)userId);
builder.write(getCharacteristic(UUID_CHARACTERISTIC_WEIGHT_HISTORY), buf.array());
}
private void saveMeasurements(List<WeightMeasurement> measurements) {
SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress());
boolean allowSmallObjects = prefs.getBoolean(PREF_MISCALE_SMALL_OBJECTS, false);
try (DBHandler db = GBApplication.acquireDB()) {
MiScaleSampleProvider provider = new MiScaleSampleProvider(getDevice(), db.getDaoSession());
List<MiScaleWeightSample> samples = new ArrayList<>();
Long userId = DBHelper.getUser(db.getDaoSession()).getId();
Long deviceId = DBHelper.getDevice(getDevice(), db.getDaoSession()).getId();
for (WeightMeasurement measurement : measurements) {
// Skip measurements of small objects if not allowed
if (!allowSmallObjects && measurement.getWeightKg() < SMALL_OBJECT_MAX_WEIGHT)
continue;
samples.add(new MiScaleWeightSample(
measurement.getTimestamp().getTime(),
deviceId,
userId,
measurement.getWeightKg()
));
}
provider.addSamples(samples);
} catch (Exception e) {
LOG.error("Error acquiring database", e);
}
}
}

View File

@ -0,0 +1,87 @@
/* Copyright (C) 2024 Severin von Wnuck-Lipinski
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 <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.miscale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Calendar;
import java.util.Date;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
public class WeightMeasurement {
private static final Logger LOG = LoggerFactory.getLogger(WeightMeasurement.class);
private Date timestamp;
private float weightKg;
public Date getTimestamp() {
return timestamp;
}
public float getWeightKg() {
return weightKg;
}
private WeightMeasurement(Date timestamp, float weightKg) {
LOG.debug("Measurement: timestamp={}, weightKg={}", timestamp, String.format("%.2f", weightKg));
this.timestamp = timestamp;
this.weightKg = weightKg;
}
public static WeightMeasurement decode(ByteBuffer buf) {
if (buf.remaining() < 10)
return null;
buf.order(ByteOrder.LITTLE_ENDIAN);
byte flags = buf.get();
boolean stabilized = testBit(flags, 5) && !testBit(flags, 7);
// Only decode measurement once weight reading has stabilized
if (!stabilized)
return null;
float weightKg = weightToKg(buf.getShort(), flags);
byte[] timestamp = new byte[7];
buf.get(timestamp);
Calendar calendar = BLETypeConversions.rawBytesToCalendar(timestamp);
return new WeightMeasurement(calendar.getTime(), weightKg);
}
private static float weightToKg(float weight, byte flags) {
boolean isLbs = testBit(flags, 0);
boolean isJin = testBit(flags, 4);
if (isLbs)
return (weight / 100) * 0.45359237f;
else if (isJin)
return (weight / 100) * 0.5f;
return weight / 200;
}
private static boolean testBit(byte value, int offset) {
return ((value >> offset) & 1) == 1;
}
}

View File

@ -3722,6 +3722,18 @@
<item>5</item> <item>5</item>
</string-array> </string-array>
<string-array name="miscale_weight_unit_names">
<item>@string/miscale_weight_unit_metric</item>
<item>@string/miscale_weight_unit_imperial</item>
<item>@string/miscale_weight_unit_chinese</item>
</string-array>
<string-array name="miscale_weight_unit_values">
<item>0</item>
<item>1</item>
<item>2</item>
</string-array>
<string-array name="fitness_tracking_apps_package_names"> <string-array name="fitness_tracking_apps_package_names">
<item>de.dennisguse.opentracks</item> <item>de.dennisguse.opentracks</item>
<item>de.dennisguse.opentracks.playStore</item> <item>de.dennisguse.opentracks.playStore</item>

View File

@ -1720,6 +1720,7 @@
<string name="devicetype_casiogbx100">Casio GBX-100</string> <string name="devicetype_casiogbx100">Casio GBX-100</string>
<string name="devicetype_casiogwb5600">Casio GW-B5600</string> <string name="devicetype_casiogwb5600">Casio GW-B5600</string>
<string name="devicetype_casiogmwb5000">Casio GMW-B5000</string> <string name="devicetype_casiogmwb5000">Casio GMW-B5000</string>
<string name="devicetype_mismartscale">Mi Smart Scale 2</string>
<string name="devicetype_micompositionscale">Mi Body Composition Scale 2</string> <string name="devicetype_micompositionscale">Mi Body Composition Scale 2</string>
<string name="devicetype_itag">iTag</string> <string name="devicetype_itag">iTag</string>
<string name="devicetype_bfh16">BFH-16</string> <string name="devicetype_bfh16">BFH-16</string>
@ -2606,6 +2607,13 @@
<string name="soundcore_equalizer_band9">Band 9</string> <string name="soundcore_equalizer_band9">Band 9</string>
<string name="soundcore_equalizer_frequency">Frequency</string> <string name="soundcore_equalizer_frequency">Frequency</string>
<string name="soundcore_equalizer_value">Value</string> <string name="soundcore_equalizer_value">Value</string>
<string name="miscale_weight_unit_title">Weight Unit</string>
<string name="miscale_weight_unit_summary">Set unit of weight for displayed measurements</string>
<string name="miscale_weight_unit_metric">Metric (kg)</string>
<string name="miscale_weight_unit_imperial">Imperial (lbs)</string>
<string name="miscale_weight_unit_chinese">Chinese (jin)</string>
<string name="miscale_small_objects_title">Small Objects</string>
<string name="miscale_small_objects_summary">Store weight of objects lighter than 10 kg</string>
<string name="protocol_version">Protocol Version</string> <string name="protocol_version">Protocol Version</string>
<string name="pref_screen_auto_brightness_title">Auto Brightness</string> <string name="pref_screen_auto_brightness_title">Auto Brightness</string>
<string name="pref_screen_auto_brightness_summary">Adjust screen brightness according to ambient light</string> <string name="pref_screen_auto_brightness_summary">Adjust screen brightness according to ambient light</string>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<ListPreference
android:defaultValue="0"
android:entries="@array/miscale_weight_unit_names"
android:entryValues="@array/miscale_weight_unit_values"
android:icon="@drawable/ic_calculate"
android:key="pref_miscale_weight_unit"
android:title="@string/miscale_weight_unit_title"
android:summary="@string/miscale_weight_unit_summary" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:icon="@drawable/ic_pressure"
android:key="pref_miscale_small_objects"
android:layout="@layout/preference_checkbox"
android:title="@string/miscale_small_objects_title"
android:summary="@string/miscale_small_objects_summary" />
</androidx.preference.PreferenceScreen>