Compare commits

..

12 Commits

Author SHA1 Message Date
Dennis Guse 1ccd2e3c0a Release: v4.0.6 2022-08-07 19:47:54 +02:00
Dennis Guse cdbddabc1b Cleanup: use ContextCompat.getColor() 2022-08-04 22:11:44 +02:00
Dennis Guse 9f6ca83f27 Bug: PublicAPI needs to call startForegroundService (SDK API26+).
Fixes #1301.
2022-08-04 22:11:44 +02:00
dependabot[bot] f2ee99a477 Bump gradle from 7.2.1 to 7.2.2
Bumps gradle from 7.2.1 to 7.2.2.

---
updated-dependencies:
- dependency-name: com.android.tools.build:gradle
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-04 06:44:02 +02:00
Dennis Guse 7009ede095 EGM2008 offset lookup for negative longitudes was wrong. 2022-08-03 17:30:31 +02:00
Dennis Guse 2b530a1c53 Cleanup: unused imports. 2022-08-02 18:44:15 +02:00
Poussinou 33673f5921 Update FUNDING.yml 2022-07-31 14:59:56 +02:00
Dennis Guse a7398d43e3 Release: v4.0.5 2022-07-29 17:58:32 +02:00
Dennis Guse 59b016a4a3 PlayStore: use an inverted icon (app launcher only).
Part of #1329.
2022-07-29 17:56:28 +02:00
Dennis Guse 78aa5d51c6 Intervals: if gain/loss is not available show "-" instead of null.
Fixes #1338.
2022-07-26 22:30:08 +02:00
Quang Trung 95f584b554 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (501 of 501 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://weblate.bubu1.eu/projects/OpenTracks/opentracks/vi/
2022-07-21 15:04:36 +02:00
Dennis Guse cf759d526d README_TESTED_SENSORS.md: we now store sensor data without movement.
Part of #1088.
2022-07-18 07:35:46 +02:00
38 changed files with 151 additions and 94 deletions
+1 -1
View File
@@ -2,4 +2,4 @@
liberapay: OpenTracks liberapay: OpenTracks
github: [rgmf, pstorch, dennisguse] github: [rgmf, pstorch, dennisguse]
custom: [ https://liberapay.com/OpenTracks, https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore ] custom: https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore
-4
View File
@@ -38,10 +38,6 @@ However, often only one value is provided.
We only support _Instantaneous Power_. We only support _Instantaneous Power_.
_WARNING_: we only support physically movements with valid GPS coordinates.
Using a device indoors (no GPS available) will only show the current power values, but won't store anything.
Also the distance is not computed.
For cycling: For cycling:
* Assioma Duo Powermeter * Assioma Duo Powermeter
* Elite drivo II * Elite drivo II
+4 -3
View File
@@ -6,7 +6,7 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.2.1' classpath 'com.android.tools.build:gradle:7.2.2'
} }
} }
@@ -59,8 +59,8 @@ android {
defaultConfig { defaultConfig {
applicationId "de.dennisguse.opentracks" applicationId "de.dennisguse.opentracks"
versionCode 4981 versionCode 4993
versionName "v4.0.4" versionName "v4.0.6"
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\"" buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
@@ -100,6 +100,7 @@ android {
releasePlayStore { releasePlayStore {
applicationIdSuffix ".playstore" applicationIdSuffix ".playstore"
versionNameSuffix "-PlayStore" versionNameSuffix "-PlayStore"
signingConfig signingConfigs.debug
} }
} }
@@ -0,0 +1,8 @@
v4.0.5: OpenTracks
Changes:
- PlayStore relase get's another logo
Bugfix:
- Interval list shows "-" if gain/loss is not present
@@ -0,0 +1,6 @@
v4.0.6: OpenTracks
Bugfix:
- EGM2008 offset computed wrong for negative longitudes
- PublicAPI crashed if OpenTracks was in background (API26+)
@@ -3,48 +3,25 @@ package de.dennisguse.opentracks;
import static androidx.test.espresso.Espresso.onData; import static androidx.test.espresso.Espresso.onData;
import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.Espresso.pressBack;
import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.longClick; import static androidx.test.espresso.action.ViewActions.longClick;
import static androidx.test.espresso.action.ViewActions.scrollTo;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription; import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText; import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.anything; import static org.hamcrest.Matchers.anything;
import static de.dennisguse.opentracks.util.EspressoUtils.childAtPosition;
import static de.dennisguse.opentracks.util.EspressoUtils.waitFor; import static de.dennisguse.opentracks.util.EspressoUtils.waitFor;
import static de.dennisguse.opentracks.util.EspressoUtils.withListSize;
import android.app.ActivityManager;
import android.app.Instrumentation;
import android.content.Context;
import android.view.View;
import android.widget.ListView;
import androidx.test.espresso.IdlingRegistry;
import androidx.test.espresso.IdlingResource;
import androidx.test.espresso.ViewInteraction;
import androidx.test.espresso.assertion.ViewAssertions;
import androidx.test.ext.junit.rules.ActivityScenarioRule; import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest; import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.GrantPermissionRule; import androidx.test.rule.GrantPermissionRule;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import de.dennisguse.opentracks.services.TrackDeleteService;
@LargeTest @LargeTest
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class EspressoDeleteTrackTest { public class EspressoDeleteTrackTest {
@@ -4,7 +4,6 @@ import static androidx.test.espresso.Espresso.onData;
import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.longClick; import static androidx.test.espresso.action.ViewActions.longClick;
import static androidx.test.espresso.action.ViewActions.scrollTo;
import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isClickable; import static androidx.test.espresso.matcher.ViewMatchers.isClickable;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
@@ -15,6 +15,10 @@
*/ */
package de.dennisguse.opentracks.chart; package de.dennisguse.opentracks.chart;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -25,10 +29,6 @@ import org.junit.runner.RunWith;
import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.R;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/** /**
* Tests {@link ChartValueSeries}. * Tests {@link ChartValueSeries}.
* *
@@ -142,7 +142,7 @@ public class EGM2008UtilsTest {
} }
@Test @Test
public void data_Berlin() throws IOException { public void data_Berlin_Germany_() throws IOException {
// given // given
TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochMilli(0)); TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochMilli(0));
trackPoint.setLatitude(52.530644); trackPoint.setLatitude(52.530644);
@@ -157,7 +157,7 @@ public class EGM2008UtilsTest {
} }
@Test @Test
public void data_Berlin_Caching() throws IOException { public void data_Berlin_Germany_Caching() throws IOException {
// given // given
TrackPoint trackPoint1 = new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochMilli(0)); TrackPoint trackPoint1 = new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochMilli(0));
trackPoint1.setLatitude(52.530644); trackPoint1.setLatitude(52.530644);
@@ -176,6 +176,22 @@ public class EGM2008UtilsTest {
assertNotEquals(altitude_egm2008.correctAltitude(trackPoint1.getLocation()), altitude_egm2008.correctAltitude(trackPoint2.getLocation()), 0.0001); assertNotEquals(altitude_egm2008.correctAltitude(trackPoint1.getLocation()), altitude_egm2008.correctAltitude(trackPoint2.getLocation()), 0.0001);
} }
@Test
public void data_Seattle_USA() throws IOException {
// given
TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochMilli(0));
trackPoint.setLatitude(47.63153);
trackPoint.setLongitude(-122.30938);
trackPoint.setAltitude(0);
// when
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
// then
assertEquals(22.99, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
}
@Test @Test
public void data_MaxUndulation() throws IOException { public void data_MaxUndulation() throws IOException {
// given // given
@@ -191,6 +207,7 @@ public class EGM2008UtilsTest {
assertEquals(-85.824, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR); assertEquals(-85.824, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
} }
@Test @Test
public void getIndices() { public void getIndices() {
TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochMilli(0)); TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochMilli(0));
@@ -208,7 +225,7 @@ public class EGM2008UtilsTest {
trackPoint.setLatitude(-90); trackPoint.setLatitude(-90);
trackPoint.setLongitude(-180); trackPoint.setLongitude(-180);
assertEquals(new EGM2008Utils.Indices(2160, 0), EGM2008Utils.getIndices(trackPoint.getLocation())); assertEquals(new EGM2008Utils.Indices(2160, 2160), EGM2008Utils.getIndices(trackPoint.getLocation()));
} }
@Test @Test
@@ -3,19 +3,15 @@ package de.dennisguse.opentracks;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import de.dennisguse.opentracks.databinding.ActivityShowErrorBinding; import de.dennisguse.opentracks.databinding.ActivityShowErrorBinding;
import de.dennisguse.opentracks.databinding.TrackListBinding;
public class ShowErrorActivity extends AbstractActivity { public class ShowErrorActivity extends AbstractActivity {
@@ -241,7 +241,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
startActivity(newIntent); startActivity(newIntent);
connection.unbind(this); connection.unbind(this);
}).startAndBind(this); }).startAndBind(this, true);
}); });
viewBinding.trackListFabAction.setOnLongClickListener((view) -> { viewBinding.trackListFabAction.setOnLongClickListener((view) -> {
if (!recordingStatus.isRecording()) { if (!recordingStatus.isRecording()) {
@@ -323,8 +323,8 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
searchView.findViewById(R.id.search_edit_frame).setPadding(0, 0, 48, 0); searchView.findViewById(R.id.search_edit_frame).setPadding(0, 0, 48, 0);
SearchView.SearchAutoComplete searchAutoComplete = searchView.findViewById(R.id.search_src_text); SearchView.SearchAutoComplete searchAutoComplete = searchView.findViewById(R.id.search_src_text);
searchAutoComplete.setHintTextColor(getResources().getColor(android.R.color.white)); searchAutoComplete.setHintTextColor(ContextCompat.getColor(this, android.R.color.white));
searchAutoComplete.setTextColor(getResources().getColor(android.R.color.white)); searchAutoComplete.setTextColor(ContextCompat.getColor(this, android.R.color.white));
searchView.setOnCloseListener(() -> { searchView.setOnCloseListener(() -> {
searchView.clearFocus(); searchView.clearFocus();
@@ -213,7 +213,7 @@ public class TrackRecordedActivity extends AbstractTrackDeleteActivity implement
connection.unbind(this); connection.unbind(this);
finish(); finish();
}).startAndBind(this); }).startAndBind(this, true);
return true; return true;
} }
@@ -11,8 +11,6 @@ import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.WindowInsets;
import android.view.WindowInsetsController;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.Toast; import android.widget.Toast;
@@ -49,7 +47,6 @@ import de.dennisguse.opentracks.ui.markers.MarkerEditActivity;
import de.dennisguse.opentracks.ui.markers.MarkerListActivity; import de.dennisguse.opentracks.ui.markers.MarkerListActivity;
import de.dennisguse.opentracks.util.IntentDashboardUtils; import de.dennisguse.opentracks.util.IntentDashboardUtils;
import de.dennisguse.opentracks.util.IntentUtils; import de.dennisguse.opentracks.util.IntentUtils;
import de.dennisguse.opentracks.util.PermissionUtils;
import de.dennisguse.opentracks.util.TrackIconUtils; import de.dennisguse.opentracks.util.TrackIconUtils;
import de.dennisguse.opentracks.util.TrackUtils; import de.dennisguse.opentracks.util.TrackUtils;
@@ -138,7 +135,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
viewBinding.trackRecordingFabAction.setImageResource(R.drawable.ic_baseline_stop_24); viewBinding.trackRecordingFabAction.setImageResource(R.drawable.ic_baseline_stop_24);
viewBinding.trackRecordingFabAction.setBackgroundTintList(ContextCompat.getColorStateList(this, R.color.opentracks_secondary_color)); viewBinding.trackRecordingFabAction.setBackgroundTintList(ContextCompat.getColorStateList(this, R.color.opentracks_secondary_color));
viewBinding.trackRecordingFabAction.setBackgroundColor(getResources().getColor(R.color.opentracks_secondary_color)); viewBinding.trackRecordingFabAction.setBackgroundColor(ContextCompat.getColor(this, R.color.opentracks_secondary_color));
viewBinding.trackRecordingFabAction.setOnLongClickListener((view) -> { viewBinding.trackRecordingFabAction.setOnLongClickListener((view) -> {
((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).vibrate(1000); ((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).vibrate(1000);
trackRecordingServiceConnection.stopRecording(TrackRecordingActivity.this); trackRecordingServiceConnection.stopRecording(TrackRecordingActivity.this);
@@ -145,7 +145,7 @@ public class TrackStoppedActivity extends AbstractTrackDeleteActivity implements
connection.unbind(this); connection.unbind(this);
finish(); finish();
}).startAndBind(this); }).startAndBind(this, true);
} }
@Override @Override
@@ -32,9 +32,7 @@ import java.util.List;
import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.TrackDataHub; import de.dennisguse.opentracks.data.TrackDataHub;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.Marker; import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.databinding.ChartBinding; import de.dennisguse.opentracks.databinding.ChartBinding;
@@ -3,7 +3,6 @@ package de.dennisguse.opentracks.chart;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.data.models.TrackPoint;
@@ -24,6 +24,7 @@ import android.graphics.Paint.Style;
import android.graphics.Path; import android.graphics.Path;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import java.text.NumberFormat; import java.text.NumberFormat;
@@ -68,12 +69,12 @@ abstract class ChartValueSeries {
fillPaint = new Paint(); fillPaint = new Paint();
fillPaint.setStyle(Style.FILL); fillPaint.setStyle(Style.FILL);
fillPaint.setColor(context.getResources().getColor(fillColor)); fillPaint.setColor(ContextCompat.getColor(context, fillColor));
fillPaint.setAntiAlias(true); fillPaint.setAntiAlias(true);
strokePaint = new Paint(); strokePaint = new Paint();
strokePaint.setStyle(Style.STROKE); strokePaint.setStyle(Style.STROKE);
strokePaint.setColor(context.getResources().getColor(strokeColor)); strokePaint.setColor(ContextCompat.getColor(context, strokeColor));
strokePaint.setAntiAlias(true); strokePaint.setAntiAlias(true);
// Make copies of the stroke paint with the default thickness // Make copies of the stroke paint with the default thickness
@@ -32,7 +32,6 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import de.dennisguse.opentracks.data.models.Marker; import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.data.tables.MarkerColumns; import de.dennisguse.opentracks.data.tables.MarkerColumns;
@@ -13,6 +13,14 @@ public class Distance {
return new Distance(distance_m); return new Distance(distance_m);
} }
public static Distance of(Double distance_m) {
if (distance_m == null) {
return Distance.of(Double.NaN);
} else {
return Distance.of((double) distance_m);
}
}
public static Distance of(String distance_m) { public static Distance of(String distance_m) {
return of(Float.parseFloat(distance_m)); return of(Float.parseFloat(distance_m));
} }
@@ -42,12 +42,13 @@ public class DistanceFormatter {
*/ */
public Pair<String, String> getDistanceParts(Distance distance) { public Pair<String, String> getDistanceParts(Distance distance) {
if (distance.isInvalid()) { if (distance.isInvalid()) {
String valueUnknown = resources.getString(R.string.value_unknown);
switch (unitSystem) { switch (unitSystem) {
case METRIC: case METRIC:
return new Pair<>(null, resources.getString(R.string.unit_meter)); return new Pair<>(valueUnknown, resources.getString(R.string.unit_meter));
case IMPERIAL: case IMPERIAL:
case NAUTICAL_IMPERIAL: case NAUTICAL_IMPERIAL:
return new Pair<>(null, resources.getString(R.string.unit_feet)); return new Pair<>(valueUnknown, resources.getString(R.string.unit_feet));
default: default:
throw new RuntimeException("Not implemented"); throw new RuntimeException("Not implemented");
} }
@@ -17,8 +17,8 @@ import androidx.documentfile.provider.DocumentFile;
import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.io.file.exporter.ExportActivity; import de.dennisguse.opentracks.io.file.exporter.ExportActivity;
import de.dennisguse.opentracks.util.IntentUtils;
import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.util.IntentUtils;
public abstract class DirectoryChooserActivity extends AppCompatActivity { public abstract class DirectoryChooserActivity extends AppCompatActivity {
@@ -34,7 +34,7 @@ public abstract class AbstractAPIActivity extends AppCompatActivity {
if (PreferencesUtils.isPublicAPIenabled()) { if (PreferencesUtils.isPublicAPIenabled()) {
Log.i(TAG, "Received and trying to execute requested action."); Log.i(TAG, "Received and trying to execute requested action.");
new TrackRecordingServiceConnection(serviceConnectedCallback) new TrackRecordingServiceConnection(serviceConnectedCallback)
.startAndBind(this); .startAndBind(this, true);
} else { } else {
Toast.makeText(this, getString(R.string.settings_public_api_disabled_toast), Toast.LENGTH_LONG).show(); Toast.makeText(this, getString(R.string.settings_public_api_disabled_toast), Toast.LENGTH_LONG).show();
Log.w(TAG, "Public API is disabled; ignoring request."); Log.w(TAG, "Public API is disabled; ignoring request.");
@@ -129,7 +129,8 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
trackRecordingManager = null; trackRecordingManager = null;
// Reverse order from onCreate // Reverse order from onCreate
showNotification(false); //TODO Why? stopForeground(true);
notificationManager.stop(); notificationManager.stop();
notificationManager = null; notificationManager = null;
@@ -205,7 +206,7 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
private void startSensors() { private void startSensors() {
wakeLock = SystemUtils.acquireWakeLock(this, wakeLock); wakeLock = SystemUtils.acquireWakeLock(this, wakeLock);
trackPointCreator.start(this, handler); trackPointCreator.start(this, handler);
showNotification(true); startForeground(TrackRecordingServiceNotificationManager.NOTIFICATION_ID, notificationManager.setGPSonlyStarted(this));
} }
public void endCurrentTrack() { public void endCurrentTrack() {
@@ -247,7 +248,8 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
if (!isRecording()) return; if (!isRecording()) return;
trackPointCreator.stop(); trackPointCreator.stop();
showNotification(false); stopForeground(true);
notificationManager.cancelNotification();
wakeLock = SystemUtils.releaseWakeLock(wakeLock); wakeLock = SystemUtils.releaseWakeLock(wakeLock);
} }
@@ -273,19 +275,6 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
} }
} }
private void showNotification(boolean isGpsStarted) {
if (isRecording()) {
startForeground(TrackRecordingServiceNotificationManager.NOTIFICATION_ID, notificationManager.setRecording(this, recordingStatus.getTrackId()));
}
if (!isRecording() && isGpsStarted) {
startForeground(TrackRecordingServiceNotificationManager.NOTIFICATION_ID, notificationManager.setGPSonlyStarted(this));
}
if (!isRecording() && !isGpsStarted) {
stopForeground(true);
notificationManager.cancelNotification();
}
}
public Marker.Id insertMarker(String name, String category, String description, String photoUrl) { public Marker.Id insertMarker(String name, String category, String description, String photoUrl) {
if (!isRecording()) { if (!isRecording()) {
return null; return null;
@@ -28,6 +28,7 @@ import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import de.dennisguse.opentracks.BuildConfig; import de.dennisguse.opentracks.BuildConfig;
import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.R;
@@ -66,15 +67,21 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
/** /**
* Starts and binds the service. * Starts and binds the service.
*
* @param foreground is the service expected to call `startForeground()`?
*/ */
public void startAndBind(Context context) { public void startAndBind(Context context, boolean foreground) {
if (trackRecordingService != null) { if (trackRecordingService != null) {
// Service is already started and bound. // Service is already started and bound.
return; return;
} }
Log.i(TAG, "Starting the service."); Log.i(TAG, "Starting the service.");
context.startService(new Intent(context, TrackRecordingService.class)); if (foreground) {
ContextCompat.startForegroundService(context, new Intent(context, TrackRecordingService.class));
} else {
context.startService(new Intent(context, TrackRecordingService.class));
}
startConnection(context); startConnection(context);
} }
@@ -88,7 +95,7 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
@Deprecated @Deprecated
public void startAndBindWithCallback(Context context) { public void startAndBindWithCallback(Context context) {
if (trackRecordingService == null) { if (trackRecordingService == null) {
startAndBind(context); startAndBind(context, false);
return; return;
} }
if (callback != null) { if (callback != null) {
@@ -68,6 +68,7 @@ class TrackRecordingServiceNotificationManager implements SharedPreferences.OnSh
} }
void stop() { void stop() {
cancelNotification();
PreferencesUtils.unregisterOnSharedPreferenceChangeListener(this); PreferencesUtils.unregisterOnSharedPreferenceChangeListener(this);
} }
@@ -5,8 +5,8 @@ import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnno
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceAverageSpeedPace; import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceAverageSpeedPace;
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceLapHeartRate; import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceLapHeartRate;
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceLapSpeedPace; import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceLapSpeedPace;
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceTotalDistance;
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceMovingTime; import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceMovingTime;
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceTotalDistance;
import android.content.Context; import android.content.Context;
import android.text.Spannable; import android.text.Spannable;
@@ -8,9 +8,6 @@ import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceFragmentCompat;
import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.services.RecordingStatus;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
public class MainSettingsFragment extends PreferenceFragmentCompat { public class MainSettingsFragment extends PreferenceFragmentCompat {
@@ -11,7 +11,6 @@ import androidx.preference.PreferenceFragmentCompat;
import de.dennisguse.opentracks.AbstractActivity; import de.dennisguse.opentracks.AbstractActivity;
import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.databinding.SettingsBinding; import de.dennisguse.opentracks.databinding.SettingsBinding;
import de.dennisguse.opentracks.databinding.TrackRecordedBinding;
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment; import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
public class SettingsActivity extends AbstractActivity implements ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller { public class SettingsActivity extends AbstractActivity implements ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller {
@@ -5,7 +5,6 @@ import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.DatePicker; import android.widget.DatePicker;
@@ -22,6 +22,8 @@ import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.core.content.ContextCompat;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@@ -169,7 +171,7 @@ public class ListItemUtils {
textView.setVisibility(View.VISIBLE); textView.setVisibility(View.VISIBLE);
textView.setText(value); textView.setText(value);
if (addShadow) { if (addShadow) {
textView.setShadowLayer(5, 0, 2, context.getResources().getColor(android.R.color.black)); textView.setShadowLayer(5, 0, 2, ContextCompat.getColor(context, android.R.color.black));
} else { } else {
textView.setShadowLayer(0, 0, 0, 0); textView.setShadowLayer(0, 0, 0, 0);
} }
@@ -27,11 +27,11 @@ abstract public class RecyclerViewSwipeDeleteCallback extends ItemTouchHelper.Ca
public RecyclerViewSwipeDeleteCallback(Context context) { public RecyclerViewSwipeDeleteCallback(Context context) {
background = new ColorDrawable(); background = new ColorDrawable();
backgroundColor = context.getResources().getColor(R.color.colorBackgroundDelete); backgroundColor = ContextCompat.getColor(context, R.color.colorBackgroundDelete);
clearPaint = new Paint(); clearPaint = new Paint();
clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
deleteDrawable = ContextCompat.getDrawable(context, R.drawable.ic_delete_forever_24dp); deleteDrawable = ContextCompat.getDrawable(context, R.drawable.ic_delete_forever_24dp);
deleteDrawable.setTint(context.getResources().getColor(R.color.colorForegroundDelete)); deleteDrawable.setTint(ContextCompat.getColor(context, R.color.colorForegroundDelete));
intrinsicWidth = deleteDrawable.getIntrinsicWidth(); intrinsicWidth = deleteDrawable.getIntrinsicWidth();
intrinsicHeight = deleteDrawable.getIntrinsicHeight(); intrinsicHeight = deleteDrawable.getIntrinsicHeight();
} }
@@ -65,7 +65,7 @@ public class EGM2008Utils {
if (location.getLongitude() >= 0) { if (location.getLongitude() >= 0) {
longitude = location.getLongitude(); longitude = location.getLongitude();
} else { } else {
longitude = 180 + Math.abs(location.getLongitude()); longitude = 360 + location.getLongitude();
} }
int longitudeIndex = (int) (longitude * RESOLUTION_IN_MINUTES); int longitudeIndex = (int) (longitude * RESOLUTION_IN_MINUTES);
@@ -172,5 +172,13 @@ public class EGM2008Utils {
public int hashCode() { public int hashCode() {
return Objects.hash(latitudeIndex, longitudeIndex); return Objects.hash(latitudeIndex, longitudeIndex);
} }
@Override
public String toString() {
return "Indices{" +
"latitudeIndex=" + latitudeIndex +
", longitudeIndex=" + longitudeIndex +
'}';
}
} }
} }
@@ -17,8 +17,6 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.regex.Pattern;
import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.Track;
@@ -254,13 +254,14 @@ public class StringUtils {
/** /**
* @return the formatted altitude_m (or null) and it's unit as {@link Pair} * @return the formatted altitude_m (or null) and it's unit as {@link Pair}
*/ */
//TODO altitude_m should be double or a value object
public static Pair<String, String> getAltitudeParts(Context context, Float altitude_m, UnitSystem unitSystem) { public static Pair<String, String> getAltitudeParts(Context context, Float altitude_m, UnitSystem unitSystem) {
DistanceFormatter formatter = DistanceFormatter.Builder() DistanceFormatter formatter = DistanceFormatter.Builder()
.setDecimalCount(1) .setDecimalCount(1)
.setUnit(unitSystem) .setUnit(unitSystem)
.build(context); .build(context);
Distance distance = altitude_m != null ? Distance.of(altitude_m) : Distance.of(Double.NaN); //TODO Refactor Double.NaN Distance distance = altitude_m != null ? Distance.of(altitude_m) : Distance.of((Double) null);
return formatter.getDistanceParts(distance); return formatter.getDistanceParts(distance);
} }
+32
View File
@@ -559,4 +559,36 @@ limitations under the License.
<string name="settings_public_api_dashboard_enabled_summary_on">Một ứng dụng bắt đầu ghi hình cũng có thể truy cập vào dữ liệu ghi lại.</string> <string name="settings_public_api_dashboard_enabled_summary_on">Một ứng dụng bắt đầu ghi hình cũng có thể truy cập vào dữ liệu ghi lại.</string>
<string name="settings_public_api_dashboard_enabled_summary_off">Ghi lại dữ liệu sẽ không được miễn phí tự động với các ứng dụng khác.</string> <string name="settings_public_api_dashboard_enabled_summary_off">Ghi lại dữ liệu sẽ không được miễn phí tự động với các ứng dụng khác.</string>
<string name="settings_public_api_dashboard_enabled_title">Chuyển dữ liệu tự động</string> <string name="settings_public_api_dashboard_enabled_title">Chuyển dữ liệu tự động</string>
<string name="settings_export_filename_title">Định dạng tên tệp</string>
<string name="show_on_dashboard_not_installed">Không có ứng dụng hỗ trợ API OpenTracks Dashboard nào được cài đặt.</string>
<string name="description_pace_nautical">Nhịp độ (phút/dặm hải lý)</string>
<string name="image_discard">Bỏ</string>
<string name="settings_announcements_average_heart_rate">Nhịp tim trung bình</string>
<string name="settings_announcements_lap_heart_rate">Nhịp tim vòng</string>
<string name="settings_announcements_average_speed_pace">Tốc độ trung bình/nhịp độ</string>
<string name="settings_stats_units_nautical">Hải lý (dặm hải lý, ft)</string>
<string name="settings_public_api_package_title">Tên gói cho API công khai</string>
<plurals name="voiceDistanceNauticalMiles">
<item quantity="other">%1$.2f dặm hải lý</item>
</plurals>
<string name="select_show_on_map_behavior">Chọn hành vi \"hiện trên bản đồ\"</string>
<string name="settings_announcements_lap_speed_pace">Tốc độ vòng/nhịp độ</string>
<string name="track_discarding">Đang bỏ đoạn đường</string>
<plurals name="voiceSpeedMKnots">
<item quantity="other">%1$.1f nút</item>
</plurals>
<string name="voice_per_nautical_mile">trên dặm hải lý</string>
<string name="description_speed_nautical">Tốc độ (nút)</string>
<string name="unit_nautical_mile">Dặm hải lý</string>
<string name="unit_knots">nút</string>
<string name="unit_minute_per_nautical_mile">phút/dặm hải lý</string>
<string name="value_integer_knots">%1$d nút</string>
<string name="value_float_knots">%1$.1f nút</string>
<string name="value_float_knots_recommended">%1$.1f nút (khuyên dùng)</string>
<string name="error_crash_title">%1$s đã dừng đột ngột</string>
<string name="share_crash_report">Chia sẻ báo cáo dừng đột ngột</string>
<string name="report_bug">Báo cáo lỗi</string>
<string name="show_on_map_format_ask">Hỏi</string>
<string name="show_on_dashboard">API OpenTracks Dashboard</string>
<string name="always">Luôn luôn</string>
</resources> </resources>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background" />
<foreground>
<inset
android:inset="20dp"
android:drawable="@drawable/ic_logo_24dp" />
</foreground>
<monochrome>
<inset
android:inset="20dp"
android:drawable="@drawable/ic_logo_24dp" />
</monochrome>
</adaptive-icon>
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_logo_24dp" />
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFF6D00</color>
</resources>