mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-25 03:16:51 +01:00
Test Device: Add fake features and data
This commit is contained in:
parent
6a576202a9
commit
a3bd7a297a
@ -0,0 +1,25 @@
|
|||||||
|
/* Copyright (C) 2024 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.devices.test;
|
||||||
|
|
||||||
|
public class TestDeviceConst {
|
||||||
|
public static final String PREF_TEST_FEATURES = "test_features";
|
||||||
|
|
||||||
|
private TestDeviceConst() {
|
||||||
|
// utility class
|
||||||
|
}
|
||||||
|
}
|
@ -23,113 +23,596 @@ import android.net.Uri;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AppManagerActivity;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.capabilities.HeartRateCapability;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.capabilities.password.PasswordCapabilityImpl;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.capabilities.widgets.WidgetManager;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.roidmi.RoidmiConst;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.test.activity.TestActivitySummaryParser;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.test.samples.TestPaiSampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.test.samples.TestSpo2SampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.test.samples.TestStressSampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.test.samples.TestSampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.test.samples.TestTemperatureSampleProvider;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.AbstractNotificationPattern;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.HeartRateSample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.PaiSample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.SleepRespiratoryRateSample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.TemperatureSample;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.unknown.UnknownDeviceSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.ServiceDeviceSupport;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.test.TestDeviceSupport;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
|
|
||||||
public class TestDeviceCoordinator extends AbstractDeviceCoordinator {
|
public class TestDeviceCoordinator extends AbstractDeviceCoordinator {
|
||||||
@Override
|
@Override
|
||||||
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
|
protected void deleteDevice(@NonNull final GBDevice gbDevice,
|
||||||
|
@NonNull final Device device,
|
||||||
}
|
@NonNull final DaoSession session) throws GBException {
|
||||||
|
// Nothing to do
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public boolean supports(GBDeviceCandidate candidate) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public Class<? extends Activity> getPairingActivity() {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsActivityDataFetching() {
|
public boolean supports(final GBDeviceCandidate candidate) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsActivityTracking() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SampleProvider<? extends ActivitySample> getSampleProvider(GBDevice device, DaoSession session) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InstallHandler findInstallHandler(Uri uri, Context context) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsScreenshots() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getAlarmSlotCount(GBDevice device) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsSmartWakeup(GBDevice device) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getManufacturer() {
|
public String getManufacturer() {
|
||||||
return "Test";
|
return "Gadgetbridge";
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsAppsManagement(GBDevice device) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<? extends Activity> getAppsManagementActivity() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsCalendarEvents() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsRealtimeData() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsFindDevice() {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends DeviceSupport> getDeviceSupportClass() {
|
public Class<? extends DeviceSupport> getDeviceSupportClass() {
|
||||||
return UnknownDeviceSupport.class;
|
return TestDeviceSupport.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getDeviceNameResource() {
|
public int getDeviceNameResource() {
|
||||||
return R.string.devicetype_test;
|
return R.string.devicetype_test;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SampleProvider<? extends ActivitySample> getSampleProvider(final GBDevice device, final DaoSession session) {
|
||||||
|
return supportsActivityTracking() ? new TestSampleProvider(device, session) : super.getSampleProvider(device, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TimeSampleProvider<? extends StressSample> getStressSampleProvider(final GBDevice device, final DaoSession session) {
|
||||||
|
return supportsStressMeasurement() ? new TestStressSampleProvider() : super.getStressSampleProvider(device, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] getStressRanges() {
|
||||||
|
// TODO getStressRanges
|
||||||
|
return super.getStressRanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TimeSampleProvider<? extends TemperatureSample> getTemperatureSampleProvider(final GBDevice device, final DaoSession session) {
|
||||||
|
return new TestTemperatureSampleProvider(); // TODO supportsTemperature
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TimeSampleProvider<? extends Spo2Sample> getSpo2SampleProvider(final GBDevice device, final DaoSession session) {
|
||||||
|
return supportsSpo2() ? new TestSpo2SampleProvider() : super.getSpo2SampleProvider(device, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TimeSampleProvider<? extends HeartRateSample> getHeartRateMaxSampleProvider(final GBDevice device, final DaoSession session) {
|
||||||
|
// TODO getHeartRateMaxSampleProvider
|
||||||
|
return super.getHeartRateMaxSampleProvider(device, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TimeSampleProvider<? extends HeartRateSample> getHeartRateRestingSampleProvider(final GBDevice device, final DaoSession session) {
|
||||||
|
// TODO getHeartRateRestingSampleProvider
|
||||||
|
return super.getHeartRateRestingSampleProvider(device, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TimeSampleProvider<? extends HeartRateSample> getHeartRateManualSampleProvider(final GBDevice device, final DaoSession session) {
|
||||||
|
// TODO getHeartRateManualSampleProvider
|
||||||
|
return super.getHeartRateManualSampleProvider(device, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TimeSampleProvider<? extends PaiSample> getPaiSampleProvider(final GBDevice device, final DaoSession session) {
|
||||||
|
return supportsPai() ? new TestPaiSampleProvider() : super.getPaiSampleProvider(device, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TimeSampleProvider<? extends SleepRespiratoryRateSample> getSleepRespiratoryRateSampleProvider(final GBDevice device, final DaoSession session) {
|
||||||
|
// TODO getHeartRateManualSampleProvider
|
||||||
|
return super.getSleepRespiratoryRateSampleProvider(device, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public ActivitySummaryParser getActivitySummaryParser(final GBDevice device) {
|
||||||
|
return supportsActivityTracks() ? new TestActivitySummaryParser() : super.getActivitySummaryParser(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getAppCacheDir() throws IOException {
|
||||||
|
return new File(FileUtils.getExternalFilesDir(), "test-app-cache");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAppCacheSortFilename() {
|
||||||
|
return "test-app-cache-order.txt";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAppFileExtension() {
|
||||||
|
return ".txt";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsAppListFetching() {
|
||||||
|
return supports(getTestDevice(), TestFeature.APP_LIST_FETCHING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsFlashing() {
|
||||||
|
return supports(getTestDevice(), TestFeature.FLASHING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public InstallHandler findInstallHandler(final Uri uri, final Context context) {
|
||||||
|
// TODO findInstallHandler?
|
||||||
|
return super.findInstallHandler(uri, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsScreenshots() {
|
||||||
|
return supports(getTestDevice(), TestFeature.SCREENSHOTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAlarmSlotCount(final GBDevice device) {
|
||||||
|
return super.getAlarmSlotCount(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsSmartWakeup(final GBDevice device) {
|
||||||
|
return supports(getTestDevice(), TestFeature.SMART_WAKEUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsAppReordering() {
|
||||||
|
return supports(getTestDevice(), TestFeature.APP_REORDERING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsAppsManagement(final GBDevice device) {
|
||||||
|
return supports(getTestDevice(), TestFeature.APPS_MANAGEMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsCachedAppManagement(final GBDevice device) {
|
||||||
|
return supports(getTestDevice(), TestFeature.CACHED_APP_MANAGEMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsInstalledAppManagement(final GBDevice device) {
|
||||||
|
return supports(getTestDevice(), TestFeature.INSTALLED_APP_MANAGEMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsWatchfaceManagement(final GBDevice device) {
|
||||||
|
return supports(getTestDevice(), TestFeature.WATCHFACE_MANAGEMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Class<? extends Activity> getAppsManagementActivity() {
|
||||||
|
return AppManagerActivity.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Class<? extends Activity> getWatchfaceDesignerActivity() {
|
||||||
|
// TODO getWatchfaceDesignerActivity
|
||||||
|
return super.getWatchfaceDesignerActivity();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsCalendarEvents() {
|
||||||
|
return supports(getTestDevice(), TestFeature.CALENDAR_EVENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsActivityDataFetching() {
|
||||||
|
return supports(getTestDevice(), TestFeature.ACTIVITY_DATA_FETCHING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsActivityTracking() {
|
||||||
|
return supports(getTestDevice(), TestFeature.ACTIVITY_TRACKING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsActivityTracks() {
|
||||||
|
return supports(getTestDevice(), TestFeature.ACTIVITY_TRACKS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsStressMeasurement() {
|
||||||
|
return supports(getTestDevice(), TestFeature.STRESS_MEASUREMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsSpo2() {
|
||||||
|
return supports(getTestDevice(), TestFeature.SPO2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsHeartRateStats() {
|
||||||
|
return supports(getTestDevice(), TestFeature.HEART_RATE_STATS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsPai() {
|
||||||
|
return supports(getTestDevice(), TestFeature.PAI);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPaiName() {
|
||||||
|
return R.string.menuitem_pai;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsPaiTime() {
|
||||||
|
return supports(getTestDevice(), TestFeature.PAI_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsSleepRespiratoryRate() {
|
||||||
|
return supports(getTestDevice(), TestFeature.SLEEP_RESPIRATORY_RATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsAlarmSnoozing() {
|
||||||
|
return supports(getTestDevice(), TestFeature.ALARM_SNOOZING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsAlarmTitle(final GBDevice device) {
|
||||||
|
return supports(getTestDevice(), TestFeature.ALARM_TITLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAlarmTitleLimit(final GBDevice device) {
|
||||||
|
return supports(getTestDevice(), TestFeature.ALARM_TITLE_LIMIT) ? 10 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsAlarmDescription(final GBDevice device) {
|
||||||
|
return supports(getTestDevice(), TestFeature.ALARM_DESCRIPTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsMusicInfo() {
|
||||||
|
return supports(getTestDevice(), TestFeature.MUSIC_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsLedColor() {
|
||||||
|
return supports(getTestDevice(), TestFeature.LED_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaximumReminderMessageLength() {
|
||||||
|
// TODO getMaximumReminderMessageLength
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getReminderSlotCount(final GBDevice device) {
|
||||||
|
return supports(getTestDevice(), TestFeature.REMINDERS) ? 3 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCannedRepliesSlotCount(final GBDevice device) {
|
||||||
|
return supports(getTestDevice(), TestFeature.CANNED_REPLIES) ? 3 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWorldClocksSlotCount() {
|
||||||
|
return supports(getTestDevice(), TestFeature.WORLD_CLOCKS) ? 3 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWorldClocksLabelLength() {
|
||||||
|
// TODO getWorldClocksLabelLength
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsDisabledWorldClocks() {
|
||||||
|
return supports(getTestDevice(), TestFeature.DISABLED_WORLD_CLOCKS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getContactsSlotCount(final GBDevice device) {
|
||||||
|
return supports(getTestDevice(), TestFeature.CONTACTS) ? 3 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsRgbLedColor() {
|
||||||
|
return supports(getTestDevice(), TestFeature.RGB_LED_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public int[] getColorPresets() {
|
||||||
|
return RoidmiConst.COLOR_PRESETS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsHeartRateMeasurement(final GBDevice device) {
|
||||||
|
return supports(getTestDevice(), TestFeature.HEART_RATE_MEASUREMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsManualHeartRateMeasurement(final GBDevice device) {
|
||||||
|
return supports(getTestDevice(), TestFeature.MANUAL_HEART_RATE_MEASUREMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsRealtimeData() {
|
||||||
|
return supports(getTestDevice(), TestFeature.REALTIME_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsRemSleep() {
|
||||||
|
return supports(getTestDevice(), TestFeature.REM_SLEEP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsWeather() {
|
||||||
|
return supports(getTestDevice(), TestFeature.WEATHER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsFindDevice() {
|
||||||
|
return supports(getTestDevice(), TestFeature.FIND_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsUnicodeEmojis() {
|
||||||
|
return supports(getTestDevice(), TestFeature.UNICODE_EMOJIS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] getSupportedDeviceSpecificConnectionSettings() {
|
||||||
|
return super.getSupportedDeviceSpecificConnectionSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] getSupportedDeviceSpecificApplicationSettings() {
|
||||||
|
return new int[]{
|
||||||
|
R.xml.devicesettings_custom_deviceicon,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] getSupportedDeviceSpecificSettings(final GBDevice device) {
|
||||||
|
final List<Integer> settings = new ArrayList<>();
|
||||||
|
|
||||||
|
settings.add(R.xml.devicesettings_header_apps);
|
||||||
|
settings.add(R.xml.devicesettings_loyalty_cards);
|
||||||
|
|
||||||
|
if (getWorldClocksSlotCount() > 0) {
|
||||||
|
settings.add(R.xml.devicesettings_header_time);
|
||||||
|
settings.add(R.xml.devicesettings_world_clocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getContactsSlotCount(device) > 0) {
|
||||||
|
settings.add(R.xml.devicesettings_header_other);
|
||||||
|
settings.add(R.xml.devicesettings_contacts);
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.add(R.xml.devicesettings_header_developer);
|
||||||
|
settings.add(R.xml.devicesettings_test_features);
|
||||||
|
|
||||||
|
return ArrayUtils.toPrimitive(settings.toArray(new Integer[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] getSupportedDeviceSpecificAuthenticationSettings() {
|
||||||
|
return new int[]{R.xml.devicesettings_pairingkey};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeviceSpecificSettingsCustomizer getDeviceSpecificSettingsCustomizer(final GBDevice device) {
|
||||||
|
return new TestDeviceSpecificSettingsCustomizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getSupportedLanguageSettings(final GBDevice device) {
|
||||||
|
return new String[]{
|
||||||
|
"auto",
|
||||||
|
"en_US",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Class<? extends Activity> getCalibrationActivity() {
|
||||||
|
// TODO getCalibrationActivity
|
||||||
|
return super.getCalibrationActivity();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBatteryCount() {
|
||||||
|
return supports(getTestDevice(), TestFeature.BATTERIES_MULTIPLE) ? 3 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BatteryConfig[] getBatteryConfig() {
|
||||||
|
if (getBatteryCount() == 1) {
|
||||||
|
return super.getBatteryConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
final BatteryConfig[] ret = new BatteryConfig[getBatteryCount()];
|
||||||
|
|
||||||
|
for (int i = 0; i < getBatteryCount(); i++) {
|
||||||
|
ret[i] = new BatteryConfig(i, R.drawable.ic_battery_full, R.string.battery);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsPowerOff() {
|
||||||
|
return supports(getTestDevice(), TestFeature.POWER_OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PasswordCapabilityImpl.Mode getPasswordCapability() {
|
||||||
|
return super.getPasswordCapability();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<HeartRateCapability.MeasurementInterval> getHeartRateMeasurementIntervals() {
|
||||||
|
return super.getHeartRateMeasurementIntervals();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsWidgets(final GBDevice device) {
|
||||||
|
return supports(getTestDevice(), TestFeature.WIDGETS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public WidgetManager getWidgetManager(final GBDevice device) {
|
||||||
|
return super.getWidgetManager(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsNavigation() {
|
||||||
|
return supports(getTestDevice(), TestFeature.NAVIGATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumSet<ServiceDeviceSupport.Flags> getInitialFlags() {
|
||||||
|
return EnumSet.noneOf(ServiceDeviceSupport.Flags.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDefaultIconResource() {
|
||||||
|
// TODO getDefaultIconResource
|
||||||
|
return super.getDefaultIconResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDisabledIconResource() {
|
||||||
|
// TODO getDisabledIconResource
|
||||||
|
return super.getDisabledIconResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsNotificationVibrationPatterns() {
|
||||||
|
return supports(getTestDevice(), TestFeature.NOTIFICATION_VIBRATION_PATTERNS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsNotificationVibrationRepetitionPatterns() {
|
||||||
|
return supports(getTestDevice(), TestFeature.NOTIFICATION_VIBRATION_REPETITION_PATTERNS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsNotificationLedPatterns() {
|
||||||
|
return supports(getTestDevice(), TestFeature.NOTIFICATION_LED_PATTERNS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractNotificationPattern[] getNotificationVibrationPatterns() {
|
||||||
|
// TODO getNotificationVibrationPatterns
|
||||||
|
return new AbstractNotificationPattern[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractNotificationPattern[] getNotificationVibrationRepetitionPatterns() {
|
||||||
|
// TODO getNotificationVibrationRepetitionPatterns
|
||||||
|
return new AbstractNotificationPattern[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractNotificationPattern[] getNotificationLedPatterns() {
|
||||||
|
// TODO getNotificationLedPatterns
|
||||||
|
return new AbstractNotificationPattern[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validateAuthKey(final String authKey) {
|
||||||
|
return authKey.equals("hunter2");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean supports(final GBDevice device, final TestFeature feature) {
|
||||||
|
if (device == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Set<String> features = new HashSet<>(getPrefs(device).getStringSet(TestDeviceConst.PREF_TEST_FEATURES, Collections.emptySet()));
|
||||||
|
// if nothing enable, enable everything
|
||||||
|
return features.isEmpty() || features.contains(feature.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private GBDevice getTestDevice() {
|
||||||
|
// HACK: Avoid the refactor of adding a device as a parameter on all functions
|
||||||
|
// This means that it's only possible to have a single test device
|
||||||
|
|
||||||
|
if (GBApplication.app() == null || GBApplication.app().getDeviceManager() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<GBDevice> devices = GBApplication.app().getDeviceManager().getDevices();
|
||||||
|
for (GBDevice device : devices) {
|
||||||
|
if (DeviceType.TEST == device.getType()) {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Prefs getPrefs(final GBDevice device) {
|
||||||
|
return new Prefs(GBApplication.getDeviceSpecificSharedPrefs(device.getAddress()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
/* Copyright (C) 2024 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.devices.test;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class to try and get deterministic random values across multiple users. This is not efficient
|
||||||
|
* and should definitely be improved.
|
||||||
|
*/
|
||||||
|
public class TestDeviceRand {
|
||||||
|
public static final long BASE_TIMESTAMP = 1420499943000L;
|
||||||
|
|
||||||
|
private TestDeviceRand() {
|
||||||
|
// utility class
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int randInt(final long ts, final int min, final int max) {
|
||||||
|
return new Random(ts - BASE_TIMESTAMP).nextInt((max - min) + 1) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long randLong(final long ts, final long min, final long max) {
|
||||||
|
return (long) (new Random(ts - BASE_TIMESTAMP).nextFloat() * (max - min) + min);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float randFloat(final long ts, final float min, final float max) {
|
||||||
|
return new Random(ts - BASE_TIMESTAMP).nextFloat() * (max - min) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean randBool(final long ts, final float pTrue) {
|
||||||
|
return new Random(ts - BASE_TIMESTAMP).nextFloat() < pTrue;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/* Copyright (C) 2024 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.devices.test;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
|
||||||
|
import androidx.preference.MultiSelectListPreference;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsHandler;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
|
|
||||||
|
public class TestDeviceSpecificSettingsCustomizer implements DeviceSpecificSettingsCustomizer {
|
||||||
|
@Override
|
||||||
|
public void onPreferenceChange(final Preference preference, final DeviceSpecificSettingsHandler handler) {
|
||||||
|
if (TestDeviceConst.PREF_TEST_FEATURES.equals(preference.getKey())) {
|
||||||
|
handler.getDevice().sendDeviceUpdateIntent(handler.getContext());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void customizeSettings(final DeviceSpecificSettingsHandler handler, final Prefs prefs) {
|
||||||
|
final Preference pref = handler.findPreference(TestDeviceConst.PREF_TEST_FEATURES);
|
||||||
|
if (pref == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate the preference directly from the enum
|
||||||
|
final CharSequence[] entries = new CharSequence[TestFeature.values().length];
|
||||||
|
final CharSequence[] values = new CharSequence[TestFeature.values().length];
|
||||||
|
for (int i = 0; i < TestFeature.values().length; i++) {
|
||||||
|
entries[i] = TestFeature.values()[i].name();
|
||||||
|
values[i] = TestFeature.values()[i].name();
|
||||||
|
}
|
||||||
|
if (pref instanceof MultiSelectListPreference) {
|
||||||
|
((MultiSelectListPreference) pref).setEntries(entries);
|
||||||
|
((MultiSelectListPreference) pref).setEntryValues(values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getPreferenceKeysWithSummary() {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<TestDeviceSpecificSettingsCustomizer> CREATOR = new Creator<TestDeviceSpecificSettingsCustomizer>() {
|
||||||
|
@Override
|
||||||
|
public TestDeviceSpecificSettingsCustomizer createFromParcel(final Parcel in) {
|
||||||
|
return new TestDeviceSpecificSettingsCustomizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TestDeviceSpecificSettingsCustomizer[] newArray(final int size) {
|
||||||
|
return new TestDeviceSpecificSettingsCustomizer[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(final Parcel dest, final int flags) {
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/* Copyright (C) 2024 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.devices.test;
|
||||||
|
|
||||||
|
public enum TestFeature {
|
||||||
|
ACTIVITY_DATA_FETCHING,
|
||||||
|
ACTIVITY_TRACKING,
|
||||||
|
ACTIVITY_TRACKS,
|
||||||
|
ALARM_DESCRIPTION,
|
||||||
|
ALARM_SNOOZING,
|
||||||
|
ALARM_TITLE_LIMIT,
|
||||||
|
ALARM_TITLE,
|
||||||
|
APP_LIST_FETCHING,
|
||||||
|
APP_REORDERING,
|
||||||
|
APPS_MANAGEMENT,
|
||||||
|
BATTERIES_MULTIPLE,
|
||||||
|
CACHED_APP_MANAGEMENT,
|
||||||
|
CALENDAR_EVENTS,
|
||||||
|
CANNED_REPLIES,
|
||||||
|
CONTACTS,
|
||||||
|
DISABLED_WORLD_CLOCKS,
|
||||||
|
FIND_DEVICE,
|
||||||
|
FLASHING,
|
||||||
|
FM_FREQUENCY,
|
||||||
|
HEART_RATE_MEASUREMENT,
|
||||||
|
HEART_RATE_STATS,
|
||||||
|
INSTALLED_APP_MANAGEMENT,
|
||||||
|
LED_COLOR,
|
||||||
|
MANUAL_HEART_RATE_MEASUREMENT,
|
||||||
|
MUSIC_INFO,
|
||||||
|
NAVIGATION,
|
||||||
|
NOTIFICATION_LED_PATTERNS,
|
||||||
|
NOTIFICATION_VIBRATION_PATTERNS,
|
||||||
|
NOTIFICATION_VIBRATION_REPETITION_PATTERNS,
|
||||||
|
PAI_TIME,
|
||||||
|
PAI,
|
||||||
|
POWER_OFF,
|
||||||
|
REALTIME_DATA,
|
||||||
|
REM_SLEEP,
|
||||||
|
REMINDERS,
|
||||||
|
RGB_LED_COLOR,
|
||||||
|
SCREENSHOTS,
|
||||||
|
SLEEP_RESPIRATORY_RATE,
|
||||||
|
SMART_WAKEUP,
|
||||||
|
SPO2,
|
||||||
|
STRESS_MEASUREMENT,
|
||||||
|
UNICODE_EMOJIS,
|
||||||
|
WATCHFACE_MANAGEMENT,
|
||||||
|
WEATHER,
|
||||||
|
WIDGETS,
|
||||||
|
WORLD_CLOCKS,
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/* Copyright (C) 2024 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.devices.test.activity;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser;
|
||||||
|
|
||||||
|
public class TestActivitySummaryParser implements ActivitySummaryParser {
|
||||||
|
@Override
|
||||||
|
public BaseActivitySummary parseBinaryData(final BaseActivitySummary summary) {
|
||||||
|
return summary;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,163 @@
|
|||||||
|
/* Copyright (C) 2024 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.devices.test.samples;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.test.TestDeviceRand;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.PaiSample;
|
||||||
|
|
||||||
|
public class TestPaiSampleProvider implements TimeSampleProvider<PaiSample> {
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public List<PaiSample> getAllSamples(final long timestampFrom, final long timestampTo) {
|
||||||
|
final List<PaiSample> samples = new ArrayList<>();
|
||||||
|
|
||||||
|
int paiLow = TestDeviceRand.randInt(timestampFrom, 0, 15);
|
||||||
|
int paiMod = TestDeviceRand.randInt(timestampFrom, 0, 15);
|
||||||
|
int paiHigh = TestDeviceRand.randInt(timestampFrom, 0, 15);
|
||||||
|
int paiTotal = paiLow + paiMod + paiHigh;
|
||||||
|
|
||||||
|
for (long ts = timestampFrom; ts < timestampTo; ts += 12 * 60 * 60 * 1000L) {
|
||||||
|
if (TestDeviceRand.randBool(ts, 0.75f)) {
|
||||||
|
samples.add(new TestPaiSample(
|
||||||
|
ts,
|
||||||
|
paiLow,
|
||||||
|
paiMod,
|
||||||
|
paiHigh,
|
||||||
|
paiTotal
|
||||||
|
));
|
||||||
|
}
|
||||||
|
paiTotal += paiLow + paiMod + paiHigh;
|
||||||
|
paiLow += TestDeviceRand.randInt(ts, - paiLow, 15 - paiLow);
|
||||||
|
paiMod += TestDeviceRand.randInt(ts, - paiMod, 15 - paiMod);
|
||||||
|
paiHigh += TestDeviceRand.randInt(ts, - paiHigh, 15 - paiHigh);
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSample(final PaiSample timeSample) {
|
||||||
|
throw new UnsupportedOperationException("read-only sample provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSamples(final List<PaiSample> timeSamples) {
|
||||||
|
throw new UnsupportedOperationException("read-only sample provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PaiSample createSample() {
|
||||||
|
throw new UnsupportedOperationException("read-only sample provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public PaiSample getLatestSample() {
|
||||||
|
final long ts = System.currentTimeMillis();
|
||||||
|
return new TestPaiSample(
|
||||||
|
ts - TestDeviceRand.randLong(ts, 10 * 1000L, 2 * 60 * 60 * 1000L),
|
||||||
|
TestDeviceRand.randInt(ts, 85, 99),
|
||||||
|
TestDeviceRand.randInt(ts, 85, 99),
|
||||||
|
TestDeviceRand.randInt(ts, 85, 99),
|
||||||
|
TestDeviceRand.randInt(ts, 85, 99)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public PaiSample getFirstSample() {
|
||||||
|
return new TestPaiSample(
|
||||||
|
TestDeviceRand.BASE_TIMESTAMP,
|
||||||
|
TestDeviceRand.randInt(TestDeviceRand.BASE_TIMESTAMP, 0, 15),
|
||||||
|
TestDeviceRand.randInt(TestDeviceRand.BASE_TIMESTAMP, 0, 15),
|
||||||
|
TestDeviceRand.randInt(TestDeviceRand.BASE_TIMESTAMP, 0, 15),
|
||||||
|
TestDeviceRand.randInt(TestDeviceRand.BASE_TIMESTAMP, 70, 90)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TestPaiSample implements PaiSample {
|
||||||
|
private final long timestamp;
|
||||||
|
private final int paiLow;
|
||||||
|
private final int paiModerate;
|
||||||
|
private final int paiHigh;
|
||||||
|
private final int paiTotal;
|
||||||
|
|
||||||
|
public TestPaiSample(final long timestamp,
|
||||||
|
final int low,
|
||||||
|
final int moderate,
|
||||||
|
final int high,
|
||||||
|
final int total) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.paiLow = low;
|
||||||
|
this.paiModerate = moderate;
|
||||||
|
this.paiHigh = high;
|
||||||
|
this.paiTotal = total;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getPaiLow() {
|
||||||
|
return paiLow;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getPaiModerate() {
|
||||||
|
return paiModerate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getPaiHigh() {
|
||||||
|
return paiHigh;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTimeLow() {
|
||||||
|
return paiLow;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTimeModerate() {
|
||||||
|
return paiModerate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTimeHigh() {
|
||||||
|
return paiHigh;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getPaiToday() {
|
||||||
|
return paiLow + paiModerate + paiHigh;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getPaiTotal() {
|
||||||
|
return paiTotal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,241 @@
|
|||||||
|
/* Copyright (C) 2024 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.devices.test.samples;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.greenrobot.dao.AbstractDao;
|
||||||
|
import de.greenrobot.dao.Property;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractSampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.test.TestDeviceRand;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||||
|
|
||||||
|
public class TestSampleProvider extends AbstractSampleProvider<TestSampleProvider.TestActivitySample> {
|
||||||
|
public TestSampleProvider(final GBDevice device, final DaoSession session) {
|
||||||
|
super(device, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractDao<TestActivitySample, ?> getSampleDao() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected Property getRawKindSampleProperty() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected Property getTimestampSampleProperty() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected Property getDeviceIdentifierSampleProperty() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int normalizeType(final int rawType) {
|
||||||
|
return rawType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int toRawActivityKind(final int activityKind) {
|
||||||
|
return activityKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float normalizeIntensity(final int rawIntensity) {
|
||||||
|
return rawIntensity / 100f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TestActivitySample createActivitySample() {
|
||||||
|
throw new UnsupportedOperationException("read-only sample provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<TestActivitySample> getGBActivitySamples(final int timestamp_from, final int timestamp_to, final int activityType) {
|
||||||
|
final List<TestActivitySample> samples = new ArrayList<>();
|
||||||
|
|
||||||
|
int[] sleepStages = new int[] {
|
||||||
|
ActivityKind.TYPE_LIGHT_SLEEP,
|
||||||
|
ActivityKind.TYPE_DEEP_SLEEP,
|
||||||
|
};
|
||||||
|
if (getDevice().getDeviceCoordinator().supportsRemSleep()) {
|
||||||
|
sleepStages = ArrayUtils.add(sleepStages, ActivityKind.TYPE_REM_SLEEP);
|
||||||
|
}
|
||||||
|
int sleepStageCurrent = 0;
|
||||||
|
int sleepStageDirection = 1;
|
||||||
|
int sleepStageDurationRemaining = TestDeviceRand.randInt(timestamp_from * 1000L, 30, 90);
|
||||||
|
|
||||||
|
int steps = TestDeviceRand.randInt(timestamp_from * 1000L, 0, 170);
|
||||||
|
int intensity = TestDeviceRand.randInt(timestamp_from * 1000L, 0, 100);
|
||||||
|
int hr = TestDeviceRand.randInt(timestamp_from * 1000L, 90, 153);
|
||||||
|
|
||||||
|
final long bedtimeHour = TestDeviceRand.randInt(timestamp_from, 21, 22);
|
||||||
|
final long bedtimeMinute = TestDeviceRand.randInt(timestamp_from, 0, 59);
|
||||||
|
final long wakeHour = TestDeviceRand.randInt(timestamp_from, 6, 9);
|
||||||
|
final long wakeMinute = TestDeviceRand.randInt(timestamp_from, 0, 59);
|
||||||
|
|
||||||
|
final Calendar cal = GregorianCalendar.getInstance();
|
||||||
|
|
||||||
|
for (long ts = timestamp_from * 1000L; ts < timestamp_to * 1000L; ts += 60 * 1000L) {
|
||||||
|
cal.setTimeInMillis(ts);
|
||||||
|
final int h = cal.get(Calendar.HOUR_OF_DAY);
|
||||||
|
final int m = cal.get(Calendar.MINUTE);
|
||||||
|
boolean isSleep = false;
|
||||||
|
if (h == bedtimeHour) {
|
||||||
|
isSleep = m >= bedtimeMinute;
|
||||||
|
} else if (h > bedtimeHour) {
|
||||||
|
isSleep = true;
|
||||||
|
} else if (h == wakeHour) {
|
||||||
|
isSleep = m <= wakeMinute;
|
||||||
|
} else if (h < wakeHour) {
|
||||||
|
isSleep = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TestDeviceRand.randBool(ts, 0.75f)) {
|
||||||
|
samples.add(new TestActivitySample(
|
||||||
|
(int) (ts / 1000),
|
||||||
|
isSleep ? sleepStages[sleepStageCurrent] : ActivityKind.TYPE_UNKNOWN,
|
||||||
|
steps,
|
||||||
|
intensity,
|
||||||
|
hr
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSleep) {
|
||||||
|
sleepStageDurationRemaining--;
|
||||||
|
if (sleepStageDurationRemaining <= 0) {
|
||||||
|
sleepStageDurationRemaining = TestDeviceRand.randInt(ts * 1000L, 30, 90);
|
||||||
|
sleepStageCurrent += sleepStageDirection;
|
||||||
|
if (sleepStageCurrent == 0 || sleepStageCurrent == sleepStages.length - 1) {
|
||||||
|
sleepStageDirection *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
steps += TestDeviceRand.randInt(ts, -steps, 170 - steps);
|
||||||
|
intensity += TestDeviceRand.randInt(ts, -1, 1);
|
||||||
|
hr += TestDeviceRand.randInt(ts, -2, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestActivitySample extends AbstractActivitySample {
|
||||||
|
private final int timestamp;
|
||||||
|
private final int kind;
|
||||||
|
private final int steps;
|
||||||
|
private final int intensity;
|
||||||
|
private final int hr;
|
||||||
|
|
||||||
|
public TestActivitySample(final int timestamp,
|
||||||
|
final int kind,
|
||||||
|
final int steps,
|
||||||
|
final int intensity,
|
||||||
|
final int hr) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.kind = kind;
|
||||||
|
this.steps = steps;
|
||||||
|
this.intensity = intensity;
|
||||||
|
this.hr = hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SampleProvider getProvider() {
|
||||||
|
return TestSampleProvider.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTimestamp(final int timestamp) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUserId(final long userId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDeviceId(final long deviceId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getDeviceId() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getUserId() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getKind() {
|
||||||
|
return kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRawKind() {
|
||||||
|
return kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getIntensity() {
|
||||||
|
return intensity / 100f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeartRate() {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRawIntensity() {
|
||||||
|
return intensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSteps() {
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
/* Copyright (C) 2024 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.devices.test.samples;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.test.TestDeviceRand;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
|
||||||
|
|
||||||
|
public class TestSpo2SampleProvider implements TimeSampleProvider<Spo2Sample> {
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public List<Spo2Sample> getAllSamples(final long timestampFrom, final long timestampTo) {
|
||||||
|
final List<Spo2Sample> samples = new ArrayList<>();
|
||||||
|
|
||||||
|
int spo2 = TestDeviceRand.randInt(timestampFrom, 85, 99);
|
||||||
|
|
||||||
|
for (long ts = timestampFrom; ts < timestampTo; ts += 15 * 60 * 1000L) {
|
||||||
|
if (TestDeviceRand.randBool(ts, 0.3f)) {
|
||||||
|
samples.add(new TestSpo2Sample(ts, spo2));
|
||||||
|
}
|
||||||
|
spo2 += TestDeviceRand.randInt(ts, 85 - spo2, 99 - spo2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSample(final Spo2Sample timeSample) {
|
||||||
|
throw new UnsupportedOperationException("read-only sample provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSamples(final List<Spo2Sample> timeSamples) {
|
||||||
|
throw new UnsupportedOperationException("read-only sample provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Spo2Sample createSample() {
|
||||||
|
throw new UnsupportedOperationException("read-only sample provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Spo2Sample getLatestSample() {
|
||||||
|
final long ts = System.currentTimeMillis();
|
||||||
|
return new TestSpo2Sample(
|
||||||
|
ts - TestDeviceRand.randLong(ts, 10 * 1000L, 2 * 60 * 60 * 1000L),
|
||||||
|
TestDeviceRand.randInt(ts, 85, 99)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Spo2Sample getFirstSample() {
|
||||||
|
return new TestSpo2Sample(
|
||||||
|
TestDeviceRand.BASE_TIMESTAMP,
|
||||||
|
TestDeviceRand.randInt(TestDeviceRand.BASE_TIMESTAMP, 85, 99)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class TestSpo2Sample implements Spo2Sample {
|
||||||
|
private final long timestamp;
|
||||||
|
private final int spo2;
|
||||||
|
|
||||||
|
public TestSpo2Sample(final long timestamp, final int spo2) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.spo2 = spo2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return Type.UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSpo2() {
|
||||||
|
return spo2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
/* Copyright (C) 2024 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.devices.test.samples;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.test.TestDeviceRand;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
|
||||||
|
|
||||||
|
public class TestStressSampleProvider implements TimeSampleProvider<StressSample> {
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public List<StressSample> getAllSamples(final long timestampFrom, final long timestampTo) {
|
||||||
|
final List<StressSample> samples = new ArrayList<>();
|
||||||
|
|
||||||
|
int stress = TestDeviceRand.randInt(timestampFrom, 10, 90);
|
||||||
|
|
||||||
|
for (long ts = timestampFrom; ts < timestampTo; ts += 15 * 60 * 1000L) {
|
||||||
|
if (TestDeviceRand.randBool(ts, 0.3f)) {
|
||||||
|
samples.add(new TestStressSample(ts, stress));
|
||||||
|
}
|
||||||
|
stress += TestDeviceRand.randInt(ts, (10 - stress) / 10, (90 - stress) / 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSample(final StressSample timeSample) {
|
||||||
|
throw new UnsupportedOperationException("read-only sample provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSamples(final List<StressSample> timeSamples) {
|
||||||
|
throw new UnsupportedOperationException("read-only sample provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StressSample createSample() {
|
||||||
|
throw new UnsupportedOperationException("read-only sample provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public StressSample getLatestSample() {
|
||||||
|
final long ts = System.currentTimeMillis();
|
||||||
|
return new TestStressSample(
|
||||||
|
ts - TestDeviceRand.randLong(ts, 10 * 1000L, 2 * 60 * 60 * 1000L),
|
||||||
|
TestDeviceRand.randInt(ts, 10, 90)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public StressSample getFirstSample() {
|
||||||
|
return new TestStressSample(
|
||||||
|
TestDeviceRand.BASE_TIMESTAMP,
|
||||||
|
TestDeviceRand.randInt(TestDeviceRand.BASE_TIMESTAMP, 10, 90)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class TestStressSample implements StressSample {
|
||||||
|
private final long timestamp;
|
||||||
|
private final int stress;
|
||||||
|
|
||||||
|
public TestStressSample(final long timestamp, final int stress) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.stress = stress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return Type.UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStress() {
|
||||||
|
return stress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
/* Copyright (C) 2024 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.devices.test.samples;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.test.TestDeviceRand;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.TemperatureSample;
|
||||||
|
|
||||||
|
public class TestTemperatureSampleProvider implements TimeSampleProvider<TemperatureSample> {
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public List<TemperatureSample> getAllSamples(final long timestampFrom, final long timestampTo) {
|
||||||
|
// TODO fake samples
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSample(final TemperatureSample timeSample) {
|
||||||
|
throw new UnsupportedOperationException("read-only sample provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSamples(final List<TemperatureSample> timeSamples) {
|
||||||
|
throw new UnsupportedOperationException("read-only sample provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TemperatureSample createSample() {
|
||||||
|
throw new UnsupportedOperationException("read-only sample provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public TemperatureSample getLatestSample() {
|
||||||
|
// TODO
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public TemperatureSample getFirstSample() {
|
||||||
|
return new TestTemperatureSample(
|
||||||
|
TestDeviceRand.BASE_TIMESTAMP,
|
||||||
|
TestDeviceRand.randFloat(TestDeviceRand.BASE_TIMESTAMP, 36f, 38f)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class TestTemperatureSample implements TemperatureSample {
|
||||||
|
private final long timestamp;
|
||||||
|
private final float temperature;
|
||||||
|
|
||||||
|
public TestTemperatureSample(final long timestamp, final float temperature) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.temperature = temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getTemperature() {
|
||||||
|
return temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTemperatureType() {
|
||||||
|
return 0; // ?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
/* Copyright (C) 2024 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.test;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCoordinator;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.test.TestDeviceCoordinator;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.test.TestFeature;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport;
|
||||||
|
|
||||||
|
public class TestDeviceSupport extends AbstractDeviceSupport {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(TestDeviceSupport.class);
|
||||||
|
|
||||||
|
private final Handler handler = new Handler();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean connect() {
|
||||||
|
LOG.info("Connecting");
|
||||||
|
|
||||||
|
getDevice().setState(GBDevice.State.CONNECTING);
|
||||||
|
getDevice().sendDeviceUpdateIntent(getContext());
|
||||||
|
|
||||||
|
handler.postDelayed(() -> {
|
||||||
|
LOG.info("Initialized");
|
||||||
|
|
||||||
|
if (getCoordinator().supportsLedColor()) {
|
||||||
|
getDevice().setExtraInfo("led_color", 0xff3061e3);
|
||||||
|
} else {
|
||||||
|
getDevice().setExtraInfo("led_color", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getCoordinator().supports(getDevice(), TestFeature.FM_FREQUENCY)) {
|
||||||
|
getDevice().setExtraInfo("fm_frequency", 90.2f);
|
||||||
|
} else {
|
||||||
|
getDevice().setExtraInfo("fm_frequency", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO battery percentages
|
||||||
|
// TODO hr measurements
|
||||||
|
// TODO app list
|
||||||
|
// TODO screenshots
|
||||||
|
|
||||||
|
getDevice().setState(GBDevice.State.INITIALIZED);
|
||||||
|
getDevice().sendDeviceUpdateIntent(getContext());
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useAutoConnect() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TestDeviceCoordinator getCoordinator() {
|
||||||
|
return (TestDeviceCoordinator) getDevice().getDeviceCoordinator();
|
||||||
|
}
|
||||||
|
}
|
@ -2679,4 +2679,6 @@
|
|||||||
<string name="pref_force_connection_type_bt_classic_value" translatable="false">BT_CLASSIC</string>
|
<string name="pref_force_connection_type_bt_classic_value" translatable="false">BT_CLASSIC</string>
|
||||||
<string name="activity_info">Activity info</string>
|
<string name="activity_info">Activity info</string>
|
||||||
<string name="warning_missing_notification_permission">Could not post ongoing notification due to missing permission</string>
|
<string name="warning_missing_notification_permission">Could not post ongoing notification due to missing permission</string>
|
||||||
|
<string name="pref_test_features_title">Features</string>
|
||||||
|
<string name="pref_test_features_summary">Enabled features for this test device</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
12
app/src/main/res/xml/devicesettings_test_features.xml
Normal file
12
app/src/main/res/xml/devicesettings_test_features.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- the values will be populated by the TestDeviceSpecificSettingsCustomizer -->
|
||||||
|
<MultiSelectListPreference
|
||||||
|
android:defaultValue="@array/empty_array"
|
||||||
|
android:entries="@array/empty_array"
|
||||||
|
android:entryValues="@array/empty_array"
|
||||||
|
android:icon="@drawable/ic_developer_mode"
|
||||||
|
android:key="test_features"
|
||||||
|
android:summary="@string/pref_test_features_summary"
|
||||||
|
android:title="@string/pref_test_features_title" />
|
||||||
|
</androidx.preference.PreferenceScreen>
|
Loading…
Reference in New Issue
Block a user