mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-28 03:25:49 +01:00
Sony Wena 3: Initial support (#3311)
Co-authored-by: vladkorotnev <vladkorotnev@noreply.codeberg.org> Co-committed-by: vladkorotnev <vladkorotnev@noreply.codeberg.org>
This commit is contained in:
parent
9fe5bc049f
commit
889a1db801
@ -43,7 +43,7 @@ public class GBDaoGenerator {
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
final Schema schema = new Schema(51, MAIN_PACKAGE + ".entities");
|
||||
final Schema schema = new Schema(59, MAIN_PACKAGE + ".entities");
|
||||
|
||||
Entity userAttributes = addUserAttributes(schema);
|
||||
Entity user = addUserInfo(schema, userAttributes);
|
||||
@ -94,12 +94,20 @@ public class GBDaoGenerator {
|
||||
addHybridHRActivitySample(schema, user, device);
|
||||
addVivomoveHrActivitySample(schema, user, device);
|
||||
addGarminFitFile(schema, user, device);
|
||||
addWena3EnergySample(schema, user, device);
|
||||
addWena3BehaviorSample(schema, user, device);
|
||||
addWena3CaloriesSample(schema, user, device);
|
||||
addWena3ActivitySample(schema, user, device);
|
||||
addWena3HeartRateSample(schema, user, device);
|
||||
addWena3Vo2Sample(schema, user, device);
|
||||
addWena3StressSample(schema, user, device);
|
||||
|
||||
addCalendarSyncState(schema, device);
|
||||
addAlarms(schema, user, device);
|
||||
addReminders(schema, user, device);
|
||||
addWorldClocks(schema, user, device);
|
||||
addContacts(schema, user, device);
|
||||
addAppSpecificNotificationSettings(schema, device);
|
||||
|
||||
Entity notificationFilter = addNotificationFilters(schema);
|
||||
|
||||
@ -863,4 +871,71 @@ public class GBDaoGenerator {
|
||||
activitySample.addIntProperty(SAMPLE_RAW_INTENSITY).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||
return activitySample;
|
||||
}
|
||||
|
||||
private static Entity addWena3BehaviorSample(Schema schema, Entity user, Entity device) {
|
||||
Entity activitySample = addEntity(schema, "Wena3BehaviorSample");
|
||||
addCommonTimeSampleProperties("AbstractTimeSample", activitySample, user, device);
|
||||
|
||||
activitySample.addIntProperty(SAMPLE_RAW_KIND).notNull();
|
||||
activitySample.addLongProperty(TIMESTAMP_FROM).notNull();
|
||||
activitySample.addLongProperty(TIMESTAMP_TO).notNull();
|
||||
return activitySample;
|
||||
}
|
||||
|
||||
private static Entity addWena3Vo2Sample(Schema schema, Entity user, Entity device) {
|
||||
Entity activitySample = addEntity(schema, "Wena3Vo2Sample");
|
||||
addCommonTimeSampleProperties("AbstractTimeSample", activitySample, user, device);
|
||||
activitySample.addIntProperty("vo2").notNull();
|
||||
activitySample.addIntProperty("datapoint").notNull().primaryKey();
|
||||
return activitySample;
|
||||
}
|
||||
|
||||
private static Entity addWena3StressSample(Schema schema, Entity user, Entity device) {
|
||||
Entity stressSample = addEntity(schema, "Wena3StressSample");
|
||||
addCommonTimeSampleProperties("AbstractStressSample", stressSample, user, device);
|
||||
stressSample.addIntProperty("typeNum").notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||
stressSample.addIntProperty("stress").notNull().codeBeforeGetter(OVERRIDE);
|
||||
return stressSample;
|
||||
}
|
||||
|
||||
private static Entity addWena3ActivitySample(Schema schema, Entity user, Entity device) {
|
||||
Entity activitySample = addEntity(schema, "Wena3ActivitySample");
|
||||
addCommonActivitySampleProperties("AbstractActivitySample", activitySample, user, device);
|
||||
activitySample.addIntProperty(SAMPLE_STEPS).notNull();
|
||||
activitySample.addIntProperty(SAMPLE_RAW_KIND).notNull().codeBeforeGetter(OVERRIDE);
|
||||
addHeartRateProperties(activitySample);
|
||||
return activitySample;
|
||||
}
|
||||
|
||||
private static Entity addWena3HeartRateSample(Schema schema, Entity user, Entity device) {
|
||||
Entity activitySample = addEntity(schema, "Wena3HeartRateSample");
|
||||
addCommonTimeSampleProperties("AbstractHeartRateSample", activitySample, user, device);
|
||||
activitySample.addIntProperty(SAMPLE_HEART_RATE).notNull();
|
||||
return activitySample;
|
||||
}
|
||||
|
||||
private static Entity addWena3EnergySample(Schema schema, Entity user, Entity device) {
|
||||
Entity activitySample = addEntity(schema, "Wena3EnergySample");
|
||||
addCommonTimeSampleProperties("AbstractTimeSample", activitySample, user, device);
|
||||
activitySample.addIntProperty("energy").notNull();
|
||||
return activitySample;
|
||||
}
|
||||
|
||||
private static Entity addWena3CaloriesSample(Schema schema, Entity user, Entity device) {
|
||||
Entity activitySample = addEntity(schema, "Wena3CaloriesSample");
|
||||
addCommonTimeSampleProperties("AbstractTimeSample", activitySample, user, device);
|
||||
activitySample.addIntProperty("calories").notNull();
|
||||
return activitySample;
|
||||
}
|
||||
|
||||
private static Entity addAppSpecificNotificationSettings(Schema schema, Entity device) {
|
||||
Entity perAppSetting = addEntity(schema, "AppSpecificNotificationSetting");
|
||||
perAppSetting.addStringProperty("packageId").notNull().primaryKey();
|
||||
Property deviceId = perAppSetting.addLongProperty("deviceId").primaryKey().notNull().getProperty();
|
||||
perAppSetting.addToOne(device, deviceId);
|
||||
perAppSetting.addStringProperty("ledPattern");
|
||||
perAppSetting.addStringProperty("vibrationPattern");
|
||||
perAppSetting.addStringProperty("vibrationRepetition");
|
||||
return perAppSetting;
|
||||
}
|
||||
}
|
||||
|
12
README.md
12
README.md
@ -103,11 +103,13 @@ vendor's servers.
|
||||
- PineTime (InfiniTime Firmware)
|
||||
- Roidmi, Roidmi 3, Mojietu 3 (Bluetooth FM Transmitters)
|
||||
- [SMA](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/SMA) Q2 (SMA-Q2-OSS Firmware)
|
||||
- [Sony Headphones](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Sony-Headphones)
|
||||
- LinkBuds S
|
||||
- WH-1000XM2, WH-1000XM3, WH-1000XM4, WH-1000XM5
|
||||
- WF-SP800N
|
||||
- WF-1000XM3, WF-1000XM4
|
||||
- Sony
|
||||
- [Headphones](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Sony-Headphones)
|
||||
- LinkBuds S
|
||||
- WH-1000XM2, WH-1000XM3, WH-1000XM4, WH-1000XM5
|
||||
- WF-SP800N
|
||||
- WF-1000XM3, WF-1000XM4
|
||||
- Wena 3
|
||||
- Teclast H10, H30
|
||||
- TLW64
|
||||
- Vibratissimo (Experimental)
|
||||
|
@ -396,6 +396,22 @@
|
||||
<data android:mimeType="*/*" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:exported="false"
|
||||
android:name=".activities.app_specific_notifications.AppSpecificNotificationSettingsActivity"
|
||||
android:label="@string/prefs_wena3_notification_per_app_settings_title"
|
||||
android:parentActivityName=".activities.devicesettings.DeviceSettingsActivity">
|
||||
<intent-filter>
|
||||
<action android:name=".SonyWena3PerAppNotificationSettingsActivity" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:exported="false"
|
||||
android:name=".activities.app_specific_notifications.AppSpecificNotificationSettingsDetailActivity"
|
||||
android:label="@string/prefs_wena3_notification_per_app_settings_title"
|
||||
android:parentActivityName=".activities.app_specific_notifications.AppSpecificNotificationSettingsActivity"
|
||||
/>
|
||||
|
||||
<service
|
||||
android:name=".externalevents.NotificationListener"
|
||||
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.app_specific_notifications;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.AppSpecificNotificationSettingsAppListAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
public class AppSpecificNotificationSettingsActivity extends AbstractGBActivity {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AppSpecificNotificationSettingsActivity.class);
|
||||
|
||||
private AppSpecificNotificationSettingsAppListAdapter appListAdapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_app_specific_notification_settings);
|
||||
RecyclerView appListView = findViewById(R.id.appListView);
|
||||
appListView.setLayoutManager(new LinearLayoutManager(this));
|
||||
|
||||
GBDevice device = getIntent().getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||
appListAdapter = new AppSpecificNotificationSettingsAppListAdapter(R.layout.item_app_specific_notification_app_list, this, device);
|
||||
|
||||
appListView.setAdapter(appListAdapter);
|
||||
|
||||
SearchView searchView = findViewById(R.id.appListViewSearch);
|
||||
searchView.setIconifiedByDefault(false);
|
||||
searchView.setIconified(false);
|
||||
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
appListAdapter.getFilter().filter(newText);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.app_specific_notifications;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.AppSpecificNotificationSettingsAppListAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.AppSpecificNotificationSettingsRepository;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.AppSpecificNotificationSetting;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.AbstractNotificationPattern;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||
|
||||
public class AppSpecificNotificationSettingsDetailActivity extends AbstractGBActivity {
|
||||
private AppSpecificNotificationSettingsRepository repository = null;
|
||||
private String bundleId = null;
|
||||
|
||||
private GBDevice mDevice;
|
||||
private DeviceCoordinator mCoordinator;
|
||||
|
||||
private List<String> mLedPatternValues = new ArrayList<>();
|
||||
private List<String> mVibrationPatternValues = new ArrayList<>();
|
||||
private List<String> mVibrationCountValues = new ArrayList<>();
|
||||
|
||||
private Spinner mSpinnerLedPattern;
|
||||
private Spinner mSpinnerVibrationPattern;
|
||||
private Spinner mSpinnerVibrationCount;
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_notification_per_app_setting_detail);
|
||||
Button mButtonSave = findViewById(R.id.buttonSaveSettings);
|
||||
Button mButtonDelete = findViewById(R.id.buttonDeleteSettings);
|
||||
mSpinnerLedPattern = findViewById(R.id.spinnerLedType);
|
||||
mSpinnerVibrationPattern = findViewById(R.id.spinnerVibraType);
|
||||
mSpinnerVibrationCount = findViewById(R.id.spinnerVibraCount);
|
||||
|
||||
mDevice = getIntent().getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||
mCoordinator = DeviceHelper.getInstance().getCoordinator(mDevice);
|
||||
|
||||
mLedPatternValues.clear();
|
||||
for(AbstractNotificationPattern p: mCoordinator.getNotificationLedPatterns())
|
||||
mLedPatternValues.add(p.getValue());
|
||||
|
||||
mVibrationPatternValues.clear();
|
||||
for(AbstractNotificationPattern p: mCoordinator.getNotificationVibrationPatterns())
|
||||
mVibrationPatternValues.add(p.getValue());
|
||||
|
||||
mVibrationCountValues.clear();
|
||||
for(AbstractNotificationPattern p: mCoordinator.getNotificationVibrationRepetitionPatterns())
|
||||
mVibrationCountValues.add(p.getValue());
|
||||
|
||||
if(!mCoordinator.supportsNotificationLedPatterns()) {
|
||||
mSpinnerLedPattern.setEnabled(false);
|
||||
} else {
|
||||
mSpinnerLedPattern.setAdapter(
|
||||
createAdapterFromArrayAddingDefault(mCoordinator.getNotificationLedPatterns())
|
||||
);
|
||||
}
|
||||
|
||||
if(!mCoordinator.supportsNotificationVibrationPatterns()) {
|
||||
mSpinnerVibrationPattern.setEnabled(false);
|
||||
} else {
|
||||
mSpinnerVibrationPattern.setAdapter(
|
||||
createAdapterFromArrayAddingDefault(mCoordinator.getNotificationVibrationPatterns())
|
||||
);
|
||||
}
|
||||
|
||||
if(!mCoordinator.supportsNotificationVibrationRepetitionPatterns()) {
|
||||
mSpinnerVibrationCount.setEnabled(false);
|
||||
} else {
|
||||
mSpinnerVibrationCount.setAdapter(
|
||||
createAdapterFromArrayAddingDefault(mCoordinator.getNotificationVibrationRepetitionPatterns())
|
||||
);
|
||||
}
|
||||
|
||||
String title = getIntent().getStringExtra(AppSpecificNotificationSettingsAppListAdapter.STRING_EXTRA_PACKAGE_TITLE);
|
||||
setTitle(title);
|
||||
bundleId = getIntent().getStringExtra(AppSpecificNotificationSettingsAppListAdapter.STRING_EXTRA_PACKAGE_NAME);
|
||||
|
||||
repository = new AppSpecificNotificationSettingsRepository(mDevice);
|
||||
mButtonDelete.setOnClickListener(view -> {
|
||||
repository.setSettingsForAppId(bundleId, null);
|
||||
finish();
|
||||
});
|
||||
|
||||
mButtonSave.setOnClickListener(view -> {
|
||||
saveSettings();
|
||||
finish();
|
||||
});
|
||||
|
||||
AppSpecificNotificationSetting setting = repository.getSettingsForAppId(bundleId);
|
||||
if(setting != null) {
|
||||
if(setting.getLedPattern() != null) {
|
||||
int idx = mLedPatternValues.indexOf(setting.getLedPattern());
|
||||
if(idx >= 0) {
|
||||
mSpinnerLedPattern.setSelection(idx + 1);
|
||||
}
|
||||
} else {
|
||||
mSpinnerLedPattern.setSelection(0);
|
||||
}
|
||||
|
||||
if(setting.getVibrationPattern() != null) {
|
||||
int idx = mVibrationPatternValues.indexOf(setting.getVibrationPattern());
|
||||
if(idx >= 0) {
|
||||
mSpinnerVibrationPattern.setSelection(idx + 1);
|
||||
}
|
||||
} else {
|
||||
mSpinnerVibrationPattern.setSelection(0);
|
||||
}
|
||||
|
||||
if(setting.getVibrationRepetition() != null) {
|
||||
int idx = mVibrationCountValues.indexOf(setting.getVibrationRepetition());
|
||||
if(idx >= 0) {
|
||||
mSpinnerVibrationCount.setSelection(idx + 1);
|
||||
}
|
||||
} else {
|
||||
mSpinnerVibrationCount.setSelection(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayAdapter<String> createAdapterFromArrayAddingDefault(AbstractNotificationPattern[] array) {
|
||||
List<String> allOptions = new ArrayList<>();
|
||||
allOptions.add(getString(R.string.pref_default));
|
||||
for(AbstractNotificationPattern s: array) allOptions.add(s.getUserReadableName(getApplicationContext()));
|
||||
|
||||
return new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, allOptions);
|
||||
}
|
||||
|
||||
private void saveSettings() {
|
||||
String led = null;
|
||||
String vibra = null;
|
||||
String vibraTimes = null;
|
||||
|
||||
if(mSpinnerLedPattern.getSelectedItemPosition() > 0) {
|
||||
led = mLedPatternValues.get(mSpinnerLedPattern.getSelectedItemPosition() - 1);
|
||||
}
|
||||
|
||||
if(mSpinnerVibrationPattern.getSelectedItemPosition() > 0) {
|
||||
vibra = mVibrationPatternValues.get(mSpinnerVibrationPattern.getSelectedItemPosition() - 1);
|
||||
}
|
||||
|
||||
if(mSpinnerVibrationCount.getSelectedItemPosition() > 0) {
|
||||
vibraTimes = mVibrationCountValues.get(mSpinnerVibrationCount.getSelectedItemPosition() - 1);
|
||||
}
|
||||
|
||||
AppSpecificNotificationSetting setting = new AppSpecificNotificationSetting(
|
||||
bundleId,
|
||||
0,
|
||||
led,
|
||||
vibra,
|
||||
vibraTimes
|
||||
);
|
||||
repository.setSettingsForAppId(bundleId, setting);
|
||||
}
|
||||
}
|
@ -342,6 +342,7 @@ public class DeviceSettingsPreferenceConst {
|
||||
public static final String PREFS_ACTIVITY_IN_DEVICE_CARD_SLEEP = "prefs_activity_in_device_card_sleep";
|
||||
public static final String PREFS_ACTIVITY_IN_DEVICE_CARD_DISTANCE = "prefs_activity_in_device_card_distance";
|
||||
public static final String PREFS_DEVICE_CHARTS_TABS = "charts_tabs";
|
||||
public static final String PREFS_PER_APP_NOTIFICATION_SETTINGS = "pref_per_app_notification_settings";
|
||||
|
||||
public static final String PREF_UM25_SHOW_THRESHOLD_NOTIFICATION = "um25_current_threshold_notify";
|
||||
public static final String PREF_UM25_SHOW_THRESHOLD = "um25_current_threshold";
|
||||
|
@ -41,6 +41,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.CalBlacklistActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureContacts;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureWorldClocks;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractPreferenceFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.app_specific_notifications.AppSpecificNotificationSettingsActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.loyaltycards.LoyaltyCardsSettingsActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.loyaltycards.LoyaltyCardsSettingsConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.capabilities.HeartRateCapability;
|
||||
@ -49,6 +50,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3SettingKeys;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||
@ -407,6 +409,8 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
|
||||
addPreferenceHandlerFor(PREF_AMPM_ENABLED);
|
||||
addPreferenceHandlerFor(PREF_SOUNDS);
|
||||
addPreferenceHandlerFor(PREF_CAMERA_REMOTE);
|
||||
addPreferenceHandlerFor(PREF_SCREEN_LIFT_WRIST);
|
||||
addPreferenceHandlerFor(PREF_SYNC_CALENDAR);
|
||||
|
||||
addPreferenceHandlerFor(PREF_BLUETOOTH_CALLS_ENABLED);
|
||||
addPreferenceHandlerFor(PREF_DISPLAY_CALLER);
|
||||
@ -900,6 +904,16 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
|
||||
});
|
||||
}
|
||||
|
||||
final Preference notificationSettings = findPreference(PREFS_PER_APP_NOTIFICATION_SETTINGS);
|
||||
if(notificationSettings != null) {
|
||||
notificationSettings.setOnPreferenceClickListener(preference -> {
|
||||
final Intent intent = new Intent(getContext(), AppSpecificNotificationSettingsActivity.class);
|
||||
intent.putExtra(GBDevice.EXTRA_DEVICE, getDevice());
|
||||
startActivity(intent);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (deviceSpecificSettingsCustomizer != null) {
|
||||
deviceSpecificSettingsCustomizer.customizeSettings(this, prefs);
|
||||
}
|
||||
|
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package nodomain.freeyourgadget.gadgetbridge.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.LauncherActivityInfo;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Filter;
|
||||
import android.widget.Filterable;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.app_specific_notifications.AppSpecificNotificationSettingsDetailActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.GBApplication.packageNameToPebbleMsgSender;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class AppSpecificNotificationSettingsAppListAdapter extends RecyclerView.Adapter<AppSpecificNotificationSettingsAppListAdapter.AppNotificationSettingsViewHolder> implements Filterable {
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(AppSpecificNotificationSettingsAppListAdapter.class);
|
||||
|
||||
public static final String STRING_EXTRA_PACKAGE_NAME = "packageName";
|
||||
public static final String STRING_EXTRA_PACKAGE_TITLE = "packageTitle";
|
||||
|
||||
private final List<ApplicationInfo> applicationInfoList;
|
||||
private final int mLayoutId;
|
||||
private final Context mContext;
|
||||
private final PackageManager mPm;
|
||||
private GBDevice mDevice;
|
||||
private final IdentityHashMap<ApplicationInfo, String> mNameMap;
|
||||
|
||||
private ApplicationFilter applicationFilter;
|
||||
|
||||
public AppSpecificNotificationSettingsAppListAdapter(int layoutId, Context context, GBDevice device) {
|
||||
mLayoutId = layoutId;
|
||||
mContext = context;
|
||||
mPm = context.getPackageManager();
|
||||
mDevice = device;
|
||||
|
||||
applicationInfoList = getAllApplications();
|
||||
|
||||
|
||||
// sort the package list by label and blacklist status
|
||||
mNameMap = new IdentityHashMap<>(applicationInfoList.size());
|
||||
for (ApplicationInfo ai : applicationInfoList) {
|
||||
CharSequence name = mPm.getApplicationLabel(ai);
|
||||
if (name == null) {
|
||||
name = ai.packageName;
|
||||
}
|
||||
mNameMap.put(ai, name.toString());
|
||||
}
|
||||
|
||||
Collections.sort(applicationInfoList, (ai1, ai2) -> {
|
||||
final String s1 = mNameMap.get(ai1);
|
||||
final String s2 = mNameMap.get(ai2);
|
||||
return s1.compareToIgnoreCase(s2);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppNotificationSettingsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(mContext).inflate(mLayoutId, parent, false);
|
||||
return new AppNotificationSettingsViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final AppNotificationSettingsViewHolder holder, int position) {
|
||||
final ApplicationInfo appInfo = applicationInfoList.get(position);
|
||||
|
||||
holder.deviceAppVersionAuthorLabel.setText(appInfo.packageName);
|
||||
holder.deviceAppNameLabel.setText(mNameMap.get(appInfo));
|
||||
holder.deviceImageView.setImageDrawable(appInfo.loadIcon(mPm));
|
||||
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
Intent intentStartNotificationFilterActivity = new Intent(mContext, AppSpecificNotificationSettingsDetailActivity.class);
|
||||
intentStartNotificationFilterActivity.putExtra(STRING_EXTRA_PACKAGE_NAME, appInfo.packageName);
|
||||
intentStartNotificationFilterActivity.putExtra(STRING_EXTRA_PACKAGE_TITLE, mNameMap.get(appInfo));
|
||||
intentStartNotificationFilterActivity.putExtra(GBDevice.EXTRA_DEVICE, mDevice);
|
||||
mContext.startActivity(intentStartNotificationFilterActivity);
|
||||
});
|
||||
|
||||
holder.btnConfigureApp.setOnClickListener(view -> {
|
||||
Intent intentStartNotificationFilterActivity = new Intent(mContext, AppSpecificNotificationSettingsDetailActivity.class);
|
||||
intentStartNotificationFilterActivity.putExtra(STRING_EXTRA_PACKAGE_NAME, appInfo.packageName);
|
||||
intentStartNotificationFilterActivity.putExtra(STRING_EXTRA_PACKAGE_TITLE, mNameMap.get(appInfo));
|
||||
intentStartNotificationFilterActivity.putExtra(GBDevice.EXTRA_DEVICE, mDevice);
|
||||
mContext.startActivity(intentStartNotificationFilterActivity);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the applications for which the Gadgetbridge notifications are enabled.
|
||||
*/
|
||||
public List<ApplicationInfo> getAllApplications() {
|
||||
final Set<String> allPackageNames = new HashSet<>();
|
||||
final List<ApplicationInfo> ret = new LinkedList<>();
|
||||
boolean filterInverted = !GBApplication.getPrefs().getString("notification_list_is_blacklist", "true").equals("true");
|
||||
|
||||
// Get apps for the current user
|
||||
final List<ApplicationInfo> currentUserApps = mPm.getInstalledApplications(PackageManager.GET_META_DATA);
|
||||
for (final ApplicationInfo app : currentUserApps) {
|
||||
boolean blacklisted = GBApplication.appIsNotifBlacklisted(app.packageName) || GBApplication.appIsPebbleBlacklisted(packageNameToPebbleMsgSender(app.packageName));
|
||||
if((!filterInverted && !blacklisted) || (filterInverted && blacklisted)) {
|
||||
allPackageNames.add(app.packageName);
|
||||
ret.add(app);
|
||||
}
|
||||
}
|
||||
|
||||
// Add all apps from other users (eg. manager profile)
|
||||
try {
|
||||
final UserHandle currentUser = Process.myUserHandle();
|
||||
final LauncherApps launcher = (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
|
||||
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
|
||||
final List<UserHandle> userProfiles = um.getUserProfiles();
|
||||
for (final UserHandle userProfile : userProfiles) {
|
||||
if (userProfile.equals(currentUser)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final List<LauncherActivityInfo> userActivityList = launcher.getActivityList(null, userProfile);
|
||||
|
||||
for (final LauncherActivityInfo app : userActivityList) {
|
||||
if (!allPackageNames.contains(app.getApplicationInfo().packageName)) {
|
||||
boolean blacklisted = GBApplication.appIsNotifBlacklisted(app.getApplicationInfo().packageName) || GBApplication.appIsPebbleBlacklisted(packageNameToPebbleMsgSender(app.getApplicationInfo().packageName));
|
||||
if((!filterInverted && !blacklisted) || (filterInverted && blacklisted)) {
|
||||
allPackageNames.add(app.getApplicationInfo().packageName);
|
||||
ret.add(app.getApplicationInfo());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
LOG.error("Failed to get apps from other users", e);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return applicationInfoList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter getFilter() {
|
||||
if (applicationFilter == null)
|
||||
applicationFilter = new ApplicationFilter(this, applicationInfoList);
|
||||
return applicationFilter;
|
||||
}
|
||||
|
||||
class AppNotificationSettingsViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
final ImageView deviceImageView;
|
||||
final TextView deviceAppVersionAuthorLabel;
|
||||
final TextView deviceAppNameLabel;
|
||||
final ImageView btnConfigureApp;
|
||||
|
||||
AppNotificationSettingsViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
deviceImageView = itemView.findViewById(R.id.item_image);
|
||||
deviceAppVersionAuthorLabel = itemView.findViewById(R.id.item_details);
|
||||
deviceAppNameLabel = itemView.findViewById(R.id.item_name);
|
||||
btnConfigureApp = itemView.findViewById(R.id.btn_configureApp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ApplicationFilter extends Filter {
|
||||
|
||||
private final AppSpecificNotificationSettingsAppListAdapter adapter;
|
||||
private final List<ApplicationInfo> originalList;
|
||||
private final List<ApplicationInfo> filteredList;
|
||||
|
||||
private ApplicationFilter(AppSpecificNotificationSettingsAppListAdapter adapter, List<ApplicationInfo> originalList) {
|
||||
super();
|
||||
this.originalList = new ArrayList<>(originalList);
|
||||
this.filteredList = new ArrayList<>();
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Filter.FilterResults performFiltering(CharSequence filter) {
|
||||
filteredList.clear();
|
||||
final Filter.FilterResults results = new Filter.FilterResults();
|
||||
|
||||
if (filter == null || filter.length() == 0)
|
||||
filteredList.addAll(originalList);
|
||||
else {
|
||||
final String filterPattern = filter.toString().toLowerCase().trim();
|
||||
|
||||
for (ApplicationInfo ai : originalList) {
|
||||
CharSequence name = mPm.getApplicationLabel(ai);
|
||||
if (name.toString().toLowerCase().contains(filterPattern) ||
|
||||
(ai.packageName.contains(filterPattern))) {
|
||||
filteredList.add(ai);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
results.values = filteredList;
|
||||
results.count = filteredList.size();
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void publishResults(CharSequence charSequence, Filter.FilterResults filterResults) {
|
||||
adapter.applicationInfoList.clear();
|
||||
adapter.applicationInfoList.addAll((List<ApplicationInfo>) filterResults.values);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.database;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import de.greenrobot.dao.query.QueryBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.AppSpecificNotificationSettingDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.AppSpecificNotificationSetting;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
// TODO: Distinguish by device ID as well to allow for different settings per device.
|
||||
// I didn't know how to get a device ID from a settings activity, so I left it as is.
|
||||
public class AppSpecificNotificationSettingsRepository {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AppSpecificNotificationSettingsRepository.class);
|
||||
private GBDevice mGbDevice;
|
||||
public AppSpecificNotificationSettingsRepository(GBDevice gbDevice) {
|
||||
mGbDevice = gbDevice;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public AppSpecificNotificationSetting getSettingsForAppId(String appId) {
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
DaoSession session = db.getDaoSession();
|
||||
QueryBuilder<AppSpecificNotificationSetting> qb = session.getAppSpecificNotificationSettingDao().queryBuilder();
|
||||
return qb.where(
|
||||
qb.and(AppSpecificNotificationSettingDao.Properties.PackageId.eq(appId),
|
||||
AppSpecificNotificationSettingDao.Properties.DeviceId.eq(DBHelper.findDevice(mGbDevice, session).getId())
|
||||
)).build().unique();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to get DB handle", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void deleteForAppId(@NonNull String appId) {
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
DaoSession session = db.getDaoSession();
|
||||
QueryBuilder<AppSpecificNotificationSetting> qb = session.getAppSpecificNotificationSettingDao().queryBuilder();
|
||||
qb.where(
|
||||
qb.and(AppSpecificNotificationSettingDao.Properties.PackageId.eq(appId),
|
||||
AppSpecificNotificationSettingDao.Properties.DeviceId.eq(DBHelper.findDevice(mGbDevice, session).getId())
|
||||
)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to get DB handle", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSettingsForAppId(@NonNull String appId, @Nullable AppSpecificNotificationSetting settings) {
|
||||
if (settings == null) {
|
||||
deleteForAppId(appId);
|
||||
} else {
|
||||
settings.setPackageId(appId);
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
DaoSession session = db.getDaoSession();
|
||||
Device dbDevice = DBHelper.findDevice(mGbDevice, session);
|
||||
settings.setDeviceId(dbDevice.getId());
|
||||
session.getAppSpecificNotificationSettingDao().insertOrReplace(settings);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to get DB handle", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -57,6 +57,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DeviceAttributesDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.AbstractNotificationPattern;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.HeartRateSample;
|
||||
@ -472,4 +473,28 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
|
||||
public EnumSet<ServiceDeviceSupport.Flags> getInitialFlags() {
|
||||
return EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING);
|
||||
}
|
||||
|
||||
public boolean supportsNotificationVibrationPatterns() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean supportsNotificationVibrationRepetitionPatterns() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean supportsNotificationLedPatterns() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public AbstractNotificationPattern[] getNotificationVibrationPatterns() {
|
||||
return new AbstractNotificationPattern[0];
|
||||
}
|
||||
|
||||
public AbstractNotificationPattern[] getNotificationVibrationRepetitionPatterns() {
|
||||
return new AbstractNotificationPattern[0];
|
||||
}
|
||||
|
||||
public AbstractNotificationPattern[] getNotificationLedPatterns() {
|
||||
return new AbstractNotificationPattern[0];
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import nodomain.freeyourgadget.gadgetbridge.capabilities.password.PasswordCapabi
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.AbstractNotificationPattern;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
|
||||
@ -563,4 +564,32 @@ public interface DeviceCoordinator {
|
||||
Class<? extends DeviceSupport> getDeviceSupportClass();
|
||||
|
||||
EnumSet<ServiceDeviceSupport.Flags> getInitialFlags();
|
||||
|
||||
/**
|
||||
* Whether the device supports a variety of vibration patterns for notifications.
|
||||
*/
|
||||
boolean supportsNotificationVibrationPatterns();
|
||||
/**
|
||||
* Whether the device supports a variety of vibration pattern repetitions for notifications.
|
||||
*/
|
||||
boolean supportsNotificationVibrationRepetitionPatterns();
|
||||
|
||||
/**
|
||||
* Whether the device supports a variety of LED patterns for notifications.
|
||||
*/
|
||||
boolean supportsNotificationLedPatterns();
|
||||
/**
|
||||
* What vibration pattern repetitions for notifications are supported by the device.
|
||||
*/
|
||||
AbstractNotificationPattern[] getNotificationVibrationPatterns();
|
||||
/**
|
||||
* What vibration pattern repetitions for notifications are supported by the device.
|
||||
* Technote: this is not an int or a range because some devices (e.g. Wena 3) only allow
|
||||
* a very specific set of value combinations here.
|
||||
*/
|
||||
AbstractNotificationPattern[] getNotificationVibrationRepetitionPatterns();
|
||||
/**
|
||||
* What LED patterns for notifications are supported by the device.
|
||||
*/
|
||||
AbstractNotificationPattern[] getNotificationLedPatterns();
|
||||
}
|
||||
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3BehaviorSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3HeartRateSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.HeartRateSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity.BehaviorSample;
|
||||
|
||||
// The sole purpose of this part of code is to take the Behavior samples
|
||||
// and drop them onto Steps samples (which are just your average activity data with the current
|
||||
// architecture of Gadgetbridge)
|
||||
public class SonyWena3ActivitySampleCombiner {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SonyWena3ActivitySampleCombiner.class);
|
||||
final SonyWena3ActivitySampleProvider activitySampleProvider;
|
||||
|
||||
public SonyWena3ActivitySampleCombiner(SonyWena3ActivitySampleProvider activitySampleProvider) {
|
||||
this.activitySampleProvider = activitySampleProvider;
|
||||
}
|
||||
|
||||
public void overlayBehaviorStartingAt(Date startDate, SonyWena3BehaviorSampleProvider behaviorSampleProvider) {
|
||||
List<Wena3BehaviorSample> behaviorSamples = behaviorSampleProvider.getAllSamples(startDate.getTime(), Long.MAX_VALUE);
|
||||
List<Wena3ActivitySample> alteredSamples = new ArrayList<>();
|
||||
for(Wena3BehaviorSample behaviorSample: behaviorSamples) {
|
||||
List<Wena3ActivitySample> activitySamplesForThisRange = activitySampleProvider.getAllActivitySamples((int)(behaviorSample.getTimestampFrom() / 1000L), (int)(behaviorSample.getTimestampTo() / 1000L));
|
||||
|
||||
LOG.debug("Changing " + activitySamplesForThisRange.size() + " samples to behavior type: " + BehaviorSample.Type.LUT[behaviorSample.getRawKind()].name());
|
||||
for(Wena3ActivitySample activitySample: activitySamplesForThisRange) {
|
||||
activitySample.setRawKind(behaviorSample.getRawKind());
|
||||
alteredSamples.add(activitySample);
|
||||
}
|
||||
}
|
||||
activitySampleProvider.addGBActivitySamples(alteredSamples.toArray(new Wena3ActivitySample[alteredSamples.size()]));
|
||||
}
|
||||
|
||||
public void overlayHeartRateStartingAt(Date startDate, SonyWena3HeartRateSampleProvider heartRateSampleProvider) {
|
||||
List<Wena3HeartRateSample> heartRateSamples = heartRateSampleProvider.getAllSamples(startDate.getTime(), Long.MAX_VALUE);
|
||||
List<Wena3ActivitySample> alteredSamples = new ArrayList<>();
|
||||
for(int i = 0; i < heartRateSamples.size(); i++) {
|
||||
HeartRateSample currentSample = heartRateSamples.get(i);
|
||||
HeartRateSample nextSample = (i == heartRateSamples.size() - 1) ? null : heartRateSamples.get(i + 1);
|
||||
|
||||
List<Wena3ActivitySample> activitySamplesInRange = activitySampleProvider.getAllActivitySamples(
|
||||
(int) (currentSample.getTimestamp() / 1000L),
|
||||
(nextSample == null ? Integer.MAX_VALUE : ((int) (nextSample.getTimestamp() / 1000L)))
|
||||
);
|
||||
|
||||
LOG.debug("Changing " + activitySamplesInRange.size() + " samples to heart rate: " + currentSample.getHeartRate());
|
||||
for(Wena3ActivitySample activitySample: activitySamplesInRange) {
|
||||
activitySample.setHeartRate(currentSample.getHeartRate());
|
||||
alteredSamples.add(activitySample);
|
||||
}
|
||||
}
|
||||
activitySampleProvider.addGBActivitySamples(alteredSamples.toArray(new Wena3ActivitySample[alteredSamples.size()]));
|
||||
}
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import de.greenrobot.dao.AbstractDao;
|
||||
import de.greenrobot.dao.Property;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3ActivitySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity.BehaviorSample;
|
||||
|
||||
public class SonyWena3ActivitySampleProvider extends AbstractSampleProvider<Wena3ActivitySample> {
|
||||
public SonyWena3ActivitySampleProvider(GBDevice device, DaoSession session) {
|
||||
super(device, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractDao<Wena3ActivitySample, ?> getSampleDao() {
|
||||
return getSession().getWena3ActivitySampleDao();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected Property getRawKindSampleProperty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getTimestampSampleProperty() {
|
||||
return Wena3ActivitySampleDao.Properties.Timestamp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getDeviceIdentifierSampleProperty() {
|
||||
return Wena3ActivitySampleDao.Properties.DeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int normalizeType(int rawType) {
|
||||
if(rawType < 0 || rawType >= BehaviorSample.Type.LUT.length) return ActivityKind.TYPE_UNKNOWN;
|
||||
|
||||
BehaviorSample.Type internalType = BehaviorSample.Type.LUT[rawType];
|
||||
switch(internalType) {
|
||||
case NOT_WEARING:
|
||||
return ActivityKind.TYPE_NOT_WORN;
|
||||
|
||||
case WALK:
|
||||
return ActivityKind.TYPE_WALKING;
|
||||
case RUN:
|
||||
return ActivityKind.TYPE_RUNNING;
|
||||
case EXERCISE:
|
||||
return ActivityKind.TYPE_EXERCISE;
|
||||
|
||||
case SLEEP_LIGHT:
|
||||
return ActivityKind.TYPE_LIGHT_SLEEP;
|
||||
case SLEEP_REM:
|
||||
return ActivityKind.TYPE_REM_SLEEP;
|
||||
case SLEEP_DEEP:
|
||||
return ActivityKind.TYPE_DEEP_SLEEP;
|
||||
|
||||
case STATIC:
|
||||
case SLEEP_AWAKE:
|
||||
case UNKNOWN:
|
||||
default:
|
||||
return ActivityKind.TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int toRawActivityKind(int activityKind) {
|
||||
switch(activityKind) {
|
||||
case ActivityKind.TYPE_NOT_MEASURED:
|
||||
case ActivityKind.TYPE_NOT_WORN:
|
||||
return BehaviorSample.Type.NOT_WEARING.ordinal();
|
||||
case ActivityKind.TYPE_WALKING:
|
||||
return BehaviorSample.Type.WALK.ordinal();
|
||||
case ActivityKind.TYPE_RUNNING:
|
||||
return BehaviorSample.Type.RUN.ordinal();
|
||||
case ActivityKind.TYPE_LIGHT_SLEEP:
|
||||
return BehaviorSample.Type.SLEEP_LIGHT.ordinal();
|
||||
case ActivityKind.TYPE_REM_SLEEP:
|
||||
return BehaviorSample.Type.SLEEP_REM.ordinal();
|
||||
case ActivityKind.TYPE_DEEP_SLEEP:
|
||||
return BehaviorSample.Type.SLEEP_DEEP.ordinal();
|
||||
case ActivityKind.TYPE_EXERCISE:
|
||||
return BehaviorSample.Type.EXERCISE.ordinal();
|
||||
default:
|
||||
return BehaviorSample.Type.UNKNOWN.ordinal();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float normalizeIntensity(int rawIntensity) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wena3ActivitySample createActivitySample() {
|
||||
return new Wena3ActivitySample();
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import de.greenrobot.dao.AbstractDao;
|
||||
import de.greenrobot.dao.Property;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractTimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3BehaviorSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3BehaviorSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
public class SonyWena3BehaviorSampleProvider extends AbstractTimeSampleProvider<Wena3BehaviorSample> {
|
||||
public SonyWena3BehaviorSampleProvider(final GBDevice device, final DaoSession session) {
|
||||
super(device, session);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AbstractDao<Wena3BehaviorSample, ?> getSampleDao() {
|
||||
return getSession().getWena3BehaviorSampleDao();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getTimestampSampleProperty() {
|
||||
return Wena3BehaviorSampleDao.Properties.Timestamp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getDeviceIdentifierSampleProperty() {
|
||||
return Wena3BehaviorSampleDao.Properties.DeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wena3BehaviorSample createSample() {
|
||||
return new Wena3BehaviorSample();
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import de.greenrobot.dao.AbstractDao;
|
||||
import de.greenrobot.dao.Property;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractTimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3CaloriesSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3CaloriesSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
public class SonyWena3CaloriesSampleProvider extends AbstractTimeSampleProvider<Wena3CaloriesSample> {
|
||||
public SonyWena3CaloriesSampleProvider(final GBDevice device, final DaoSession session) {
|
||||
super(device, session);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AbstractDao<Wena3CaloriesSample, ?> getSampleDao() {
|
||||
return getSession().getWena3CaloriesSampleDao();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getTimestampSampleProperty() {
|
||||
return Wena3CaloriesSampleDao.Properties.Timestamp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getDeviceIdentifierSampleProperty() {
|
||||
return Wena3CaloriesSampleDao.Properties.DeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wena3CaloriesSample createSample() {
|
||||
return new Wena3CaloriesSample();
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class SonyWena3Constants {
|
||||
public static final String BT_DEVICE_NAME = "WNW-21A";
|
||||
private static final String uuidTemplate = "4EFD%s-A6C1-16F0-062F-F196CF496695";
|
||||
|
||||
public static final UUID COMMON_SERVICE_UUID = UUID.fromString(String.format(uuidTemplate, "1501"));
|
||||
public static final UUID COMMON_SERVICE_CHARACTERISTIC_MODE_UUID = UUID.fromString(String.format(uuidTemplate, "1503"));
|
||||
public static final UUID COMMON_SERVICE_CHARACTERISTIC_CONTROL_UUID = UUID.fromString(String.format(uuidTemplate, "1514"));
|
||||
public static final UUID COMMON_SERVICE_CHARACTERISTIC_INFO_UUID = UUID.fromString(String.format(uuidTemplate, "1520"));
|
||||
public static final UUID COMMON_SERVICE_CHARACTERISTIC_STATE_UUID = UUID.fromString(String.format(uuidTemplate, "1521"));
|
||||
|
||||
public static final UUID NOTIFICATION_SERVICE_UUID = UUID.fromString(String.format(uuidTemplate, "4001"));
|
||||
public static final UUID NOTIFICATION_SERVICE_CHARACTERISTIC_UUID = UUID.fromString(String.format(uuidTemplate, "4002"));
|
||||
|
||||
public static final UUID ACTIVITY_LOG_SERVICE_UUID = UUID.fromString(String.format(uuidTemplate, "3001"));
|
||||
public static final UUID ACTIVITY_LOG_CHARACTERISTIC_UUID = UUID.fromString(String.format(uuidTemplate, "3002"));
|
||||
|
||||
|
||||
public static int[] LED_PRESETS = {
|
||||
Color.rgb(255, 0, 0),
|
||||
Color.rgb(255, 255, 0),
|
||||
Color.rgb(0, 255, 0),
|
||||
Color.rgb(0, 255, 255),
|
||||
Color.rgb(0, 0, 255),
|
||||
Color.rgb(255, 0, 255),
|
||||
Color.rgb(255, 255, 255)
|
||||
};
|
||||
|
||||
public static final long EPOCH_START = 1577836800000L;
|
||||
|
||||
public static final int ALARM_SLOTS = 9;
|
||||
public static final int ALARM_DEFAULT_SMART_WAKEUP_MARGIN_MINUTES = 10;
|
||||
|
||||
public static final String DB_FIELD_VO2_DATAPOINT_NUMBER = "datapoint";
|
||||
public static final String DB_FIELD_VO2_VALUE = "vo2";
|
||||
public static final String DB_FIELD_STRESS = "stress";
|
||||
public static final String DB_FIELD_STEPS = "steps";
|
||||
public static final String DB_FIELD_HEART_RATE = "heartRate";
|
||||
public static final String DB_FIELD_ENERGY = "energy";
|
||||
public static final String DB_FIELD_CALORIES = "calories";
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,302 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.le.ScanFilter;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import de.greenrobot.dao.query.QueryBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3ActivitySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3BehaviorSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3CaloriesSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3EnergySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3HeartRateSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3StressSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3Vo2SampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.AbstractNotificationPattern;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.HeartRateSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.SonyWena3DeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines.LedColor;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines.VibrationCount;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines.VibrationKind;
|
||||
|
||||
public class SonyWena3Coordinator extends AbstractBLEDeviceCoordinator {
|
||||
@Override
|
||||
public DeviceType getDeviceType() {
|
||||
return DeviceType.SONY_WENA_3;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Class<? extends Activity> getPairingActivity() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getManufacturer() {
|
||||
return "Sony";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsAppsManagement(GBDevice device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Activity> getAppsManagementActivity() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Class<? extends DeviceSupport> getDeviceSupportClass() {
|
||||
return SonyWena3DeviceSupport.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceSpecificSettingsCustomizer getDeviceSpecificSettingsCustomizer(GBDevice device) {
|
||||
return new SonyWena3SettingsCustomizer();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Collection<? extends ScanFilter> createBLEScanFilters() {
|
||||
ScanFilter.Builder builder = new ScanFilter.Builder();
|
||||
builder.setDeviceName(SonyWena3Constants.BT_DEVICE_NAME);
|
||||
ArrayList<ScanFilter> result = new ArrayList<>();
|
||||
result.add(builder.build());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) {
|
||||
Long deviceId = device.getId();
|
||||
QueryBuilder<?> qb;
|
||||
|
||||
qb = session.getWena3HeartRateSampleDao().queryBuilder();
|
||||
qb.where(Wena3HeartRateSampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
qb = session.getWena3BehaviorSampleDao().queryBuilder();
|
||||
qb.where(Wena3BehaviorSampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
qb = session.getWena3CaloriesSampleDao().queryBuilder();
|
||||
qb.where(Wena3CaloriesSampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
qb = session.getWena3EnergySampleDao().queryBuilder();
|
||||
qb.where(Wena3EnergySampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
qb = session.getWena3ActivitySampleDao().queryBuilder();
|
||||
qb.where(Wena3ActivitySampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
qb = session.getWena3Vo2SampleDao().queryBuilder();
|
||||
qb.where(Wena3Vo2SampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
qb = session.getWena3StressSampleDao().queryBuilder();
|
||||
qb.where(Wena3StressSampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public DeviceType getSupportedType(GBDeviceCandidate candidate) {
|
||||
if(SonyWena3Constants.BT_DEVICE_NAME.equals(candidate.getName())) {
|
||||
return DeviceType.SONY_WENA_3;
|
||||
}
|
||||
return DeviceType.UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBondingStyle() {
|
||||
return BONDING_STYLE_BOND;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCalendarEvents() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsRealtimeData() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsActivityDataFetching() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsActivityTracking() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean supportsAppReordering() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsStressMeasurement() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeSampleProvider<? extends StressSample> getStressSampleProvider(GBDevice device, DaoSession session) {
|
||||
return new SonyWena3StressSampleProvider(device, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSpo2() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsHeartRateMeasurement(GBDevice device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsHeartRateStats() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SampleProvider<? extends ActivitySample> getSampleProvider(GBDevice device, DaoSession session) {
|
||||
return new SonyWena3ActivitySampleProvider(device, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeSampleProvider<? extends HeartRateSample> getHeartRateRestingSampleProvider(GBDevice device, DaoSession session) {
|
||||
return new SonyWena3HeartRateSampleProvider(device, session);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public InstallHandler findInstallHandler(Uri uri, Context context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsScreenshots() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlarmSlotCount(GBDevice device) {
|
||||
return SonyWena3Constants.ALARM_SLOTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSmartWakeup(GBDevice device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsMusicInfo() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFindDevice() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsWeather() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExperimental() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedLanguageSettings(GBDevice device) {
|
||||
return new String[]{
|
||||
"auto",
|
||||
"en_US",
|
||||
"ja_JP"
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
|
||||
return new int[]{
|
||||
R.xml.devicesettings_notifications_enable,
|
||||
R.xml.devicesettings_sync_calendar,
|
||||
R.xml.devicesettings_wearlocation,
|
||||
R.xml.devicesettings_donotdisturb_no_auto,
|
||||
R.xml.devicesettings_wena3_auto_power_off,
|
||||
R.xml.devicesettings_goal_notification,
|
||||
R.xml.devicesettings_wena3,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public boolean supportsNotificationVibrationPatterns() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean supportsNotificationVibrationRepetitionPatterns() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean supportsNotificationLedPatterns() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public AbstractNotificationPattern[] getNotificationVibrationPatterns() {
|
||||
return new AbstractNotificationPattern[] {
|
||||
VibrationKind.NONE, VibrationKind.BASIC,
|
||||
VibrationKind.CONTINUOUS, VibrationKind.RAPID,
|
||||
VibrationKind.TRIPLE, VibrationKind.STEP_UP, VibrationKind.STEP_DOWN,
|
||||
VibrationKind.WARNING, VibrationKind.SIREN, VibrationKind.SHORT
|
||||
};
|
||||
}
|
||||
|
||||
public AbstractNotificationPattern[] getNotificationVibrationRepetitionPatterns() {
|
||||
return new AbstractNotificationPattern[] {
|
||||
VibrationCount.ONCE, VibrationCount.TWICE, VibrationCount.THREE, VibrationCount.FOUR,
|
||||
VibrationCount.INDEFINITE
|
||||
};
|
||||
}
|
||||
|
||||
public AbstractNotificationPattern[] getNotificationLedPatterns() {
|
||||
return new AbstractNotificationPattern[] {
|
||||
LedColor.NONE, LedColor.RED, LedColor.YELLOW, LedColor.GREEN,
|
||||
LedColor.CYAN, LedColor.BLUE, LedColor.PURPLE, LedColor.WHITE
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import de.greenrobot.dao.AbstractDao;
|
||||
import de.greenrobot.dao.Property;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractTimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3EnergySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3EnergySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
public class SonyWena3EnergySampleProvider extends AbstractTimeSampleProvider<Wena3EnergySample> {
|
||||
public SonyWena3EnergySampleProvider(final GBDevice device, final DaoSession session) {
|
||||
super(device, session);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AbstractDao<Wena3EnergySample, ?> getSampleDao() {
|
||||
return getSession().getWena3EnergySampleDao();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getTimestampSampleProperty() {
|
||||
return Wena3EnergySampleDao.Properties.Timestamp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getDeviceIdentifierSampleProperty() {
|
||||
return Wena3EnergySampleDao.Properties.DeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wena3EnergySample createSample() {
|
||||
return new Wena3EnergySample();
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.greenrobot.dao.AbstractDao;
|
||||
import de.greenrobot.dao.Property;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractTimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3HeartRateSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3HeartRateSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
public class SonyWena3HeartRateSampleProvider extends AbstractTimeSampleProvider<Wena3HeartRateSample> {
|
||||
public SonyWena3HeartRateSampleProvider(final GBDevice device, final DaoSession session) {
|
||||
super(device, session);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AbstractDao<Wena3HeartRateSample, ?> getSampleDao() {
|
||||
return getSession().getWena3HeartRateSampleDao();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getTimestampSampleProperty() {
|
||||
return Wena3HeartRateSampleDao.Properties.Timestamp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getDeviceIdentifierSampleProperty() {
|
||||
return Wena3HeartRateSampleDao.Properties.DeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wena3HeartRateSample createSample() {
|
||||
return new Wena3HeartRateSample();
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3;
|
||||
|
||||
public class SonyWena3SettingKeys {
|
||||
// ------ Booleans
|
||||
public static final String RICH_DESIGN_MODE = "pref_wena3_rich_design_mode";
|
||||
public static final String LARGE_FONT_SIZE = "pref_wena3_large_font_size";
|
||||
public static final String WEATHER_IN_STATUSBAR = "pref_wena3_weather_in_statusbar";
|
||||
public static final String SMART_VIBRATION = "pref_wena3_vibration_smart";
|
||||
public static final String RECEIVE_CALLS = "pref_wena3_receive_calls";
|
||||
public static final String BACKGROUND_SYNC = "pref_wena3_background_sync";
|
||||
|
||||
public static final String AUTO_POWER_SCHEDULE_KIND = "pref_wena3_power_schedule_kind";
|
||||
public static final String AUTO_POWER_SCHEDULE_START_HHMM = "pref_wena3_power_schedule_start";
|
||||
public static final String AUTO_POWER_SCHEDULE_END_HHMM = "pref_wena3_power_schedule_end";
|
||||
|
||||
public static final String LEFT_HOME_ICON = "pref_wena3_home_icon_left";
|
||||
public static final String CENTER_HOME_ICON = "pref_wena3_home_icon_center";
|
||||
public static final String RIGHT_HOME_ICON = "pref_wena3_home_icon_right";
|
||||
public static final String MENU_ICON_CSV_KEY = "pref_wena3_menu_icon_csv";
|
||||
public static final String STATUS_PAGE_CSV_KEY = "pref_wena3_status_pages_csv";
|
||||
public static final int MAX_STATUS_PAGES = 7;
|
||||
|
||||
public static final String DEFAULT_CALL_LED_COLOR = "pref_wena3_default_call_led_color";
|
||||
public static final String DEFAULT_LED_COLOR = "pref_wena3_default_led_color";
|
||||
public static final String DEFAULT_CALL_VIBRATION_PATTERN = "pref_wena3_call_default_vibration";
|
||||
public static final String DEFAULT_VIBRATION_PATTERN = "pref_wena3_default_vibration";
|
||||
public static final String BUTTON_LONG_PRESS_ACTION = "pref_wena3_button_long_action";
|
||||
public static final String BUTTON_DOUBLE_PRESS_ACTION = "pref_wena3_button_double_action";
|
||||
public static final String VIBRATION_STRENGTH = "pref_wena3_vibration_strength";
|
||||
// ------ Ints
|
||||
public static final String SMART_WAKEUP_MARGIN_MINUTES = "pref_wena3_smart_wakeup_margin";
|
||||
public static final String DAY_START_HOUR = "pref_wena3_day_start_hour";
|
||||
public static final String DEFAULT_VIBRATION_REPETITION = "pref_wena3_default_vibration_repetition";
|
||||
public static final String DEFAULT_CALL_VIBRATION_REPETITION = "pref_wena3_default_call_vibration_repetition";
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
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 SonyWena3SettingsCustomizer implements DeviceSpecificSettingsCustomizer {
|
||||
@Override
|
||||
public void customizeSettings(DeviceSpecificSettingsHandler handler, Prefs prefs) {
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.RICH_DESIGN_MODE);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.LARGE_FONT_SIZE);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.WEATHER_IN_STATUSBAR);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.SMART_VIBRATION);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.SMART_WAKEUP_MARGIN_MINUTES);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.VIBRATION_STRENGTH);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.LEFT_HOME_ICON);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.CENTER_HOME_ICON);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.RIGHT_HOME_ICON);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.DAY_START_HOUR);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.AUTO_POWER_SCHEDULE_KIND);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.AUTO_POWER_SCHEDULE_START_HHMM);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.AUTO_POWER_SCHEDULE_END_HHMM);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.BUTTON_DOUBLE_PRESS_ACTION);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.BUTTON_LONG_PRESS_ACTION);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.MENU_ICON_CSV_KEY);
|
||||
handler.addPreferenceHandlerFor(SonyWena3SettingKeys.STATUS_PAGE_CSV_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreferenceChange(Preference preference, DeviceSpecificSettingsHandler handler) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getPreferenceKeysWithSummary() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
public static final Creator<SonyWena3SettingsCustomizer> CREATOR = new Creator<SonyWena3SettingsCustomizer>() {
|
||||
@Override
|
||||
public SonyWena3SettingsCustomizer createFromParcel(final Parcel in) {
|
||||
return new SonyWena3SettingsCustomizer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SonyWena3SettingsCustomizer[] newArray(final int size) {
|
||||
return new SonyWena3SettingsCustomizer[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(final Parcel dest, final int flags) {
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.greenrobot.dao.AbstractDao;
|
||||
import de.greenrobot.dao.Property;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractTimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3StressSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3StressSampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
public class SonyWena3StressSampleProvider extends AbstractTimeSampleProvider<Wena3StressSample> {
|
||||
public SonyWena3StressSampleProvider(final GBDevice device, final DaoSession session) {
|
||||
super(device, session);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AbstractDao<Wena3StressSample, ?> getSampleDao() {
|
||||
return getSession().getWena3StressSampleDao();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getTimestampSampleProperty() {
|
||||
return Wena3StressSampleDao.Properties.Timestamp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getDeviceIdentifierSampleProperty() {
|
||||
return Wena3StressSampleDao.Properties.DeviceId;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public List<Wena3StressSample> getAllSamples(long timestampFrom, long timestampTo) {
|
||||
List<Wena3StressSample> samples = super.getAllSamples(timestampFrom, timestampTo);
|
||||
for(Wena3StressSample sample: samples) {
|
||||
if(sample.getStress() < -100 || sample.getStress() > 100) {
|
||||
sample.setStress(-1);
|
||||
} else {
|
||||
// Move from the original -100 .. 100 range to 0 .. 100
|
||||
sample.setStress(Math.round(((float)sample.getStress() + 100.0f) / 2.0f));
|
||||
}
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wena3StressSample createSample() {
|
||||
return new Wena3StressSample();
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import de.greenrobot.dao.AbstractDao;
|
||||
import de.greenrobot.dao.Property;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractTimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3Vo2Sample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3Vo2SampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
public class SonyWena3Vo2SampleProvider extends AbstractTimeSampleProvider<Wena3Vo2Sample> {
|
||||
public SonyWena3Vo2SampleProvider(final GBDevice device, final DaoSession session) {
|
||||
super(device, session);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AbstractDao<Wena3Vo2Sample, ?> getSampleDao() {
|
||||
return getSession().getWena3Vo2SampleDao();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getTimestampSampleProperty() {
|
||||
return Wena3Vo2SampleDao.Properties.Timestamp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getDeviceIdentifierSampleProperty() {
|
||||
return Wena3Vo2SampleDao.Properties.DeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wena3Vo2Sample createSample() {
|
||||
return new Wena3Vo2Sample();
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
public interface AbstractNotificationPattern {
|
||||
String getUserReadableName(Context context);
|
||||
String getValue();
|
||||
}
|
@ -148,6 +148,7 @@ public enum DeviceType {
|
||||
ASTEROIDOS(540, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_asteroidos),
|
||||
SOFLOW_SO6(550, R.drawable.ic_device_vesc, R.drawable.ic_device_vesc_disabled, R.string.devicetype_soflow_s06),
|
||||
WITHINGS_STEEL_HR(560, R.drawable.ic_device_watchxplus, R.drawable.ic_device_watchxplus_disabled, R.string.withings_steel_hr),
|
||||
SONY_WENA_3(570, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_sony_wena3),
|
||||
TEST(1000, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_test);
|
||||
|
||||
private final int key;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,21 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol;
|
||||
|
||||
public interface Wena3Packetable {
|
||||
byte[] toByteArray();
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic;
|
||||
|
||||
|
||||
public class ActivityPacketCrc {
|
||||
private static final int CRC_INITIAL_VALUE = 65535;
|
||||
private static final int[] CRC_TABLE = new int[] {
|
||||
0x0000, 0x8005, 0x800f, 0x000a, 0x801b,
|
||||
0x001e, 0x0014, 0x8011, 0x8033, 0x0036,
|
||||
0x003c, 0x8039, 0x0028, 0x802d, 0x8027,
|
||||
0x0022, 0x8063, 0x0066, 0x006c, 0x8069,
|
||||
0x0078, 0x807d, 0x8077, 0x0072, 0x0050,
|
||||
0x8055, 0x805f, 0x005a, 0x804b, 0x004e,
|
||||
0x0044, 0x8041, 0x80c3, 0x00c6, 0x00cc,
|
||||
0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
|
||||
0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb,
|
||||
0x00ee, 0x00e4, 0x80e1, 0x00a0, 0x80a5,
|
||||
0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4,
|
||||
0x80b1, 0x8093, 0x0096, 0x009c, 0x8099,
|
||||
0x0088, 0x808d, 0x8087, 0x0082, 0x8183,
|
||||
0x0186, 0x018c, 0x8189, 0x0198, 0x819d,
|
||||
0x8197, 0x0192, 0x01b0, 0x81b5, 0x81bf,
|
||||
0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
|
||||
0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb,
|
||||
0x01fe, 0x01f4, 0x81f1, 0x81d3, 0x01d6,
|
||||
0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7,
|
||||
0x01c2, 0x0140, 0x8145, 0x814f, 0x014a,
|
||||
0x815b, 0x015e, 0x0154, 0x8151, 0x8173,
|
||||
0x0176, 0x017c, 0x8179, 0x0168, 0x816d,
|
||||
0x8167, 0x0162, 0x8123, 0x0126, 0x012c,
|
||||
0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
|
||||
0x0110, 0x8115, 0x811f, 0x011a, 0x810b,
|
||||
0x010e, 0x0104, 0x8101, 0x8303, 0x0306,
|
||||
0x030c, 0x8309, 0x0318, 0x831d, 0x8317,
|
||||
0x0312, 0x0330, 0x8335, 0x833f, 0x033a,
|
||||
0x832b, 0x032e, 0x0324, 0x8321, 0x0360,
|
||||
0x8365, 0x836f, 0x036a, 0x837b, 0x037e,
|
||||
0x0374, 0x8371, 0x8353, 0x0356, 0x035c,
|
||||
0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
|
||||
0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db,
|
||||
0x03de, 0x03d4, 0x83d1, 0x83f3, 0x03f6,
|
||||
0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7,
|
||||
0x03e2, 0x83a3, 0x03a6, 0x03ac, 0x83a9,
|
||||
0x03b8, 0x83bd, 0x83b7, 0x03b2, 0x0390,
|
||||
0x8395, 0x839f, 0x039a, 0x838b, 0x038e,
|
||||
0x0384, 0x8381, 0x0280, 0x8285, 0x828f,
|
||||
0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
|
||||
0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8,
|
||||
0x82ad, 0x82a7, 0x02a2, 0x82e3, 0x02e6,
|
||||
0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7,
|
||||
0x02f2, 0x02d0, 0x82d5, 0x82df, 0x02da,
|
||||
0x82cb, 0x02ce, 0x02c4, 0x82c1, 0x8243,
|
||||
0x0246, 0x024c, 0x8249, 0x0258, 0x825d,
|
||||
0x8257, 0x0252, 0x0270, 0x8275, 0x827f,
|
||||
0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
|
||||
0x0220, 0x8225, 0x822f, 0x022a, 0x823b,
|
||||
0x023e, 0x0234, 0x8231, 0x8213, 0x0216,
|
||||
0x021c, 0x8219, 0x0208, 0x820d, 0x8207,
|
||||
0x0202
|
||||
};
|
||||
|
||||
private int result = CRC_INITIAL_VALUE;
|
||||
|
||||
public void next(byte i) {
|
||||
result = CRC_TABLE[((i & 255) ^ (result >>> 8))] ^ ((result << 8) & 65535);
|
||||
}
|
||||
|
||||
public void next(byte[] b) {
|
||||
for(byte v: b) next(v);
|
||||
}
|
||||
|
||||
public int getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity.ActivitySyncDataPacket;
|
||||
|
||||
public interface ActivityPacketParser {
|
||||
/// Return `true` if further data packets should be accepted by this parser.
|
||||
/// Make sure to configure internal state correctly to prepare for incoming data if returning `true`.
|
||||
/// Otherwise return `false`.
|
||||
boolean parseHeader(ActivitySyncDataPacket packet, GBDevice sourceDevice);
|
||||
void parsePacket(ActivitySyncDataPacket packet, GBDevice sourceDevice);
|
||||
void finishReceiving(GBDevice device);
|
||||
void reset();
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity.ActivitySyncDataPacket;
|
||||
|
||||
public class ActivitySyncPacketProcessor {
|
||||
private static final int RESET_SEQ_NO = 0xFF;
|
||||
private static final int MAX_SEQ_NO = 0x7F;
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ActivitySyncPacketProcessor.class);
|
||||
|
||||
private ActivityPacketParser currentParser = null;
|
||||
private final List<ActivityPacketParser> parsers = new ArrayList<>();
|
||||
private int currentSeqNo = RESET_SEQ_NO;
|
||||
private boolean haveHeader = false;
|
||||
|
||||
public ActivitySyncPacketProcessor() {}
|
||||
|
||||
public void registerParser(ActivityPacketParser parser) {
|
||||
parsers.add(parser);
|
||||
}
|
||||
|
||||
public void receivePacket(ActivitySyncDataPacket packet, GBDevice device) {
|
||||
if(packet.sequenceNo == RESET_SEQ_NO) {
|
||||
LOG.info("Initial packet received, off we go with a sync!");
|
||||
currentSeqNo = RESET_SEQ_NO;
|
||||
resetAll();
|
||||
// Do NOT return here: the initial packet is still a packet!
|
||||
}
|
||||
|
||||
if(packet.sequenceNo != currentSeqNo) {
|
||||
LOG.error("There was packet loss (skip "+currentSeqNo+" to "+packet.sequenceNo+")");
|
||||
finalizeCurrentParserIfNeeded(device);
|
||||
return;
|
||||
} else {
|
||||
if(currentSeqNo == MAX_SEQ_NO || currentSeqNo == RESET_SEQ_NO) {
|
||||
currentSeqNo = 0;
|
||||
} else {
|
||||
currentSeqNo ++;
|
||||
}
|
||||
}
|
||||
|
||||
if(!packet.isCrcValid) {
|
||||
LOG.error("Received packet has invalid CRC");
|
||||
return;
|
||||
}
|
||||
|
||||
switch(packet.type) {
|
||||
case HEADER:
|
||||
haveHeader = true;
|
||||
finalizeCurrentParserIfNeeded(device);
|
||||
for(ActivityPacketParser parser: parsers) {
|
||||
if(parser.parseHeader(packet, device)) {
|
||||
currentParser = parser;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(currentParser == null) {
|
||||
LOG.warn("No parsers can understand " + packet);
|
||||
}
|
||||
break;
|
||||
|
||||
case DATA:
|
||||
if(currentParser != null) {
|
||||
currentParser.parsePacket(packet, device);
|
||||
} else {
|
||||
if(!haveHeader) {
|
||||
LOG.warn("DATA arrived before HEADER: dropped " + packet);
|
||||
} else {
|
||||
LOG.warn("No parser known: dropped data packet " + packet);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FINISH:
|
||||
LOG.info("End of transmission received");
|
||||
finalizeCurrentParserIfNeeded(device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void resetAll() {
|
||||
currentParser = null;
|
||||
for(ActivityPacketParser parser: parsers) parser.reset();
|
||||
}
|
||||
|
||||
private void finalizeCurrentParserIfNeeded(GBDevice device) {
|
||||
if(currentParser != null) {
|
||||
currentParser.finishReceiving(device);
|
||||
currentParser = null;
|
||||
}
|
||||
haveHeader = false;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class StepsSampleCollection {
|
||||
public final Date startDate;
|
||||
public final List<Integer> everyMinuteCount;
|
||||
|
||||
public StepsSampleCollection(Date startDate, List<Integer> everyMinuteCount) {
|
||||
this.startDate = startDate;
|
||||
this.everyMinuteCount = everyMinuteCount;
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3ActivitySampleCombiner;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3ActivitySampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3BehaviorSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3BehaviorSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity.BehaviorSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.util.TimeUtil;
|
||||
|
||||
public class BehaviorPacketParser extends SamplePacketParser<BehaviorSample> {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(BehaviorPacketParser.class);
|
||||
public BehaviorPacketParser() {
|
||||
super(0x02);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean tryExtractingMetadataFromHeaderBuffer(ByteBuffer buffer) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
BehaviorSample takeSampleFromBuffer(ByteBuffer buffer) {
|
||||
// Entry structure:
|
||||
// - 1b type
|
||||
// - 4b padding?
|
||||
// - 4b start date
|
||||
// - 4b end date
|
||||
int id = (buffer.get() & 0xFF);
|
||||
if(id < BehaviorSample.Type.LUT.length) {
|
||||
BehaviorSample.Type type = BehaviorSample.Type.LUT[id];
|
||||
buffer.position(buffer.position()+4);
|
||||
Date start = TimeUtil.wenaTimeToDate(buffer.getInt());
|
||||
Date end = TimeUtil.wenaTimeToDate(buffer.getInt());
|
||||
return new BehaviorSample(start, end, type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean canTakeSampleFromBuffer(ByteBuffer buffer) {
|
||||
return buffer.remaining() >= 13;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishReceiving(GBDevice device) {
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
SonyWena3BehaviorSampleProvider sampleProvider = new SonyWena3BehaviorSampleProvider(device, db.getDaoSession());
|
||||
Long userId = DBHelper.getUser(db.getDaoSession()).getId();
|
||||
Long deviceId = DBHelper.getDevice(device, db.getDaoSession()).getId();
|
||||
List<Wena3BehaviorSample> samples = new ArrayList<>();
|
||||
|
||||
for(BehaviorSample rawSample: accumulator) {
|
||||
Wena3BehaviorSample gbSample = new Wena3BehaviorSample();
|
||||
gbSample.setDeviceId(deviceId);
|
||||
gbSample.setUserId(userId);
|
||||
gbSample.setTimestamp(rawSample.start.getTime());
|
||||
gbSample.setTimestampFrom(rawSample.start.getTime());
|
||||
gbSample.setTimestampTo(rawSample.end.getTime());
|
||||
gbSample.setRawKind(rawSample.type.ordinal());
|
||||
samples.add(gbSample);
|
||||
}
|
||||
sampleProvider.addSamples(samples);
|
||||
|
||||
if(!accumulator.isEmpty()) {
|
||||
SonyWena3ActivitySampleProvider activitySampleProvider = new SonyWena3ActivitySampleProvider(device, db.getDaoSession());
|
||||
SonyWena3ActivitySampleCombiner combiner = new SonyWena3ActivitySampleCombiner(activitySampleProvider);
|
||||
combiner.overlayBehaviorStartingAt(accumulator.get(0).start, sampleProvider);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error acquiring database for recording Behavior samples", e);
|
||||
}
|
||||
|
||||
// Finally clean up the parser
|
||||
super.finishReceiving(device);
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3CaloriesSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3CaloriesSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
public class CaloriesPacketParser extends LinearSamplePacketParser<Integer> {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CaloriesPacketParser.class);
|
||||
public CaloriesPacketParser() {
|
||||
super(0x06, OneBytePerSamplePacketParser.ONE_MINUTE_IN_MS);
|
||||
}
|
||||
|
||||
@Override
|
||||
Integer takeSampleFromBuffer(ByteBuffer buffer) {
|
||||
return (buffer.getShort() & 65535);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean canTakeSampleFromBuffer(ByteBuffer buffer) {
|
||||
return buffer.remaining() >= 2;
|
||||
}
|
||||
@Override
|
||||
public void finishReceiving(GBDevice device) {
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
SonyWena3CaloriesSampleProvider sampleProvider = new SonyWena3CaloriesSampleProvider(device, db.getDaoSession());
|
||||
Long userId = DBHelper.getUser(db.getDaoSession()).getId();
|
||||
Long deviceId = DBHelper.getDevice(device, db.getDaoSession()).getId();
|
||||
|
||||
int i = 0;
|
||||
List<Wena3CaloriesSample> samples = new ArrayList<>();
|
||||
|
||||
for(int rawSample: accumulator) {
|
||||
Date currentSampleDate = timestampOfSampleAtIndex(i);
|
||||
|
||||
Wena3CaloriesSample gbSample = new Wena3CaloriesSample();
|
||||
gbSample.setDeviceId(deviceId);
|
||||
gbSample.setUserId(userId);
|
||||
gbSample.setTimestamp(currentSampleDate.getTime());
|
||||
gbSample.setCalories(rawSample);
|
||||
samples.add(gbSample);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
sampleProvider.addSamples(samples);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error acquiring database for recording Calories samples", e);
|
||||
}
|
||||
|
||||
// Finally clean up the parser
|
||||
super.finishReceiving(device);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3EnergySampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3EnergySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
public class EnergyPacketParser extends OneBytePerSamplePacketParser {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(EnergyPacketParser.class);
|
||||
private static final int ENERGY_PKT_MARKER = 0x05;
|
||||
public EnergyPacketParser() {
|
||||
super(ENERGY_PKT_MARKER, ONE_MINUTE_IN_MS);
|
||||
}
|
||||
@Override
|
||||
public void finishReceiving(GBDevice device) {
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
SonyWena3EnergySampleProvider sampleProvider = new SonyWena3EnergySampleProvider(device, db.getDaoSession());
|
||||
Long userId = DBHelper.getUser(db.getDaoSession()).getId();
|
||||
Long deviceId = DBHelper.getDevice(device, db.getDaoSession()).getId();
|
||||
List<Wena3EnergySample> samples = new ArrayList<>();
|
||||
int i = 0;
|
||||
|
||||
for(int rawSample: accumulator) {
|
||||
Date currentSampleDate = timestampOfSampleAtIndex(i);
|
||||
|
||||
Wena3EnergySample gbSample = new Wena3EnergySample();
|
||||
gbSample.setDeviceId(deviceId);
|
||||
gbSample.setUserId(userId);
|
||||
gbSample.setTimestamp(currentSampleDate.getTime());
|
||||
gbSample.setEnergy(rawSample);
|
||||
samples.add(gbSample);
|
||||
|
||||
i++;
|
||||
}
|
||||
sampleProvider.addSamples(samples);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error acquiring database for recording Energy samples", e);
|
||||
}
|
||||
|
||||
// Finally clean up the parser
|
||||
super.finishReceiving(device);
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3ActivitySampleCombiner;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3ActivitySampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3HeartRateSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3HeartRateSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
public class HeartRatePacketParser extends OneBytePerSamplePacketParser {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HeartRatePacketParser.class);
|
||||
private static final int HEART_PKT_MARKER = 0x01;
|
||||
public HeartRatePacketParser() {
|
||||
super(HEART_PKT_MARKER, ONE_MINUTE_IN_MS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishReceiving(GBDevice device) {
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
SonyWena3HeartRateSampleProvider sampleProvider = new SonyWena3HeartRateSampleProvider(device, db.getDaoSession());
|
||||
Long userId = DBHelper.getUser(db.getDaoSession()).getId();
|
||||
Long deviceId = DBHelper.getDevice(device, db.getDaoSession()).getId();
|
||||
List<Wena3HeartRateSample> samples = new ArrayList<>();
|
||||
|
||||
Date currentSampleDate = startDate;
|
||||
int i = 0;
|
||||
for(int rawSample: accumulator) {
|
||||
Wena3HeartRateSample gbSample = new Wena3HeartRateSample();
|
||||
gbSample.setDeviceId(deviceId);
|
||||
gbSample.setUserId(userId);
|
||||
gbSample.setTimestamp(currentSampleDate.getTime());
|
||||
gbSample.setHeartRate(rawSample);
|
||||
samples.add(gbSample);
|
||||
|
||||
i++;
|
||||
currentSampleDate = timestampOfSampleAtIndex(i);
|
||||
}
|
||||
|
||||
sampleProvider.addSamples(samples);
|
||||
|
||||
if(!accumulator.isEmpty()) {
|
||||
SonyWena3ActivitySampleProvider activitySampleProvider = new SonyWena3ActivitySampleProvider(device, db.getDaoSession());
|
||||
SonyWena3ActivitySampleCombiner combiner = new SonyWena3ActivitySampleCombiner(activitySampleProvider);
|
||||
combiner.overlayHeartRateStartingAt(startDate, sampleProvider);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error acquiring database for recording heart rate samples", e);
|
||||
}
|
||||
|
||||
// Finally clean up the parser
|
||||
super.finishReceiving(device);
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Date;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.util.TimeUtil;
|
||||
|
||||
abstract class LinearSamplePacketParser<Sample> extends SamplePacketParser<Sample> {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LinearSamplePacketParser.class);
|
||||
private int msBetweenSamples = 0;
|
||||
public Date startDate = null;
|
||||
|
||||
public LinearSamplePacketParser(int headerMarker, int sampleDistanceInMs) {
|
||||
super(headerMarker);
|
||||
msBetweenSamples = sampleDistanceInMs;
|
||||
reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishReceiving(GBDevice device) {
|
||||
Date estimatedEndDate = new Date(startDate.getTime() + ((long) accumulator.size() * msBetweenSamples));
|
||||
LOG.info("Finished collecting "+accumulator.size()+" samples over "+startDate+" ~ "+estimatedEndDate);
|
||||
super.finishReceiving(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean tryExtractingMetadataFromHeaderBuffer(ByteBuffer buffer) {
|
||||
if(buffer.remaining() < 4) {
|
||||
LOG.error("Received ASDP header is too short");
|
||||
return false;
|
||||
}
|
||||
|
||||
startDate = TimeUtil.wenaTimeToDate(buffer.getInt());
|
||||
return true;
|
||||
}
|
||||
|
||||
public Date timestampOfSampleAtIndex(int index) {
|
||||
assert startDate != null;
|
||||
if(index == 0) return startDate;
|
||||
return new Date(startDate.getTime() + (long) msBetweenSamples * index);
|
||||
}
|
||||
|
||||
abstract Sample takeSampleFromBuffer(ByteBuffer buffer);
|
||||
abstract boolean canTakeSampleFromBuffer(ByteBuffer buffer);
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class OneBytePerSamplePacketParser extends LinearSamplePacketParser<Integer> {
|
||||
public static final int ONE_MINUTE_IN_MS = 60_000; // 1 sample per minute it seems
|
||||
|
||||
public OneBytePerSamplePacketParser(int headerMarker, int sampleDistanceInMs) {
|
||||
super(headerMarker, sampleDistanceInMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
Integer takeSampleFromBuffer(ByteBuffer buffer) {
|
||||
return Integer.valueOf(buffer.get() & 0xFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean canTakeSampleFromBuffer(ByteBuffer buffer) {
|
||||
return buffer.remaining() > 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.ActivityPacketParser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity.ActivitySyncDataPacket;
|
||||
|
||||
abstract class SamplePacketParser<Sample> implements ActivityPacketParser {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SamplePacketParser.class);
|
||||
private final int headerMarker;
|
||||
public List<Sample> accumulator = new ArrayList<>();
|
||||
private enum State {
|
||||
READY, RECEIVING, FINISHED
|
||||
}
|
||||
private State currentState = State.READY;
|
||||
|
||||
public SamplePacketParser(int headerMarker) {
|
||||
this.headerMarker = headerMarker;
|
||||
reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
accumulator = new ArrayList<>();
|
||||
currentState = State.READY;
|
||||
}
|
||||
@Override
|
||||
public boolean parseHeader(ActivitySyncDataPacket packet, GBDevice sourceDevice) {
|
||||
assert packet.isCrcValid;
|
||||
assert packet.type == ActivitySyncDataPacket.PacketType.HEADER;
|
||||
|
||||
ByteBuffer buf = packet.dataBuffer();
|
||||
|
||||
int type = buf.get();
|
||||
if(type != this.headerMarker) {
|
||||
LOG.debug("Received ASDP with marker "+type+", not expected type");
|
||||
return false;
|
||||
}
|
||||
if(currentState != State.READY)
|
||||
return false;
|
||||
|
||||
if(!tryExtractingMetadataFromHeaderBuffer(buf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
currentState = State.RECEIVING;
|
||||
LOG.info("Ready to receive packets");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parsePacket(ActivitySyncDataPacket packet, GBDevice sourceDevice) {
|
||||
assert currentState == State.RECEIVING;
|
||||
assert packet.isCrcValid;
|
||||
assert packet.type == ActivitySyncDataPacket.PacketType.DATA;
|
||||
|
||||
ByteBuffer buf = packet.dataBuffer();
|
||||
while(canTakeSampleFromBuffer(buf))
|
||||
accumulator.add(takeSampleFromBuffer(buf));
|
||||
|
||||
LOG.info("Accumulated "+accumulator.size()+" samples");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishReceiving(GBDevice device) {
|
||||
assert currentState == State.RECEIVING;
|
||||
currentState = State.FINISHED;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
abstract Sample takeSampleFromBuffer(ByteBuffer buffer);
|
||||
abstract boolean canTakeSampleFromBuffer(ByteBuffer buffer);
|
||||
abstract boolean tryExtractingMetadataFromHeaderBuffer(ByteBuffer buffer);
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3ActivitySampleCombiner;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3ActivitySampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3BehaviorSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3HeartRateSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
public class StepsPacketParser extends OneBytePerSamplePacketParser {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StepsPacketParser.class);
|
||||
private static final int STEPS_PKT_MARKER = 0x00;
|
||||
public StepsPacketParser() {
|
||||
super(STEPS_PKT_MARKER, ONE_MINUTE_IN_MS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishReceiving(GBDevice device) {
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
SonyWena3ActivitySampleProvider sampleProvider = new SonyWena3ActivitySampleProvider(device, db.getDaoSession());
|
||||
Long userId = DBHelper.getUser(db.getDaoSession()).getId();
|
||||
Long deviceId = DBHelper.getDevice(device, db.getDaoSession()).getId();
|
||||
List<Wena3ActivitySample> samples = new ArrayList<>();
|
||||
Date currentSampleDate = startDate;
|
||||
int i = 0;
|
||||
for(int rawSample: accumulator) {
|
||||
Wena3ActivitySample gbSample = new Wena3ActivitySample();
|
||||
gbSample.setDeviceId(deviceId);
|
||||
gbSample.setUserId(userId);
|
||||
gbSample.setTimestamp((int)(currentSampleDate.getTime() / 1000L));
|
||||
gbSample.setSteps(rawSample);
|
||||
samples.add(gbSample);
|
||||
|
||||
i++;
|
||||
currentSampleDate = timestampOfSampleAtIndex(i);
|
||||
}
|
||||
sampleProvider.addGBActivitySamples(samples.toArray(new Wena3ActivitySample[samples.size()]));
|
||||
|
||||
SonyWena3ActivitySampleCombiner combiner = new SonyWena3ActivitySampleCombiner(sampleProvider);
|
||||
|
||||
SonyWena3BehaviorSampleProvider behaviorSampleProvider = new SonyWena3BehaviorSampleProvider(device, db.getDaoSession());
|
||||
combiner.overlayBehaviorStartingAt(startDate, behaviorSampleProvider);
|
||||
|
||||
SonyWena3HeartRateSampleProvider heartRateSampleProvider = new SonyWena3HeartRateSampleProvider(device, db.getDaoSession());
|
||||
combiner.overlayHeartRateStartingAt(startDate, heartRateSampleProvider);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error acquiring database for recording steps samples", e);
|
||||
}
|
||||
|
||||
// Finally clean up the parser
|
||||
super.finishReceiving(device);
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3StressSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3StressSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
|
||||
|
||||
public class StressPacketParser extends OneBytePerSamplePacketParser {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StressPacketParser.class);
|
||||
private static final int STRESS_PKT_MARKER = 0x04;
|
||||
public StressPacketParser() {
|
||||
super(STRESS_PKT_MARKER, ONE_MINUTE_IN_MS);
|
||||
}
|
||||
@Override
|
||||
Integer takeSampleFromBuffer(ByteBuffer buffer) {
|
||||
// In this one we actually need signed values, hence the override
|
||||
return Integer.valueOf(buffer.get());
|
||||
}
|
||||
@Override
|
||||
public void finishReceiving(GBDevice device) {
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
SonyWena3StressSampleProvider sampleProvider = new SonyWena3StressSampleProvider(device, db.getDaoSession());
|
||||
Long userId = DBHelper.getUser(db.getDaoSession()).getId();
|
||||
Long deviceId = DBHelper.getDevice(device, db.getDaoSession()).getId();
|
||||
List<Wena3StressSample> samples = new ArrayList<>();
|
||||
|
||||
Date currentSampleDate = startDate;
|
||||
int i = 0;
|
||||
for(int rawSample: accumulator) {
|
||||
if(rawSample >= -100 && rawSample <= 100) {
|
||||
Wena3StressSample gbSample = new Wena3StressSample();
|
||||
gbSample.setDeviceId(deviceId);
|
||||
gbSample.setUserId(userId);
|
||||
gbSample.setTimestamp(currentSampleDate.getTime());
|
||||
gbSample.setStress(rawSample);
|
||||
gbSample.setType(StressSample.Type.AUTOMATIC);
|
||||
samples.add(gbSample);
|
||||
} else {
|
||||
LOG.debug("Discard stress value as out of range: " + rawSample);
|
||||
}
|
||||
|
||||
i++;
|
||||
currentSampleDate = timestampOfSampleAtIndex(i);
|
||||
}
|
||||
|
||||
sampleProvider.addSamples(samples);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error acquiring database for recording stress samples", e);
|
||||
}
|
||||
|
||||
// Finally clean up the parser
|
||||
super.finishReceiving(device);
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.parsers;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3Vo2SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Wena3Vo2Sample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity.Vo2MaxSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.util.TimeUtil;
|
||||
|
||||
public class Vo2MaxPacketParser extends SamplePacketParser<Vo2MaxSample> {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Vo2MaxPacketParser.class);
|
||||
public Vo2MaxPacketParser() {
|
||||
super(0x03);
|
||||
}
|
||||
|
||||
@Override
|
||||
Vo2MaxSample takeSampleFromBuffer(ByteBuffer buffer) {
|
||||
Date ts = TimeUtil.wenaTimeToDate(buffer.getInt());
|
||||
int value = buffer.get() & 0xFF;
|
||||
return new Vo2MaxSample(ts, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean canTakeSampleFromBuffer(ByteBuffer buffer) {
|
||||
return buffer.remaining() >= 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean tryExtractingMetadataFromHeaderBuffer(ByteBuffer buffer) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishReceiving(GBDevice device) {
|
||||
try (DBHandler db = GBApplication.acquireDB()) {
|
||||
SonyWena3Vo2SampleProvider sampleProvider = new SonyWena3Vo2SampleProvider(device, db.getDaoSession());
|
||||
Long userId = DBHelper.getUser(db.getDaoSession()).getId();
|
||||
Long deviceId = DBHelper.getDevice(device, db.getDaoSession()).getId();
|
||||
List<Wena3Vo2Sample> samples = new ArrayList<>();
|
||||
Date currentSampleDate = null;
|
||||
int currentDateDatapoint = 0;
|
||||
|
||||
for(Vo2MaxSample rawSample: accumulator) {
|
||||
if(currentSampleDate == null || currentSampleDate != rawSample.timestamp) {
|
||||
currentDateDatapoint = 0;
|
||||
currentSampleDate = rawSample.timestamp;
|
||||
} else {
|
||||
currentDateDatapoint ++;
|
||||
}
|
||||
Wena3Vo2Sample gbSample = new Wena3Vo2Sample();
|
||||
gbSample.setDeviceId(deviceId);
|
||||
gbSample.setUserId(userId);
|
||||
gbSample.setTimestamp(currentSampleDate.getTime());
|
||||
gbSample.setDatapoint(currentDateDatapoint);
|
||||
gbSample.setVo2(rawSample.value);
|
||||
samples.add(gbSample);
|
||||
}
|
||||
sampleProvider.addSamples(samples);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error acquiring database for recording Vo2 samples", e);
|
||||
}
|
||||
|
||||
// Finally clean up the parser
|
||||
super.finishReceiving(device);
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.logic.ActivityPacketCrc;
|
||||
|
||||
public class ActivitySyncDataPacket {
|
||||
public enum PacketType {
|
||||
HEADER,
|
||||
DATA,
|
||||
FINISH;
|
||||
|
||||
static final PacketType[] LUT = new PacketType[] { HEADER, DATA, FINISH };
|
||||
}
|
||||
|
||||
public final int sequenceNo;
|
||||
public final PacketType type;
|
||||
public int crc;
|
||||
public int expectedCrc;
|
||||
public boolean isCrcValid;
|
||||
public final byte[] data;
|
||||
|
||||
public ActivitySyncDataPacket(byte[] packet) {
|
||||
/*
|
||||
1byte [seqno OR FF=RESET]
|
||||
2byte [crc16]
|
||||
1byte [mark: 00=head, 01=data, 02=end]
|
||||
IF HEAD
|
||||
1byte [type: 00=Steps 01=Heart 02=Behavior 03=Vo2 04=Stress 05=BodyEnergy 06=Calories 07=???]
|
||||
(usually) 4byte [WenaDate start ts]
|
||||
IF DATA
|
||||
(samples of appropriate [type]?)
|
||||
IF END
|
||||
(reception completed!)
|
||||
*/
|
||||
ByteBuffer buf = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN);
|
||||
sequenceNo = Integer.valueOf(buf.get() & 0xFF);
|
||||
crc = buf.getShort();
|
||||
crc &= 0xFFFF;
|
||||
type = PacketType.LUT[buf.get()];
|
||||
data = new byte[buf.remaining()];
|
||||
buf.get(data);
|
||||
checkCrc();
|
||||
}
|
||||
|
||||
private void checkCrc() {
|
||||
ActivityPacketCrc calc = new ActivityPacketCrc();
|
||||
ByteBuffer tmp = ByteBuffer.allocate(data.length + 1).put((byte)type.ordinal()).put(data);
|
||||
calc.next(tmp.array());
|
||||
expectedCrc = calc.getResult();
|
||||
isCrcValid = (expectedCrc == crc);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public String toString() {
|
||||
return String.format("<ASDP type %d, Seq.No: %d, CRC: %x, Valid: %s, Data: %s>", type.ordinal(), sequenceNo, crc, isCrcValid ? "yes" : String.format("NO [expected %x]", expectedCrc), toHexString(data));
|
||||
}
|
||||
|
||||
private static String toHexString(byte[] bytes) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (bytes != null)
|
||||
for (byte b:bytes) {
|
||||
final String hexString = Integer.toHexString(b & 0xff);
|
||||
if(hexString.length()==1)
|
||||
sb.append('0');
|
||||
sb.append(hexString).append(' ');
|
||||
}
|
||||
return sb.toString().toUpperCase();
|
||||
}
|
||||
|
||||
public ByteBuffer dataBuffer() {
|
||||
return ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
|
||||
public class ActivitySyncStartPacket implements Wena3Packetable {
|
||||
public ActivitySyncStartPacket() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return new byte[] { (byte) 0xFF };
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Date;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.util.TimeUtil;
|
||||
|
||||
abstract class ActivitySyncTimePacketTemplate implements Wena3Packetable {
|
||||
public final byte header;
|
||||
|
||||
@Nullable
|
||||
public final Date date1;
|
||||
@Nullable
|
||||
public final Date date2;
|
||||
@Nullable
|
||||
public final Date date3;
|
||||
@Nullable
|
||||
public final Date date4;
|
||||
|
||||
public ActivitySyncTimePacketTemplate(byte header, @Nullable Date date1, @Nullable Date date2, @Nullable Date date3, @Nullable Date date4) {
|
||||
this.header = header;
|
||||
this.date1 = date1;
|
||||
this.date2 = date2;
|
||||
this.date3 = date3;
|
||||
this.date4 = date4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
ByteBuffer buf = ByteBuffer.allocate(17)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put(header);
|
||||
if(date1 == null) {
|
||||
buf.putInt(0);
|
||||
} else {
|
||||
buf.putInt(TimeUtil.dateToWenaTime(date1));
|
||||
}
|
||||
if(date2 == null) {
|
||||
buf.putInt(0);
|
||||
} else {
|
||||
buf.putInt(TimeUtil.dateToWenaTime(date2));
|
||||
}
|
||||
if(date3 == null) {
|
||||
buf.putInt(0);
|
||||
} else {
|
||||
buf.putInt(TimeUtil.dateToWenaTime(date3));
|
||||
}
|
||||
if(date4 == null) {
|
||||
buf.putInt(0);
|
||||
} else {
|
||||
buf.putInt(TimeUtil.dateToWenaTime(date4));
|
||||
}
|
||||
return buf.array();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class ActivitySyncTimePacketTypeA extends ActivitySyncTimePacketTemplate {
|
||||
public ActivitySyncTimePacketTypeA(@Nullable Date stepCountLastSyncTime, @Nullable Date heartRateLastSyncTime, @Nullable Date behaviorLastSyncTime, @Nullable Date vo2MaxLastSyncTime) {
|
||||
super((byte) 0x1, stepCountLastSyncTime, heartRateLastSyncTime, behaviorLastSyncTime, vo2MaxLastSyncTime);
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class ActivitySyncTimePacketTypeB extends ActivitySyncTimePacketTemplate {
|
||||
public ActivitySyncTimePacketTypeB(@Nullable Date stressLastSyncTime, @Nullable Date bodyEnergyLastSyncTime, @Nullable Date caloriesLastSyncTime, @Nullable Date eventsLastSyncTime) {
|
||||
super((byte) 0x2, stressLastSyncTime, bodyEnergyLastSyncTime, caloriesLastSyncTime, eventsLastSyncTime);
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class BehaviorSample {
|
||||
public enum Type {
|
||||
UNKNOWN,
|
||||
NOT_WEARING,
|
||||
WALK,
|
||||
RUN,
|
||||
EXERCISE,
|
||||
SLEEP_DEEP,
|
||||
SLEEP_LIGHT,
|
||||
SLEEP_REM,
|
||||
SLEEP_AWAKE,
|
||||
STATIC;
|
||||
|
||||
public final static Type[] LUT = new Type[] {
|
||||
UNKNOWN,
|
||||
NOT_WEARING,
|
||||
WALK,
|
||||
RUN,
|
||||
EXERCISE,
|
||||
SLEEP_DEEP,
|
||||
SLEEP_LIGHT,
|
||||
SLEEP_REM,
|
||||
SLEEP_AWAKE,
|
||||
STATIC
|
||||
};
|
||||
}
|
||||
|
||||
public final Date start;
|
||||
public final Date end;
|
||||
public final Type type;
|
||||
|
||||
public BehaviorSample(Date start, Date end, Type type) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.activity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class Vo2MaxSample {
|
||||
public final Date timestamp;
|
||||
public final int value;
|
||||
|
||||
public Vo2MaxSample(Date timestamp, int value) {
|
||||
this.timestamp = timestamp;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.calendar;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.util.TimeUtil;
|
||||
|
||||
public class CalendarEntry implements Wena3Packetable {
|
||||
public final Date begin;
|
||||
public final Date end;
|
||||
public final boolean isAllDay;
|
||||
public final String title;
|
||||
public final String location;
|
||||
/// 1-based, not index!
|
||||
public final byte position;
|
||||
public final byte totalItemCount;
|
||||
|
||||
public CalendarEntry(Date begin, Date end, boolean isAllDay, String title, String location, byte position, byte totalItemCount) {
|
||||
this.begin = begin;
|
||||
this.end = end;
|
||||
this.isAllDay = isAllDay;
|
||||
this.title = title;
|
||||
this.location = location;
|
||||
this.position = position;
|
||||
this.totalItemCount = totalItemCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
byte[] cstrTitle = title.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] cstrLocation = location.getBytes(StandardCharsets.UTF_8);
|
||||
return ByteBuffer.allocate(14 + cstrTitle.length + cstrLocation.length)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte) 0x02)
|
||||
.put(position)
|
||||
.put(totalItemCount)
|
||||
.put((byte) cstrTitle.length)
|
||||
.put((byte) cstrLocation.length)
|
||||
.put((byte) (isAllDay ? 0x1 : 0x0))
|
||||
.putInt(TimeUtil.dateToWenaTime(begin))
|
||||
.putInt(TimeUtil.dateToWenaTime(end))
|
||||
.put(cstrTitle)
|
||||
.put(cstrLocation)
|
||||
.array();
|
||||
|
||||
}
|
||||
|
||||
public static byte[] byteArrayForEmptyEvent(byte position, byte totalItemCount) {
|
||||
return ByteBuffer.allocate(14)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte) 0x02)
|
||||
.put(position)
|
||||
.put(totalItemCount)
|
||||
.put((byte) 0x0)
|
||||
.put((byte) 0x0)
|
||||
.put((byte) 0x0)
|
||||
.putInt(0)
|
||||
.putInt(0)
|
||||
.array();
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
|
||||
// NB: This seems to not work on the Wena 3!
|
||||
// For me, the vendor's app just sends an "APP" notification for incoming calls as well,
|
||||
// just with a continuous vibration...
|
||||
@Deprecated
|
||||
public class EndOfIncomingCall implements Wena3Packetable {
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return new byte[] { 0x1 };
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines.LedColor;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines.NotificationFlags;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines.NotificationKind;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines.VibrationOptions;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.util.TimeUtil;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||
|
||||
public class NotificationArrival implements Wena3Packetable {
|
||||
public final NotificationKind kind;
|
||||
public final int id;
|
||||
public final String title;
|
||||
public final String message;
|
||||
public final String actionLabel;
|
||||
public final Date dateTime;
|
||||
public final VibrationOptions vibration;
|
||||
public final LedColor ledColor;
|
||||
public final NotificationFlags flags;
|
||||
|
||||
public NotificationArrival(
|
||||
NotificationKind kind,
|
||||
int id,
|
||||
String title,
|
||||
String message,
|
||||
String actionLabel,
|
||||
Date dateTime,
|
||||
VibrationOptions vibration,
|
||||
LedColor ledColor,
|
||||
NotificationFlags flags
|
||||
) {
|
||||
this.kind = kind;
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.message = message;
|
||||
this.actionLabel = actionLabel;
|
||||
this.dateTime = dateTime;
|
||||
this.vibration = vibration;
|
||||
this.ledColor = ledColor;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
assert vibration.count <= 255;
|
||||
|
||||
byte vibraFlags = 0;
|
||||
byte vibraCount = (byte)vibration.count;
|
||||
|
||||
if(vibration.continuous) {
|
||||
vibraFlags = 0x3;
|
||||
vibraCount = 0;
|
||||
} else {
|
||||
if(vibraCount > 4) vibraCount = 4;
|
||||
else if (vibraCount < 0) vibraCount = 1;
|
||||
}
|
||||
|
||||
byte[] encodedTitle = StringUtils.truncate(title.trim(), 31).getBytes(StandardCharsets.UTF_8);
|
||||
byte[] encodedMessage = StringUtils.truncate(message.trim(), 239).getBytes(StandardCharsets.UTF_8);
|
||||
byte[] encodedAction = StringUtils.truncate(actionLabel.trim(), 15).getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
ByteBuffer buf = ByteBuffer
|
||||
.allocate(18 + encodedTitle.length + encodedMessage.length + encodedAction.length)
|
||||
.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
buf.put((byte) 0x00) // marker
|
||||
.put((byte)ledColor.ordinal())
|
||||
.put(vibraFlags)
|
||||
.put((byte)vibration.kind.ordinal())
|
||||
.put(vibraCount)
|
||||
.put((byte)encodedTitle.length)
|
||||
.put((byte)encodedMessage.length)
|
||||
.put((byte)flags.value)
|
||||
.put((byte)kind.ordinal())
|
||||
.put((byte)encodedAction.length)
|
||||
.putInt(id)
|
||||
.putInt(TimeUtil.dateToWenaTime(dateTime))
|
||||
.put(encodedTitle)
|
||||
.put(encodedMessage)
|
||||
.put(encodedAction);
|
||||
|
||||
return buf.array();
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines.NotificationKind;
|
||||
|
||||
public class NotificationRemoval implements Wena3Packetable {
|
||||
public final NotificationKind kind;
|
||||
public final int id;
|
||||
|
||||
public NotificationRemoval(NotificationKind kind, int id) {
|
||||
this.kind = kind;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return ByteBuffer
|
||||
.allocate(7)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte) 0x01)
|
||||
.put((byte)kind.ordinal())
|
||||
.putInt(id)
|
||||
.array();
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.AbstractNotificationPattern;
|
||||
|
||||
public enum LedColor implements AbstractNotificationPattern {
|
||||
NONE(0, R.string.prefs_wena3_led_none),
|
||||
RED(1, R.string.red),
|
||||
YELLOW(2, R.string.yellow),
|
||||
GREEN(3, R.string.green),
|
||||
CYAN(4, R.string.cyan),
|
||||
BLUE(5, R.string.blue),
|
||||
PURPLE(6, R.string.purple),
|
||||
WHITE(7, R.string.white);
|
||||
|
||||
public final byte value;
|
||||
private final int stringId;
|
||||
|
||||
LedColor(int value, int stringId) {
|
||||
this.value = (byte) value;
|
||||
this.stringId = stringId;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getUserReadableName(Context context) {
|
||||
return context.getString(stringId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return name();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines;
|
||||
|
||||
public enum NotificationFlags {
|
||||
NONE(0),
|
||||
IS_TEST(1),
|
||||
IS_RETRANSMISSION(2),
|
||||
HAS_ACTION(4);
|
||||
|
||||
public int value = 0;
|
||||
NotificationFlags(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines;
|
||||
|
||||
public enum NotificationKind {
|
||||
APP,
|
||||
CALL
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
*
|
||||
* This file is part of Gadgetbridge.
|
||||
*
|
||||
* Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Gadgetbridge is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.AbstractNotificationPattern;
|
||||
|
||||
public enum VibrationCount implements AbstractNotificationPattern {
|
||||
INDEFINITE(0, R.string.prefs_wena3_notification_vibration_repetition_0),
|
||||
ONCE(1, R.string.prefs_wena3_notification_vibration_repetition_1),
|
||||
TWICE(2, R.string.prefs_wena3_notification_vibration_repetition_2),
|
||||
THREE(3, R.string.prefs_wena3_notification_vibration_repetition_3),
|
||||
FOUR(4, R.string.prefs_wena3_notification_vibration_repetition_4),
|
||||
;
|
||||
|
||||
public int value;
|
||||
public int stringId;
|
||||
VibrationCount(int value, int stringId) {
|
||||
this.value = value;
|
||||
this.stringId = stringId;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getUserReadableName(Context context) {
|
||||
return context.getString(stringId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.AbstractNotificationPattern;
|
||||
|
||||
public enum VibrationKind implements AbstractNotificationPattern {
|
||||
NONE(0, R.string.prefs_wena3_vibration_none),
|
||||
CONTINUOUS(1, R.string.prefs_wena3_vibration_continuous),
|
||||
BASIC(2, R.string.prefs_wena3_vibration_basic),
|
||||
RAPID(3, R.string.prefs_wena3_vibration_rapid),
|
||||
TRIPLE(4, R.string.prefs_wena3_vibration_triple),
|
||||
STEP_UP(5, R.string.prefs_wena3_vibration_step_up),
|
||||
STEP_DOWN(6, R.string.prefs_wena3_vibration_step_down),
|
||||
WARNING(7, R.string.prefs_wena3_vibration_warning),
|
||||
SIREN(8, R.string.prefs_wena3_vibration_siren),
|
||||
SHORT(9, R.string.prefs_wena3_vibration_short);
|
||||
|
||||
public final byte value;
|
||||
private final int stringId;
|
||||
|
||||
VibrationKind(int value, int stringId) {
|
||||
this.value = (byte) value;
|
||||
this.stringId = stringId;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getUserReadableName(Context context) {
|
||||
return context.getString(stringId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return name();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.notification.defines;
|
||||
|
||||
public class VibrationOptions {
|
||||
public final VibrationKind kind;
|
||||
public final int count;
|
||||
public final boolean continuous;
|
||||
|
||||
public VibrationOptions(VibrationKind kind, int count, boolean continuous) {
|
||||
this.kind = kind;
|
||||
this.count = count;
|
||||
this.continuous = continuous;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
|
||||
public class AlarmListSettings implements Wena3Packetable {
|
||||
public static final int MAX_ALARMS_IN_PACKET = 3;
|
||||
|
||||
// While the Wena 3 has 9 alarms, the packet fits 3 at most
|
||||
// So to update all alarms you need to send 3 packets
|
||||
public final List<SingleAlarmSetting> alarms;
|
||||
// Usually 0 for first packet, 3 for second, 6 for third
|
||||
public final int alarmListOffset;
|
||||
|
||||
public AlarmListSettings(List<SingleAlarmSetting> alarms, int alarmListOffset) {
|
||||
this.alarms = alarms;
|
||||
this.alarmListOffset = alarmListOffset;
|
||||
|
||||
assert (this.alarmListOffset % 3) == 0;
|
||||
assert this.alarms.size() <= MAX_ALARMS_IN_PACKET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
ByteBuffer buf = ByteBuffer.allocate(19).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
buf.put((byte) 0x06);
|
||||
|
||||
for(int i = 0; i < MAX_ALARMS_IN_PACKET; i++) {
|
||||
buf.put((byte) (alarmListOffset + i));
|
||||
if(i < alarms.size()) {
|
||||
SingleAlarmSetting alarm = alarms.get(i);
|
||||
buf.put(alarm.toByteArray());
|
||||
} else {
|
||||
buf.put(SingleAlarmSetting.emptyPacket());
|
||||
}
|
||||
}
|
||||
|
||||
return buf.array();
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class AutoPowerOffSettings extends DoNotDisturbSettings {
|
||||
|
||||
public AutoPowerOffSettings(boolean enable, int startHour, int startMinute, int endHour, int endMinute) {
|
||||
super(enable, startHour, startMinute, endHour, endMinute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return ByteBuffer.allocate(6)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte) 0x15)
|
||||
.put((byte) (enable ? 0x1 : 0x0))
|
||||
.put((byte) startHour)
|
||||
.put((byte) startMinute)
|
||||
.put((byte) endHour)
|
||||
.put((byte) endMinute)
|
||||
.array();
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.GenderSetting;
|
||||
|
||||
public class BodyPropertiesSetting implements Wena3Packetable {
|
||||
public final GenderSetting gender;
|
||||
public final short yearOfBirth;
|
||||
public final short monthOfBirth;
|
||||
public final short dayOfBirth;
|
||||
public final short height;
|
||||
public final short weight;
|
||||
|
||||
public BodyPropertiesSetting(GenderSetting gender, short yearOfBirth, short monthOfBirth, short dayOfBirth, short height, short weight) {
|
||||
this.gender = gender;
|
||||
this.yearOfBirth = yearOfBirth;
|
||||
this.monthOfBirth = monthOfBirth;
|
||||
this.dayOfBirth = dayOfBirth;
|
||||
this.height = height;
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return ByteBuffer.allocate(10)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte) 0x1D)
|
||||
.put((byte) gender.ordinal())
|
||||
.putShort(yearOfBirth)
|
||||
.put((byte) (monthOfBirth + 1)) // Java uses 0-indexed months
|
||||
.put((byte) dayOfBirth)
|
||||
.putShort((short) (height * 10))
|
||||
.putShort((short) (weight * 10))
|
||||
.array();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
|
||||
public class CalendarNotificationEnableSetting implements Wena3Packetable {
|
||||
public final boolean enableCalendar;
|
||||
public final boolean enableNotifications;
|
||||
|
||||
public CalendarNotificationEnableSetting(boolean enableCalendar, boolean enableNotifications) {
|
||||
this.enableCalendar = enableCalendar;
|
||||
this.enableNotifications = enableNotifications;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return new byte[] {
|
||||
0x12,
|
||||
(byte) (enableNotifications ? 0x1 : 0x0),
|
||||
(byte) (enableCalendar ? 0x1 : 0x0)
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
|
||||
public class CameraAppTypeSetting implements Wena3Packetable {
|
||||
private static final String PHOTOPRO_APP_ID = "com.sonymobile.photopro";
|
||||
public final boolean hasXperiaApp;
|
||||
|
||||
public CameraAppTypeSetting(boolean isXperia) {
|
||||
this.hasXperiaApp = isXperia;
|
||||
}
|
||||
|
||||
public static CameraAppTypeSetting findOut(PackageManager pm) {
|
||||
try {
|
||||
pm.getPackageInfo(PHOTOPRO_APP_ID, 0);
|
||||
return new CameraAppTypeSetting(true);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return new CameraAppTypeSetting(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return ByteBuffer
|
||||
.allocate(2)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte)0x21)
|
||||
.put((byte) (hasXperiaApp ? 0x1 : 0x0))
|
||||
.array();
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
|
||||
public class DayStartHourSetting implements Wena3Packetable {
|
||||
public final int dayStartHour;
|
||||
|
||||
public DayStartHourSetting(int dayStartHour) {
|
||||
this.dayStartHour = dayStartHour;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return new byte[] {
|
||||
0x16, (byte) dayStartHour
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.DeviceButtonActionId;
|
||||
|
||||
public class DeviceButtonActionSetting implements Wena3Packetable {
|
||||
public final DeviceButtonActionId longPress;
|
||||
public final DeviceButtonActionId doubleClick;
|
||||
|
||||
public DeviceButtonActionSetting(DeviceButtonActionId longPress, DeviceButtonActionId doubleClick) {
|
||||
this.longPress = longPress;
|
||||
this.doubleClick = doubleClick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return ByteBuffer.allocate(5)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte)0x1C)
|
||||
.putShort(longPress.value)
|
||||
.putShort(doubleClick.value)
|
||||
.array();
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.DisplayDesign;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.DisplayOrientation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.FontSize;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.Language;
|
||||
|
||||
public class DisplaySetting implements Wena3Packetable {
|
||||
public final boolean displayOnRaiseWrist;
|
||||
public final Language language;
|
||||
public final int displayDuration;
|
||||
public final DisplayOrientation orientation;
|
||||
public final DisplayDesign design;
|
||||
public final FontSize fontSize;
|
||||
public final boolean weatherInStatusBar;
|
||||
|
||||
public DisplaySetting(boolean displayOnRaiseWrist, Language language, int displayDuration, DisplayOrientation orientation, DisplayDesign design, FontSize fontSize, boolean weatherInStatusBar) {
|
||||
this.displayOnRaiseWrist = displayOnRaiseWrist;
|
||||
this.language = language;
|
||||
this.displayDuration = displayDuration;
|
||||
this.orientation = orientation;
|
||||
this.design = design;
|
||||
this.fontSize = fontSize;
|
||||
this.weatherInStatusBar = weatherInStatusBar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return ByteBuffer
|
||||
.allocate(8)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte)0x1A)
|
||||
.put((byte) fontSize.ordinal())
|
||||
.put((byte) orientation.ordinal())
|
||||
.put((byte) language.ordinal())
|
||||
.put((byte) (displayOnRaiseWrist ? 0x1 : 0x0))
|
||||
.put((byte) design.ordinal())
|
||||
.put((byte) (weatherInStatusBar ? 0x1 : 0x0))
|
||||
.put((byte) displayDuration)
|
||||
.array();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,51 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
|
||||
public class DoNotDisturbSettings implements Wena3Packetable {
|
||||
public final boolean enable;
|
||||
public final int startHour;
|
||||
public final int startMinute;
|
||||
public final int endHour;
|
||||
public final int endMinute;
|
||||
|
||||
public DoNotDisturbSettings(boolean enable, int startHour, int startMinute, int endHour, int endMinute) {
|
||||
this.enable = enable;
|
||||
this.startHour = startHour;
|
||||
this.startMinute = startMinute;
|
||||
this.endHour = endHour;
|
||||
this.endMinute = endMinute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return ByteBuffer.allocate(6)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte) 0x14)
|
||||
.put((byte) (enable ? 0x1 : 0x0))
|
||||
.put((byte) startHour)
|
||||
.put((byte) startMinute)
|
||||
.put((byte) endHour)
|
||||
.put((byte) endMinute)
|
||||
.array();
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
|
||||
public class GoalStepsSetting implements Wena3Packetable {
|
||||
public final boolean goalNotificationEnabled;
|
||||
public final int goalSteps;
|
||||
|
||||
public GoalStepsSetting(boolean goalNotificationEnabled, int goalSteps) {
|
||||
this.goalNotificationEnabled = goalNotificationEnabled;
|
||||
this.goalSteps = goalSteps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return ByteBuffer.allocate(6)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte) 0x17)
|
||||
.put((byte) (goalNotificationEnabled ? 0x1 : 0x0))
|
||||
.putInt(goalSteps)
|
||||
.array();
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.HomeIconId;
|
||||
|
||||
public class HomeIconOrderSetting implements Wena3Packetable {
|
||||
public final HomeIconId left;
|
||||
public final HomeIconId center;
|
||||
public final HomeIconId right;
|
||||
|
||||
public HomeIconOrderSetting(HomeIconId left, HomeIconId center, HomeIconId right) {
|
||||
this.left = left;
|
||||
this.center = center;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return ByteBuffer.allocate(7)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte) 0x1B)
|
||||
.putShort(left.value)
|
||||
.putShort(center.value)
|
||||
.putShort(right.value)
|
||||
.array();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.MenuIconId;
|
||||
|
||||
public class MenuIconSetting implements Wena3Packetable {
|
||||
public final List<MenuIconId> iconList = new ArrayList<>();
|
||||
|
||||
public MenuIconSetting() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
ByteBuffer buf = ByteBuffer.allocate(1 + iconList.size()).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buf.put((byte) 0x19);
|
||||
for(MenuIconId id : iconList) {
|
||||
buf.put(id.value);
|
||||
}
|
||||
return buf.array();
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
|
||||
public class SingleAlarmSetting implements Wena3Packetable {
|
||||
public final boolean enable;
|
||||
// Bitmask: See model.Alarm.ALARM_MON, TUE, ...
|
||||
public final byte repetition;
|
||||
public final int smartAlarmMargin;
|
||||
public final int hour;
|
||||
public final int minute;
|
||||
|
||||
public SingleAlarmSetting(boolean enable, byte repetition, int smartAlarmMargin, int hour, int minute) {
|
||||
this.enable = enable;
|
||||
this.repetition = repetition;
|
||||
this.smartAlarmMargin = smartAlarmMargin;
|
||||
this.hour = hour;
|
||||
this.minute = minute;
|
||||
}
|
||||
|
||||
// NB: normally this never occurs on the wire
|
||||
// outside of an AlarmListSettings packet!
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
// For some reason their bitmask starts on Sunday!
|
||||
// So this brings it in line with what Gadgetbridge expects...
|
||||
byte newRepetition = (byte) ((((repetition & ~Alarm.ALARM_SUN) << 1) | ((repetition & Alarm.ALARM_SUN) >> 6)) & 0xFF);
|
||||
return ByteBuffer.allocate(5)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte) (enable ? 0x2 : 0x1)) // 0x0 means no object...
|
||||
.put(newRepetition)
|
||||
.put((byte) smartAlarmMargin)
|
||||
.put((byte) hour)
|
||||
.put((byte) minute)
|
||||
.array();
|
||||
}
|
||||
|
||||
public static byte[] emptyPacket() {
|
||||
return ByteBuffer.allocate(5)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put(new byte[] {0, 0, 0, 0, 0})
|
||||
.array();
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.StatusPageId;
|
||||
|
||||
public class StatusPageOrderSetting implements Wena3Packetable {
|
||||
public final List<StatusPageId> pages = new ArrayList<>();
|
||||
|
||||
public StatusPageOrderSetting() {}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
ByteBuffer buf = ByteBuffer.allocate(1 + pages.size()).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buf.put((byte) 0x18);
|
||||
for(StatusPageId id : pages) {
|
||||
buf.put(id.value);
|
||||
}
|
||||
return buf.array();
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Date;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.util.TimeUtil;
|
||||
|
||||
public class TimeSetting implements Wena3Packetable {
|
||||
public final Date currentTime;
|
||||
|
||||
public TimeSetting(Date dateTime) {
|
||||
this.currentTime = dateTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return ByteBuffer.allocate(5)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte) 0x10)
|
||||
.putInt(TimeUtil.dateToWenaTime(currentTime))
|
||||
.array();
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
|
||||
public class TimeZoneSetting implements Wena3Packetable {
|
||||
public final TimeZone timeZone;
|
||||
public final Date referenceDate;
|
||||
|
||||
public TimeZoneSetting(TimeZone tz, Date referenceDate) {
|
||||
this.timeZone = tz;
|
||||
this.referenceDate = referenceDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
int offset = timeZone.getOffset(referenceDate.getTime());
|
||||
return ByteBuffer
|
||||
.allocate(3)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte)0x11)
|
||||
.put((byte) (offset / 3_600_000))
|
||||
.put((byte) ((offset / 60_000) % 60))
|
||||
.array();
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines.VibrationStrength;
|
||||
|
||||
public class VibrationSetting implements Wena3Packetable {
|
||||
public final boolean smartVibration;
|
||||
public final VibrationStrength strength;
|
||||
|
||||
public VibrationSetting(boolean smartVibration, VibrationStrength strength) {
|
||||
this.smartVibration = smartVibration;
|
||||
this.strength = strength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return new byte[] {
|
||||
0x08,
|
||||
(byte) strength.ordinal(),
|
||||
(byte) (smartVibration ? 0x01 : 0x00)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines;
|
||||
|
||||
public enum DeviceButtonActionId {
|
||||
NONE(0),
|
||||
ALEXA(1),
|
||||
QRIO(2),
|
||||
QRIO_UNLOCK(258),
|
||||
QRIO_LOCK(514),
|
||||
FIND_PHONE(3),
|
||||
TOGGLE_NFC(4),
|
||||
TOGGLE_SILENT(5),
|
||||
START_TIMER(262),
|
||||
TIMER(6),
|
||||
WEATHER(7),
|
||||
WENA_PAY(8),
|
||||
SCHEDULE(9),
|
||||
ACTIVITY_SCREEN(10),
|
||||
NOTIFICATION_SCREEN(11),
|
||||
SUICA(12),
|
||||
EDY(13),
|
||||
ALARM(14),
|
||||
RIIIVER(15),
|
||||
MUSIC(16),
|
||||
TOGGLE_MUSIC(272),
|
||||
MUSIC_NEXT(528),
|
||||
MUSIC_PREV(784);
|
||||
|
||||
|
||||
public final short value;
|
||||
|
||||
DeviceButtonActionId(int val) {
|
||||
this.value = (short) val;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines;
|
||||
|
||||
public enum DisplayDesign {
|
||||
NORMAL,
|
||||
RICH
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines;
|
||||
|
||||
public enum DisplayOrientation {
|
||||
RIGHT_HAND,
|
||||
LEFT_HAND
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines;
|
||||
|
||||
public enum FontSize {
|
||||
NORMAL,
|
||||
LARGE
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines;
|
||||
|
||||
public enum GenderSetting {
|
||||
FEMALE, // == 0
|
||||
MALE // == 1
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines;
|
||||
|
||||
// This is done via a class to be able to init the value from an arbitrary int (e.g. from prefs)
|
||||
// Whether listing all cases is needed is a good concern, they are essentially unused because
|
||||
// the settings dialog uses a string-array instead...
|
||||
public enum HomeIconId {
|
||||
TIMER(256),
|
||||
ALARM(512),
|
||||
CLOCK(768),
|
||||
ALEXA(1024),
|
||||
WENA_PAY(1280),
|
||||
QRIO_LOCK(1536),
|
||||
EDY(1792),
|
||||
NOTIFICATION_COUNT(2048),
|
||||
SCHEDULE(2304),
|
||||
PEDOMETER(2560),
|
||||
SLEEP(2816),
|
||||
HEART_RATE(3072),
|
||||
VO2MAX(3328),
|
||||
STRESS(3584),
|
||||
ENERGY(3840),
|
||||
|
||||
SUICA(4096),
|
||||
CALORIES(4352),
|
||||
RIIIVER(4608),
|
||||
MUSIC(4864),
|
||||
CAMERA(5120);
|
||||
|
||||
public final short value;
|
||||
|
||||
HomeIconId(final int value) {
|
||||
this.value = (short) value;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines;
|
||||
|
||||
public enum Language {
|
||||
ENGLISH,
|
||||
JAPANESE
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines;
|
||||
|
||||
public enum MenuIconId {
|
||||
NONE(0),
|
||||
TIMER(1),
|
||||
ALARM(2),
|
||||
FIND_PHONE(3),
|
||||
ALEXA(4),
|
||||
PAYMENT(5),
|
||||
QRIO(6),
|
||||
WEATHER(7),
|
||||
MUSIC(8),
|
||||
CAMERA(9);
|
||||
|
||||
public final byte value;
|
||||
|
||||
MenuIconId(int value) {
|
||||
this.value = (byte) value;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines;
|
||||
|
||||
public enum StatusPageId {
|
||||
NONE(0),
|
||||
PEDOMETER(1),
|
||||
SLEEP(2),
|
||||
HEART_RATE(3),
|
||||
VO2MAX(4),
|
||||
STRESS(5),
|
||||
ENERGY(6),
|
||||
CALORIES(7);
|
||||
|
||||
public final byte value;
|
||||
|
||||
StatusPageId(int val) {
|
||||
this.value = (byte) val;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.settings.defines;
|
||||
|
||||
public enum VibrationStrength {
|
||||
NORMAL(0),
|
||||
WEAK(1),
|
||||
STRONG(2);
|
||||
|
||||
public final byte value;
|
||||
|
||||
VibrationStrength(int val) {
|
||||
this.value = (byte) val;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
|
||||
|
||||
public class BatteryLevelInfo {
|
||||
public final int batteryPercentage;
|
||||
|
||||
public BatteryLevelInfo(byte[] packet) {
|
||||
this.batteryPercentage = Integer.valueOf(packet[0]);
|
||||
}
|
||||
|
||||
public GBDeviceEventBatteryInfo toDeviceEvent() {
|
||||
final GBDeviceEventBatteryInfo deviceEventBatteryInfo = new GBDeviceEventBatteryInfo();
|
||||
deviceEventBatteryInfo.level = batteryPercentage;
|
||||
return deviceEventBatteryInfo;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
|
||||
|
||||
public class DeviceInfo {
|
||||
public final String firmwareName;
|
||||
public final String serialNo;
|
||||
|
||||
public DeviceInfo(byte[] packet) {
|
||||
ByteBuffer buf = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN);
|
||||
byte[] fwNameStr = new byte[8];
|
||||
buf.get(fwNameStr);
|
||||
serialNo = Integer.toString(buf.getInt());
|
||||
firmwareName = new String(fwNameStr, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public GBDeviceEventVersionInfo toDeviceEvent() {
|
||||
final GBDeviceEventVersionInfo gbDeviceEventVersionInfo = new GBDeviceEventVersionInfo();
|
||||
gbDeviceEventVersionInfo.fwVersion = firmwareName;
|
||||
gbDeviceEventVersionInfo.fwVersion2 = serialNo;
|
||||
return gbDeviceEventVersionInfo;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||
|
||||
public class MusicInfo implements Wena3Packetable {
|
||||
public final String musicInfoText;
|
||||
|
||||
public MusicInfo(String musicInfoText) {
|
||||
this.musicInfoText = musicInfoText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
byte[] encodedString = StringUtils.truncate(musicInfoText.trim(), 99).getBytes(StandardCharsets.UTF_8);
|
||||
return ByteBuffer
|
||||
.allocate(2 + encodedString.length)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte)0x05)
|
||||
.put((byte)encodedString.length)
|
||||
.put(encodedString)
|
||||
.array();
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status;
|
||||
|
||||
public class NotificationServiceStatusRequest {
|
||||
public final int requestType;
|
||||
public int unknown;
|
||||
|
||||
public NotificationServiceStatusRequest(byte[] packet) {
|
||||
this.requestType = Integer.valueOf(packet[0]);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status;
|
||||
|
||||
public enum StatusRequestType {
|
||||
BACKGROUND_SYNC_REQUEST(0), // timer?
|
||||
GET_CALENDAR(1),
|
||||
LOCATE_PHONE(2),
|
||||
GET_WEATHER(3),
|
||||
RIIIVER_SIDE_BUTTON_ENGAGED(4), // -> 0x0 double click, 0x1 long click
|
||||
RIIIVER_HOME_ICON_CLICKED(5), // -> 0x00 0x12, 0x01 0x12, 0x02 0x12 : button no.?
|
||||
UNKNOWN1(6), // -> payment related?
|
||||
NOTIFICATION_REMOVE_REQUEST(10), // -> followed by int notification id
|
||||
MUSIC_INFO_FETCH(11);
|
||||
|
||||
public final int value;
|
||||
StatusRequestType(int val) {
|
||||
this.value = val;
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status;
|
||||
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Weather {
|
||||
private final WeatherType main;
|
||||
private final WeatherType sub;
|
||||
|
||||
public Weather(WeatherType main, WeatherType sub) {
|
||||
this.main = main;
|
||||
this.sub = sub;
|
||||
}
|
||||
|
||||
public byte packed() {
|
||||
return (byte)((main.ordinal() << 3) | sub.ordinal());
|
||||
}
|
||||
|
||||
public static Weather fromOpenWeatherMap(int conditionCode) {
|
||||
WeatherType main = WeatherType.SUNNY;
|
||||
WeatherType sub = WeatherType.SUNNY;
|
||||
|
||||
switch (conditionCode) {
|
||||
// https://openweathermap.org/weather-conditions
|
||||
case 200:
|
||||
case 201:
|
||||
case 210:
|
||||
case 230:
|
||||
case 231:
|
||||
case 300:
|
||||
case 301:
|
||||
case 310:
|
||||
case 311:
|
||||
case 313:
|
||||
case 500:
|
||||
case 501:
|
||||
case 520:
|
||||
case 521:
|
||||
main = WeatherType.RAIN;
|
||||
sub = WeatherType.RAIN;
|
||||
break;
|
||||
|
||||
case 202:
|
||||
case 212:
|
||||
case 221:
|
||||
case 232:
|
||||
case 302:
|
||||
case 312:
|
||||
case 314:
|
||||
case 321:
|
||||
case 502:
|
||||
case 503:
|
||||
case 504:
|
||||
case 522:
|
||||
case 531:
|
||||
main = WeatherType.HEAVY_RAIN;
|
||||
sub = WeatherType.HEAVY_RAIN;
|
||||
break;
|
||||
|
||||
case 511:
|
||||
case 615:
|
||||
case 616:
|
||||
main = WeatherType.RAIN;
|
||||
sub = WeatherType.SNOW;
|
||||
break;
|
||||
|
||||
case 600:
|
||||
case 601:
|
||||
case 602:
|
||||
case 611:
|
||||
case 612:
|
||||
case 613:
|
||||
case 620:
|
||||
case 621:
|
||||
case 622:
|
||||
main = WeatherType.SNOW;
|
||||
sub = WeatherType.SNOW;
|
||||
break;
|
||||
|
||||
case 701:
|
||||
case 711:
|
||||
case 721:
|
||||
case 731:
|
||||
case 741:
|
||||
case 751:
|
||||
case 761:
|
||||
case 762:
|
||||
case 771:
|
||||
case 781:
|
||||
main = WeatherType.SUNNY;
|
||||
sub = WeatherType.CLOUDY;
|
||||
break;
|
||||
|
||||
case 800:
|
||||
case 801:
|
||||
main = WeatherType.SUNNY;
|
||||
sub = WeatherType.SUNNY;
|
||||
break;
|
||||
|
||||
case 802:
|
||||
case 803:
|
||||
main = WeatherType.SUNNY;
|
||||
sub = WeatherType.CLOUDY;
|
||||
break;
|
||||
|
||||
case 804:
|
||||
main = WeatherType.CLOUDY;
|
||||
sub = WeatherType.CLOUDY;
|
||||
break;
|
||||
|
||||
default:
|
||||
LoggerFactory.getLogger(Weather.class)
|
||||
.warn("Unknown condition code " + conditionCode);
|
||||
break;
|
||||
}
|
||||
|
||||
return new Weather(main, sub);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status;
|
||||
|
||||
import lineageos.weather.util.WeatherUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
|
||||
public class WeatherDay {
|
||||
public final Weather day;
|
||||
public final Weather night;
|
||||
public final int temperatureMaximum;
|
||||
public final int temperatureMinimum;
|
||||
|
||||
public WeatherDay(Weather day, Weather night, int temperatureMaximum, int temperatureMinimum) {
|
||||
this.day = day;
|
||||
this.night = night;
|
||||
// For some reason, Wena uses Farenheit on the wire, but Celsius on display...
|
||||
// Assume a middle ground input in Kelvin.
|
||||
this.temperatureMaximum = (int) Math.round(WeatherUtils.celsiusToFahrenheit(temperatureMaximum - 273.15));
|
||||
this.temperatureMinimum = (int) Math.round(WeatherUtils.celsiusToFahrenheit(temperatureMinimum - 273.15));
|
||||
}
|
||||
|
||||
public static WeatherDay fromSpec(WeatherSpec.Daily daily) {
|
||||
return new WeatherDay(
|
||||
Weather.fromOpenWeatherMap(daily.conditionCode),
|
||||
Weather.fromOpenWeatherMap(daily.conditionCode),
|
||||
daily.maxTemp,
|
||||
daily.minTemp
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,51 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.Wena3Packetable;
|
||||
|
||||
public class WeatherReport implements Wena3Packetable {
|
||||
public final List<WeatherDay> fiveDays;
|
||||
|
||||
public WeatherReport(List<WeatherDay> fiveDays) {
|
||||
this.fiveDays = fiveDays;
|
||||
assert this.fiveDays.size() == 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
ByteBuffer buf = ByteBuffer
|
||||
.allocate(21)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.put((byte) 0x03);
|
||||
|
||||
for(int i = 0; i < 5; i++) {
|
||||
WeatherDay current = this.fiveDays.get(i);
|
||||
buf.put(current.day.packed());
|
||||
buf.put(current.night.packed());
|
||||
buf.put((byte) (current.temperatureMinimum + 100));
|
||||
buf.put((byte) (current.temperatureMaximum + 100));
|
||||
}
|
||||
|
||||
return buf.array();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.packets.status;
|
||||
|
||||
public enum WeatherType {
|
||||
SUNNY,
|
||||
CLOUDY,
|
||||
RAIN,
|
||||
HEAVY_RAIN,
|
||||
SNOW
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/* Copyright (C) 2023 akasaka / Genjitsu Labs
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.sony.wena3.protocol.util;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3Constants;
|
||||
|
||||
public class TimeUtil {
|
||||
public static int dateToWenaTime(Date date) {
|
||||
return (int) ((date.getTime() - SonyWena3Constants.EPOCH_START) / (long)1000);
|
||||
}
|
||||
|
||||
public static Date wenaTimeToDate(int wenaTime) {
|
||||
return new Date(((long) wenaTime) * 1000L + SonyWena3Constants.EPOCH_START);
|
||||
}
|
||||
}
|
@ -52,6 +52,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.lefun.BohemicSmartBraceletDe
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators.SonyLinkBudsSCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.soflow.SoFlowCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators.SonyWH1000XM5Coordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3Coordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.supercars.SuperCarsCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.fitpro.FitProDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.UnknownDeviceCoordinator;
|
||||
@ -390,6 +391,7 @@ public class DeviceHelper {
|
||||
result.add(new SonyWH1000XM2Coordinator());
|
||||
result.add(new SonyWF1000XM4Coordinator());
|
||||
result.add(new SonyWH1000XM5Coordinator());
|
||||
result.add(new SonyWena3Coordinator());
|
||||
result.add(new QC35Coordinator());
|
||||
result.add(new BinarySensorCoordinator());
|
||||
result.add(new FlipperZeroCoordinator());
|
||||
|
9
app/src/main/res/drawable/ic_wb_twilight.xml
Normal file
9
app/src/main/res/drawable/ic_wb_twilight.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector android:height="24dp" android:tint="#7E7E7E"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M16.9552,8.662l2.1207,-2.1222l1.4148,1.4138l-2.1207,2.1222z"/>
|
||||
<path android:fillColor="@android:color/white" android:pathData="M2,18h20v2h-20z"/>
|
||||
<path android:fillColor="@android:color/white" android:pathData="M11,4h2v3h-2z"/>
|
||||
<path android:fillColor="@android:color/white" android:pathData="M3.5425,7.9248l1.4142,-1.4142l2.1213,2.1213l-1.4142,1.4142z"/>
|
||||
<path android:fillColor="@android:color/white" android:pathData="M5,16h14c0,-3.87 -3.13,-7 -7,-7S5,12.13 5,16z"/>
|
||||
</vector>
|
24
app/src/main/res/drawable/ic_wena_icon_center.xml
Normal file
24
app/src/main/res/drawable/ic_wena_icon_center.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="12.7"
|
||||
android:viewportHeight="12.7">
|
||||
<path
|
||||
android:pathData="M5.041,4.975h2.619v2.75h-2.619z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="0.0891348"
|
||||
android:fillColor="#616161"
|
||||
android:strokeColor="#626262"/>
|
||||
<path
|
||||
android:pathData="M8.436,4.975h2.619v2.75h-2.619z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="0.0891348"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#626262"/>
|
||||
<path
|
||||
android:pathData="M1.645,4.975h2.619v2.75h-2.619z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="0.0891348"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#626262"/>
|
||||
</vector>
|
24
app/src/main/res/drawable/ic_wena_icon_left.xml
Normal file
24
app/src/main/res/drawable/ic_wena_icon_left.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="12.7"
|
||||
android:viewportHeight="12.7">
|
||||
<path
|
||||
android:pathData="M5.041,4.975h2.619v2.75h-2.619z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="0.0891348"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#626262"/>
|
||||
<path
|
||||
android:pathData="M8.436,4.975h2.619v2.75h-2.619z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="0.0891348"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#626262"/>
|
||||
<path
|
||||
android:pathData="M1.645,4.975h2.619v2.75h-2.619z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="0.0891348"
|
||||
android:fillColor="#616161"
|
||||
android:strokeColor="#626262"/>
|
||||
</vector>
|
24
app/src/main/res/drawable/ic_wena_icon_right.xml
Normal file
24
app/src/main/res/drawable/ic_wena_icon_right.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="12.7"
|
||||
android:viewportHeight="12.7">
|
||||
<path
|
||||
android:pathData="M5.041,4.975h2.619v2.75h-2.619z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="0.0891348"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#626262"/>
|
||||
<path
|
||||
android:pathData="M8.436,4.975h2.619v2.75h-2.619z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="0.0891348"
|
||||
android:fillColor="#616161"
|
||||
android:strokeColor="#626262"/>
|
||||
<path
|
||||
android:pathData="M1.645,4.975h2.619v2.75h-2.619z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="0.0891348"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#626262"/>
|
||||
</vector>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user