mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-27 20:36:51 +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:
parent
5ebb3b85b0
commit
e3e5c20a5a
@ -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>
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
51
app/src/main/res/layout/activity_cycling_live_data.xml
Normal file
51
app/src/main/res/layout/activity_cycling_live_data.xml
Normal 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>
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user