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

Cycling Sensor: added live data view

Cycling Sensor: I18N

Cycling Sensor: honor metric/imperial setting

Cycling Sensor: re-use existing speed strings
This commit is contained in:
Daniel Dakhno 2024-09-11 00:16:37 +02:00 committed by José Rebelo
parent 5ebb3b85b0
commit e3e5c20a5a
6 changed files with 260 additions and 21 deletions

View File

@ -901,6 +901,11 @@
android:name=".activities.CameraActivity"
android:launchMode="singleInstance"
android:exported="false" />
<activity
android:name=".devices.cycling_sensor.activity.CyclingLiveDataActivity"
android:launchMode="singleInstance"
android:exported="true" />
</application>
</manifest>

View File

@ -0,0 +1,170 @@
package nodomain.freeyourgadget.gadgetbridge.devices.cycling_sensor.activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
import nodomain.freeyourgadget.gadgetbridge.activities.SettingsActivity;
import nodomain.freeyourgadget.gadgetbridge.entities.CyclingSample;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
public class CyclingLiveDataActivity extends AbstractGBActivity {
private TextView speedView, tripDistanceView, totalDistanceView;
private GBDevice selectedDevice;
private float tripStartDistance = 0, tripCurrentDistance = 0;
private float toUnitFactor = 1;
private int
speedStringResource = R.string.km_h,
tripStringResource = R.string.label_distance_trip,
totalStringResource = R.string.label_distance_total;
private static final String PREFS_KEY_TRIP_START = "CYCLING_TRIP_START";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(getIntent() == null) {
selectedDevice = getStoredCyclingSensor();
}else if(getIntent().getExtras() == null) {
selectedDevice = getStoredCyclingSensor();
}else if((selectedDevice =
getIntent().getExtras().getParcelable("device")) == null) {
selectedDevice = getStoredCyclingSensor();
}
if (selectedDevice == null) {
GB.toast(getString(R.string.error_no_cycling_sensor_found), Toast.LENGTH_SHORT, GB.ERROR);
finish();
return;
}
setContentView(R.layout.activity_cycling_live_data);
speedView = findViewById(R.id.cycling_data_speed);
tripDistanceView = findViewById(R.id.cycling_data_trip_distance);
totalDistanceView = findViewById(R.id.cycling_data_total_distance);
tripStartDistance = GBApplication
.getDevicePrefs(selectedDevice)
.getFloat(PREFS_KEY_TRIP_START, 0);
tripDistanceView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if(tripCurrentDistance == 0) {
return true;
}
tripStartDistance = tripCurrentDistance;
GBApplication
.getDeviceSpecificSharedPrefs(selectedDevice.getAddress())
.edit()
.putFloat(PREFS_KEY_TRIP_START, tripStartDistance)
.apply();
tripDistanceView.setText(getString(tripStringResource, 0f));
return true;
}
});
String measurementSystem = GBApplication.getPrefs().getString(SettingsActivity.PREF_MEASUREMENT_SYSTEM, "metric");
if(!measurementSystem.equals("metric")) {
toUnitFactor = 0.621371f;
speedStringResource = R.string.mi_h;
tripStringResource = R.string.label_distance_trip_mph;
totalStringResource = R.string.label_distance_total_mph;
}
}
private GBDevice getStoredCyclingSensor(){
List<GBDevice> devices = GBApplication
.app()
.getDeviceManager()
.getDevices();
for(GBDevice device: devices) {
if (device.getState() != GBDevice.State.INITIALIZED) continue;
if (device.getType() != DeviceType.CYCLING_SENSOR) continue;
return device;
}
return null;
}
private BroadcastReceiver cyclingDataReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String deviceAddress = intent.getStringExtra("EXTRA_DEVICE_ADDRESS");
if(deviceAddress == null) {
return;
}
if(!deviceAddress.equals(selectedDevice.getAddress())) {
return;
}
CyclingSample sample = (CyclingSample) intent.getSerializableExtra(DeviceService.EXTRA_REALTIME_SAMPLE);
if(sample == null) {
return;
}
Float metersPerSecond = sample.getSpeed();
if(metersPerSecond != null) {
float kmh = metersPerSecond * 3.6f * toUnitFactor;
speedView.setText(String.format("%.1f %s", kmh, getString(speedStringResource)));
}else{
speedView.setText(String.format("%.1f %s", 0f, getString(speedStringResource)));
}
tripCurrentDistance = sample.getDistance();
tripDistanceView.setText(getString(tripStringResource, ((tripCurrentDistance - tripStartDistance) * toUnitFactor) / 1000));
totalDistanceView.setText(getString(totalStringResource, (tripCurrentDistance * toUnitFactor) / 1000));
}
};
@Override
protected void onResume() {
super.onResume();
LocalBroadcastManager
.getInstance(this)
.registerReceiver(
cyclingDataReceiver,
new IntentFilter(DeviceService.ACTION_REALTIME_SAMPLES)
);
}
@Override
protected void onPause() {
super.onPause();
LocalBroadcastManager
.getInstance(this)
.unregisterReceiver(cyclingDataReceiver);
}
}

View File

@ -11,6 +11,7 @@ import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.cycling_sensor.activity.CyclingLiveDataActivity;
import nodomain.freeyourgadget.gadgetbridge.devices.cycling_sensor.db.CyclingSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.CyclingSample;
import nodomain.freeyourgadget.gadgetbridge.entities.CyclingSampleDao;
@ -80,7 +81,7 @@ public class CyclingSensorCoordinator extends AbstractBLEDeviceCoordinator {
@Override
public Class<? extends Activity> getAppsManagementActivity() {
return null;
return CyclingLiveDataActivity.class;
}
@Override
@ -110,4 +111,11 @@ public class CyclingSensorCoordinator extends AbstractBLEDeviceCoordinator {
public int getDeviceNameResource() {
return R.string.devicetype_cycling_sensor;
}
@Override
public boolean supportsAppsManagement(GBDevice device) {
return true;
}
}

View File

@ -1,7 +1,5 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.cycling_sensor.support;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivityKind.CYCLING;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.Intent;
@ -93,7 +91,7 @@ public class CyclingSensorSupport extends CyclingSensorBaseSupport {
private long persistenceInterval;
private long nextPersistenceTimestamp = 0;
private float wheelCircumference;
private float wheelCircumferenceMeters;
private CyclingSpeedCadenceMeasurement lastReportedMeasurement = null;
private long lastMeasurementTime = 0;
@ -125,7 +123,7 @@ public class CyclingSensorSupport extends CyclingSensorBaseSupport {
nextPersistenceTimestamp = 0;
float wheelDiameter = deviceSpecificPrefs.getFloat(DeviceSettingsPreferenceConst.PREF_CYCLING_SENSOR_WHEEL_DIAMETER, 29);
wheelCircumference = (float)(wheelDiameter * 2.54 * Math.PI) / 100;
wheelCircumferenceMeters = (float)(wheelDiameter * 2.54 * Math.PI) / 100;
}
@Override
@ -196,13 +194,30 @@ public class CyclingSensorSupport extends CyclingSensorBaseSupport {
float revolutionsPerSecond = revolutionsDelta * (1000f / millisDelta);
speed = revolutionsPerSecond * wheelCircumference;
speed = revolutionsPerSecond * wheelCircumferenceMeters;
}
}
lastReportedMeasurement = currentMeasurement;
lastMeasurementTime = now;
CyclingSample sample = new CyclingSample();
if (currentMeasurement.revolutionDataPresent) {
sample.setRevolutionCount(currentMeasurement.revolutionCount);
sample.setSpeed(speed);
sample.setDistance(currentMeasurement.revolutionCount * wheelCircumferenceMeters);
}
sample.setTimestamp(now);
Intent liveIntent = new Intent(DeviceService.ACTION_REALTIME_SAMPLES);
liveIntent.putExtra(DeviceService.EXTRA_REALTIME_SAMPLE, sample);
liveIntent.putExtra("EXTRA_DEVICE_ADDRESS", getDevice().getAddress());
LocalBroadcastManager.getInstance(getContext())
.sendBroadcast(liveIntent);
if(now < nextPersistenceTimestamp){
// too early
return;
@ -210,21 +225,6 @@ public class CyclingSensorSupport extends CyclingSensorBaseSupport {
nextPersistenceTimestamp = now + persistenceInterval;
CyclingSample sample = new CyclingSample();
if (currentMeasurement.revolutionDataPresent) {
sample.setRevolutionCount(currentMeasurement.revolutionCount);
sample.setSpeed(speed);
sample.setDistance(currentMeasurement.revolutionCount * wheelCircumference);
}
sample.setTimestamp(now);
Intent liveIntent = new Intent(DeviceService.ACTION_REALTIME_SAMPLES);
liveIntent.putExtra(DeviceService.EXTRA_REALTIME_SAMPLE, sample);
LocalBroadcastManager.getInstance(getContext())
.sendBroadcast(liveIntent);
try(DBHandler handler = GBApplication.acquireDB()) {
DaoSession session = handler.getDaoSession();

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/cycling_data_speed"
android:textSize="@dimen/um25_value_text_size"
android:layout_marginTop="100dp"
android:gravity="center"
android:textColor="@color/primary_dark"
android:text="-"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/cycling_data_trip_distance"
android:textSize="@dimen/um25_value_text_size"
android:layout_marginTop="100dp"
android:gravity="center"
android:textColor="@color/primary_dark"
android:text="-"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="@dimen/um25_value_text_size_small"
android:gravity="center"
android:textColor="@color/secondarytext"
android:text="Long press to zero"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/cycling_data_total_distance"
android:textSize="@dimen/um25_value_text_size_small"
android:layout_marginTop="100dp"
android:gravity="center"
android:textColor="@color/secondarytext"
android:text="-"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -3296,4 +3296,9 @@
<string name="backup_restore_abort_import_confirmation">Abort the import? This may lead to a corrupted or inconsistent database.</string>
<string name="backup_restore_restart_title">Restart</string>
<string name="backup_restore_restart_summary">%1s will now restart.</string>
<string name="label_distance_trip">Trip: %.1f km</string>
<string name="label_distance_total">Total: %.1f km</string>
<string name="label_distance_trip_mph">Trip: %.1f mi</string>
<string name="label_distance_total_mph">Total: %.1f mi</string>
<string name="error_no_cycling_sensor_found">no cycling sensor found</string>
</resources>