mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Zepp OS: Add HRV support
Support is determined by whether the display item hrv exists
This commit is contained in:
+1
-1
@@ -122,7 +122,7 @@ public class ActivityChartsActivity extends AbstractChartsActivity {
|
||||
if (!coordinator.supportsWeightMeasurement()) {
|
||||
tabList.remove("weight");
|
||||
}
|
||||
if (!coordinator.supportsHrvMeasurement()) {
|
||||
if (!coordinator.supportsHrvMeasurement(device)) {
|
||||
tabList.remove("hrvstatus");
|
||||
}
|
||||
if (!coordinator.supportsHeartRateMeasurement(device)) {
|
||||
|
||||
+9
-1
@@ -169,7 +169,7 @@ public class HRVStatusFragment extends AbstractChartFragment<HRVStatusFragment.H
|
||||
List<Entry> lineEntries = new ArrayList<>();
|
||||
final List<ILineDataSet> lineDataSets = new ArrayList<>();
|
||||
weeklyData.getDaysData().forEach((HRVStatusDayData day) -> {
|
||||
if (day.status.getNum() > 0) {
|
||||
if (day.dayAvg > 0) {
|
||||
lineEntries.add(new Entry(day.i, day.dayAvg));
|
||||
} else {
|
||||
if (!lineEntries.isEmpty()) {
|
||||
@@ -297,12 +297,20 @@ public class HRVStatusFragment extends AbstractChartFragment<HRVStatusFragment.H
|
||||
private List<? extends HrvSummarySample> getSamples(final DBHandler db, final GBDevice device, int tsFrom, int tsTo) {
|
||||
final DeviceCoordinator coordinator = device.getDeviceCoordinator();
|
||||
final TimeSampleProvider<? extends HrvSummarySample> sampleProvider = coordinator.getHrvSummarySampleProvider(device, db.getDaoSession());
|
||||
if (sampleProvider == null) {
|
||||
LOG.warn("Device {} does not implement HrvSummarySampleProvider", device);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return sampleProvider.getAllSamples(tsFrom * 1000L, tsTo * 1000L);
|
||||
}
|
||||
|
||||
public List<? extends HrvValueSample> getHrvValueSamples(final DBHandler db, final GBDevice device, int tsFrom, int tsTo) {
|
||||
final DeviceCoordinator coordinator = device.getDeviceCoordinator();
|
||||
final TimeSampleProvider<? extends HrvValueSample> sampleProvider = coordinator.getHrvValueSampleProvider(device, db.getDaoSession());
|
||||
if (sampleProvider == null) {
|
||||
LOG.warn("Device {} does not implement HrvValueSampleProvider", device);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return sampleProvider.getAllSamples(tsFrom * 1000L, tsTo * 1000L);
|
||||
}
|
||||
|
||||
|
||||
+14
-4
@@ -30,6 +30,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.DashboardFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample;
|
||||
|
||||
@@ -50,7 +51,7 @@ public class DashboardHrvWidget extends AbstractGaugeWidget {
|
||||
|
||||
@Override
|
||||
protected boolean isSupportedBy(final GBDevice device) {
|
||||
return device.getDeviceCoordinator().supportsHrvMeasurement();
|
||||
return device.getDeviceCoordinator().supportsHrvMeasurement(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,8 +62,17 @@ public class DashboardHrvWidget extends AbstractGaugeWidget {
|
||||
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
for (GBDevice dev : devices) {
|
||||
final List<? extends HrvSummarySample> deviceLatestSummaries = dev.getDeviceCoordinator().getHrvSummarySampleProvider(dev, dbHandler.getDaoSession())
|
||||
.getAllSamples(dashboardData.timeFrom * 1000L, dashboardData.timeTo * 1000L);
|
||||
final TimeSampleProvider<? extends HrvSummarySample> hrvSummarySampleProvider = dev.getDeviceCoordinator().getHrvSummarySampleProvider(dev, dbHandler.getDaoSession());
|
||||
|
||||
if (hrvSummarySampleProvider == null) {
|
||||
LOG.warn("Device {} does not has an hrv summary sample provider", dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
final List<? extends HrvSummarySample> deviceLatestSummaries = hrvSummarySampleProvider.getAllSamples(
|
||||
dashboardData.timeFrom * 1000L,
|
||||
dashboardData.timeTo * 1000L
|
||||
);
|
||||
|
||||
if (!deviceLatestSummaries.isEmpty() && (latestSummary == null || latestSummary.getTimestamp() < deviceLatestSummaries.get(deviceLatestSummaries.size() - 1).getTimestamp())) {
|
||||
latestSummary = deviceLatestSummaries.get(deviceLatestSummaries.size() - 1);
|
||||
@@ -94,7 +104,7 @@ public class DashboardHrvWidget extends AbstractGaugeWidget {
|
||||
final HrvData hrvData = (HrvData) dashboardData.get("hrv");
|
||||
final float value = hrvData != null ? calculateGaugeValue(hrvData.weeklyAverage, hrvData.baselineLowUpper, hrvData.baselineBalancedLower, hrvData.baselineBalancedUpper) : -1;
|
||||
final String valueText;
|
||||
valueText = value > 0 ? getString(R.string.hrv_status_unit, hrvData.weeklyAverage) : getString(R.string.stats_empty_value);
|
||||
valueText = hrvData != null && hrvData.weeklyAverage > 0 ? getString(R.string.hrv_status_unit, hrvData.weeklyAverage) : getString(R.string.stats_empty_value);
|
||||
setText(valueText);
|
||||
drawSegmentedGauge(
|
||||
colors,
|
||||
|
||||
+1
-1
@@ -508,7 +508,7 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsHrvMeasurement() {
|
||||
public boolean supportsHrvMeasurement(final GBDevice device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -243,7 +243,7 @@ public interface DeviceCoordinator {
|
||||
boolean supportsStressMeasurement();
|
||||
|
||||
boolean supportsBodyEnergy();
|
||||
boolean supportsHrvMeasurement();
|
||||
boolean supportsHrvMeasurement(GBDevice device);
|
||||
boolean supportsVO2Max();
|
||||
boolean supportsVO2MaxCycling();
|
||||
boolean supportsVO2MaxRunning();
|
||||
|
||||
+1
-1
@@ -174,7 +174,7 @@ public abstract class AbstractColmiR0xCoordinator extends AbstractBLEDeviceCoord
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsHrvMeasurement() {
|
||||
public boolean supportsHrvMeasurement(final GBDevice device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -266,7 +266,7 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsHrvMeasurement() {
|
||||
public boolean supportsHrvMeasurement(final GBDevice device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -42,6 +42,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSett
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
|
||||
import nodomain.freeyourgadget.gadgetbridge.capabilities.password.PasswordCapabilityImpl;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.GenericHrvValueSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.DateTimeDisplay;
|
||||
@@ -172,6 +173,11 @@ public abstract class HuamiCoordinator extends AbstractBLEDeviceCoordinator {
|
||||
return new HuamiSleepRespiratoryRateSampleProvider(device, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericHrvValueSampleProvider getHrvValueSampleProvider(GBDevice device, DaoSession session) {
|
||||
return new GenericHrvValueSampleProvider(device, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeSampleProvider<? extends SleepScoreSample> getSleepScoreProvider(final GBDevice device, final DaoSession session) {
|
||||
return new HuamiSleepSessionSampleProvider(device, session);
|
||||
|
||||
+14
@@ -35,6 +35,7 @@ import java.util.regex.Pattern;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AppManagerActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsScreen;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
|
||||
@@ -45,6 +46,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.Vo2MaxSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.WorkoutVo2MaxSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiExtendedSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
|
||||
@@ -226,6 +228,11 @@ public abstract class ZeppOsCoordinator extends HuamiCoordinator {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsHrvMeasurement(final GBDevice device) {
|
||||
return supportsDisplayItem(device, "hrv");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SleepAsAndroidFeature> getSleepAsAndroidFeatures() {
|
||||
return EnumSet.of(SleepAsAndroidFeature.ACCELEROMETER, SleepAsAndroidFeature.HEART_RATE, SleepAsAndroidFeature.ALARMS, SleepAsAndroidFeature.NOTIFICATIONS);
|
||||
@@ -628,6 +635,13 @@ public abstract class ZeppOsCoordinator extends HuamiCoordinator {
|
||||
return ZeppOsConfigService.deviceHasConfig(getPrefs(device), config);
|
||||
}
|
||||
|
||||
private boolean supportsDisplayItem(final GBDevice device, final String item) {
|
||||
return getPrefs(device).getList(
|
||||
DeviceSettingsUtils.getPrefPossibleValuesKey(HuamiConst.PREF_DISPLAY_ITEMS_SORTABLE),
|
||||
Collections.emptyList()
|
||||
).contains(item);
|
||||
}
|
||||
|
||||
public static boolean experimentalFeatures(final GBDevice device) {
|
||||
return getPrefs(device).getBoolean("zepp_os_experimental_features", false);
|
||||
}
|
||||
|
||||
+4
-5
@@ -129,13 +129,12 @@ public class TestDeviceCoordinator extends AbstractDeviceCoordinator {
|
||||
|
||||
@Override
|
||||
public TimeSampleProvider<? extends HrvSummarySample> getHrvSummarySampleProvider(final GBDevice device, final DaoSession session) {
|
||||
return supportsBodyEnergy() ? new TestHrvSummarySampleProvider() : super.getHrvSummarySampleProvider(device ,session);
|
||||
|
||||
return supportsHrvMeasurement(device) ? new TestHrvSummarySampleProvider() : super.getHrvSummarySampleProvider(device ,session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeSampleProvider<? extends HrvValueSample> getHrvValueSampleProvider(final GBDevice device, final DaoSession session) {
|
||||
return supportsBodyEnergy() ? new TestHrvValueSampleProvider() : super.getHrvValueSampleProvider(device ,session);
|
||||
return supportsHrvMeasurement(device) ? new TestHrvValueSampleProvider() : super.getHrvValueSampleProvider(device ,session);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -346,8 +345,8 @@ public class TestDeviceCoordinator extends AbstractDeviceCoordinator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsHrvMeasurement() {
|
||||
return supports(getTestDevice(), TestFeature.HRV_MEASUREMENT);
|
||||
public boolean supportsHrvMeasurement(final GBDevice device) {
|
||||
return supports(device, TestFeature.HRV_MEASUREMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-6
@@ -19,9 +19,6 @@ package nodomain.freeyourgadget.gadgetbridge.devices.ultrahuman;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -62,8 +59,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.ultrahuman.UltrahumanDeviceSupport;
|
||||
|
||||
public class UltrahumanDeviceCoordinator extends AbstractBLEDeviceCoordinator {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(UltrahumanDeviceCoordinator.class);
|
||||
|
||||
@Override
|
||||
public List<DeviceCardAction> getCustomActions() {
|
||||
// TODO - use an airplane icon instead
|
||||
@@ -187,7 +182,7 @@ public class UltrahumanDeviceCoordinator extends AbstractBLEDeviceCoordinator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsHrvMeasurement() {
|
||||
public boolean supportsHrvMeasurement(final GBDevice device) {
|
||||
// TODO - needs getHrvSummarySampleProvider in addition to the implemented getHrvValueSampleProvider
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ public class RecordedDataTypes {
|
||||
public static final int TYPE_SLEEP_RESPIRATORY_RATE = 0x00000200;
|
||||
public static final int TYPE_HUAMI_STATISTICS = 0x00000400;
|
||||
public static final int TYPE_SLEEP = 0x00000800;
|
||||
public static final int TYPE_HRV = 0x00001000;
|
||||
|
||||
public static final int TYPE_ALL = (int)0xffffffff;
|
||||
|
||||
@@ -38,5 +39,6 @@ public class RecordedDataTypes {
|
||||
public static final int TYPE_SYNC = TYPE_ACTIVITY | TYPE_GPS_TRACKS | TYPE_SPO2 | TYPE_STRESS |
|
||||
TYPE_TEMPERATURE |
|
||||
TYPE_SLEEP |
|
||||
TYPE_HRV |
|
||||
TYPE_HEART_RATE | TYPE_PAI | TYPE_SLEEP_RESPIRATORY_RATE;
|
||||
}
|
||||
|
||||
+5
@@ -130,6 +130,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.SleepState;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WearingState;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.SleepAsAndroidSender;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.fetch.AbstractFetchOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.fetch.FetchHrvOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.fetch.FetchSleepSessionOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.fetch.FetchStatisticsOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.fetch.FetchTemperatureOperation;
|
||||
@@ -1713,6 +1714,10 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements
|
||||
this.fetchOperationQueue.add(new FetchSpo2NormalOperation(this));
|
||||
}
|
||||
|
||||
if ((dataTypes & RecordedDataTypes.TYPE_HRV) != 0 && coordinator.supportsHrvMeasurement(gbDevice)) {
|
||||
this.fetchOperationQueue.add(new FetchHrvOperation(this));
|
||||
}
|
||||
|
||||
if (ZeppOsCoordinator.experimentalFeatures(getDevice())) {
|
||||
if ((dataTypes & RecordedDataTypes.TYPE_HEART_RATE) != 0 && coordinator.supportsHeartRateStats()) {
|
||||
this.fetchOperationQueue.add(new FetchHeartRateManualOperation(this));
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/* Copyright (C) 2025 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 <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.fetch;
|
||||
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.GenericHrvValueSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.GenericHrvValueSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
/**
|
||||
* An operation that fetches HRV data.
|
||||
*/
|
||||
public class FetchHrvOperation extends AbstractRepeatingFetchOperation {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FetchHrvOperation.class);
|
||||
|
||||
public FetchHrvOperation(final HuamiSupport support) {
|
||||
super(support, HuamiFetchDataType.HRV);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String taskDescription() {
|
||||
return getContext().getString(R.string.busy_task_fetch_hrv_data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handleActivityData(final GregorianCalendar timestamp, final byte[] bytes) {
|
||||
if (bytes.length % 6 != 0) {
|
||||
LOG.error("Unexpected length for hrv data {}, not divisible by 6", bytes.length);
|
||||
return false;
|
||||
}
|
||||
|
||||
final ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
final List<GenericHrvValueSample> samples = new ArrayList<>();
|
||||
|
||||
while (buf.hasRemaining()) {
|
||||
final long timestampSeconds = buf.getInt();
|
||||
final byte unk1 = buf.get();
|
||||
final int hrv = buf.get() & 0xff;
|
||||
|
||||
timestamp.setTimeInMillis(timestampSeconds * 1000L);
|
||||
|
||||
LOG.trace("HRV at {}: {} unk1={}", timestamp.getTime(), hrv, unk1);
|
||||
|
||||
final GenericHrvValueSample sample = new GenericHrvValueSample();
|
||||
sample.setTimestamp(timestamp.getTimeInMillis());
|
||||
sample.setValue(hrv);
|
||||
samples.add(sample);
|
||||
}
|
||||
|
||||
return persistSamples(samples);
|
||||
}
|
||||
|
||||
protected boolean persistSamples(final List<GenericHrvValueSample> samples) {
|
||||
try (DBHandler handler = GBApplication.acquireDB()) {
|
||||
final DaoSession session = handler.getDaoSession();
|
||||
|
||||
final HuamiCoordinator coordinator = (HuamiCoordinator) getDevice().getDeviceCoordinator();
|
||||
final GenericHrvValueSampleProvider sampleProvider = coordinator.getHrvValueSampleProvider(getDevice(), session);
|
||||
|
||||
sampleProvider.persistForDevice(getContext(), getDevice(), samples);
|
||||
} catch (final Exception e) {
|
||||
GB.toast(getContext(), "Error saving hrv samples", Toast.LENGTH_LONG, GB.ERROR, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLastSyncTimeKey() {
|
||||
return "lastHrvTimeMillis";
|
||||
}
|
||||
}
|
||||
+1
@@ -33,6 +33,7 @@ public enum HuamiFetchDataType {
|
||||
RESTING_HEART_RATE(0x3a),
|
||||
MAX_HEART_RATE(0x3d),
|
||||
SLEEP_SESSION(0x48),
|
||||
HRV(0x49),
|
||||
;
|
||||
|
||||
private final byte code;
|
||||
|
||||
@@ -172,7 +172,7 @@ public class Prefs {
|
||||
*/
|
||||
public List<String> getList(final String key, final List<String> defaultValue, final String separatorRegex) {
|
||||
final String stringValue = preferences.getString(key, null);
|
||||
if (stringValue == null) {
|
||||
if (stringValue == null || stringValue.isEmpty()) {
|
||||
return defaultValue;
|
||||
}
|
||||
return Arrays.asList(stringValue.split(separatorRegex));
|
||||
|
||||
Reference in New Issue
Block a user