forked from upstream-mirrors/OpenTracks
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 24c2c5fc1b | |||
| 8797b033a3 | |||
| b2c4cdc4aa | |||
| ae37ec9c33 | |||
| ccc18739a4 | |||
| f48c4806b5 | |||
| 3aadf6d5d8 | |||
| 2f2679c775 | |||
| 442e23b106 | |||
| 65249f11b2 | |||
| 34b5c2ab18 | |||
| 93919183be | |||
| 1915641d78 | |||
| c2c7cad3eb | |||
| e4957e45af | |||
| 77bce9a5eb |
+3
-3
@@ -6,7 +6,7 @@ buildscript {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:8.1.0-beta02'
|
classpath 'com.android.tools.build:gradle:8.1.0-beta03'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,8 +64,8 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "de.dennisguse.opentracks"
|
applicationId "de.dennisguse.opentracks"
|
||||||
versionCode 5211
|
versionCode 5222
|
||||||
versionName "v4.3.5"
|
versionName "v4.4.0"
|
||||||
|
|
||||||
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
v4.4.0: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Export all tracks as one file
|
||||||
@@ -13,6 +13,8 @@ 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.waitFor;
|
import static de.dennisguse.opentracks.util.EspressoUtils.waitFor;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
|
||||||
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;
|
||||||
@@ -30,7 +32,11 @@ public class EspressoDeleteTrackTest {
|
|||||||
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
|
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public GrantPermissionRule mGrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
public GrantPermissionRule mGrantPermissionRuleLocation = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||||
|
@Rule
|
||||||
|
public GrantPermissionRule mGrantPermissionRuleBluetooth = GrantPermissionRule.grant(Manifest.permission.BLUETOOTH_CONNECT);
|
||||||
|
@Rule
|
||||||
|
public GrantPermissionRule mGrantPermissionRuleNotifications = GrantPermissionRule.grant(Manifest.permission.POST_NOTIFICATIONS);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void espressoDeleteTrackTest() {
|
public void espressoDeleteTrackTest() {
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
|||||||
import static org.hamcrest.Matchers.allOf;
|
import static org.hamcrest.Matchers.allOf;
|
||||||
import static de.dennisguse.opentracks.util.EspressoUtils.waitFor;
|
import static de.dennisguse.opentracks.util.EspressoUtils.waitFor;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
|
||||||
import androidx.test.espresso.ViewInteraction;
|
import androidx.test.espresso.ViewInteraction;
|
||||||
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;
|
||||||
@@ -38,7 +40,11 @@ public class EspressoEditTrackRecordingTest {
|
|||||||
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
|
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public GrantPermissionRule mGrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
public GrantPermissionRule mGrantPermissionRuleLocation = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||||
|
@Rule
|
||||||
|
public GrantPermissionRule mGrantPermissionRuleBluetooth = GrantPermissionRule.grant(android.Manifest.permission.BLUETOOTH_CONNECT);
|
||||||
|
@Rule
|
||||||
|
public GrantPermissionRule mGrantPermissionRuleNotifications = GrantPermissionRule.grant(Manifest.permission.POST_NOTIFICATIONS);
|
||||||
|
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import static org.hamcrest.Matchers.anything;
|
|||||||
import static de.dennisguse.opentracks.util.EspressoUtils.selectTabAtIndex;
|
import static de.dennisguse.opentracks.util.EspressoUtils.selectTabAtIndex;
|
||||||
import static de.dennisguse.opentracks.util.EspressoUtils.waitFor;
|
import static de.dennisguse.opentracks.util.EspressoUtils.waitFor;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
|
||||||
import androidx.test.espresso.ViewInteraction;
|
import androidx.test.espresso.ViewInteraction;
|
||||||
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;
|
||||||
@@ -31,7 +33,11 @@ public class EspressoUITest {
|
|||||||
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
|
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public GrantPermissionRule mGrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
public GrantPermissionRule mGrantPermissionRuleLocation = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||||
|
@Rule
|
||||||
|
public GrantPermissionRule mGrantPermissionRuleBluetooth = GrantPermissionRule.grant(android.Manifest.permission.BLUETOOTH_CONNECT);
|
||||||
|
@Rule
|
||||||
|
public GrantPermissionRule mGrantPermissionRuleNotifications = GrantPermissionRule.grant(Manifest.permission.POST_NOTIFICATIONS);
|
||||||
|
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
+5
-5
@@ -208,7 +208,7 @@ public class ExportImportTest {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
// 1. export
|
// 1. export
|
||||||
trackExporter.writeTrack(track, context.getContentResolver().openOutputStream(tmpFileUri));
|
trackExporter.writeTrack(List.of(track), context.getContentResolver().openOutputStream(tmpFileUri));
|
||||||
contentProviderUtils.deleteTrack(context, trackId);
|
contentProviderUtils.deleteTrack(context, trackId);
|
||||||
|
|
||||||
// 2. import
|
// 2. import
|
||||||
@@ -290,7 +290,7 @@ public class ExportImportTest {
|
|||||||
TrackExporter trackExporter = TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.createTrackExporter(context, contentProviderUtils);
|
TrackExporter trackExporter = TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.createTrackExporter(context, contentProviderUtils);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
trackExporter.writeTrack(track, context.getContentResolver().openOutputStream(tmpFileUri));
|
trackExporter.writeTrack(List.of(track), context.getContentResolver().openOutputStream(tmpFileUri));
|
||||||
|
|
||||||
// 2. import
|
// 2. import
|
||||||
InputStream inputStream = context.getContentResolver().openInputStream(tmpFileUri);
|
InputStream inputStream = context.getContentResolver().openInputStream(tmpFileUri);
|
||||||
@@ -314,7 +314,7 @@ public class ExportImportTest {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
// 1. export
|
// 1. export
|
||||||
trackExporter.writeTrack(track, context.getContentResolver().openOutputStream(tmpFileUri));
|
trackExporter.writeTrack(List.of(track), context.getContentResolver().openOutputStream(tmpFileUri));
|
||||||
contentProviderUtils.deleteTrack(context, trackId);
|
contentProviderUtils.deleteTrack(context, trackId);
|
||||||
|
|
||||||
// 2. import
|
// 2. import
|
||||||
@@ -432,7 +432,7 @@ public class ExportImportTest {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
// 1. export
|
// 1. export
|
||||||
trackExporter.writeTrack(track, context.getContentResolver().openOutputStream(tmpFileUri));
|
trackExporter.writeTrack(List.of(track), context.getContentResolver().openOutputStream(tmpFileUri));
|
||||||
|
|
||||||
// 2. import
|
// 2. import
|
||||||
InputStream inputStream = context.getContentResolver().openInputStream(tmpFileUri);
|
InputStream inputStream = context.getContentResolver().openInputStream(tmpFileUri);
|
||||||
@@ -457,7 +457,7 @@ public class ExportImportTest {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
// 1. export
|
// 1. export
|
||||||
trackExporter.writeTrack(track, context.getContentResolver().openOutputStream(tmpFileUri));
|
trackExporter.writeTrack(List.of(track), context.getContentResolver().openOutputStream(tmpFileUri));
|
||||||
contentProviderUtils.deleteTrack(context, trackId);
|
contentProviderUtils.deleteTrack(context, trackId);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
|
|||||||
+1
-1
@@ -232,7 +232,7 @@ public class GPXTrackImporterTest {
|
|||||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||||
|
|
||||||
TrackExporter trackExporter = TrackFileFormat.GPX.createTrackExporter(context, contentProviderUtils);
|
TrackExporter trackExporter = TrackFileFormat.GPX.createTrackExporter(context, contentProviderUtils);
|
||||||
trackExporter.writeTrack(importedTrack, outputStream);
|
trackExporter.writeTrack(List.of(importedTrack), outputStream);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
String expected = new BufferedReader(
|
String expected = new BufferedReader(
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ public class EGM2008UtilsTest {
|
|||||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(-14.8980, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
assertEquals(-14.8980, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -94,7 +94,7 @@ public class EGM2008UtilsTest {
|
|||||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(30.15, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
assertEquals(30.15, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -109,7 +109,7 @@ public class EGM2008UtilsTest {
|
|||||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(30.15, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
assertEquals(30.15, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -124,7 +124,7 @@ public class EGM2008UtilsTest {
|
|||||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(30.15, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
assertEquals(30.15, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -139,7 +139,7 @@ public class EGM2008UtilsTest {
|
|||||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(-17.2260, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
assertEquals(-17.2260, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -154,7 +154,7 @@ public class EGM2008UtilsTest {
|
|||||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(-39.4865, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
assertEquals(-39.4865, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -174,7 +174,7 @@ public class EGM2008UtilsTest {
|
|||||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint1.getLocation());
|
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint1.getLocation());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertNotEquals(altitude_egm2008.correctAltitude(trackPoint1.getLocation()), altitude_egm2008.correctAltitude(trackPoint2.getLocation()), 0.0001);
|
assertNotEquals(altitude_egm2008.correctAltitude(trackPoint1.getLocation()).toM(), altitude_egm2008.correctAltitude(trackPoint2.getLocation()).toM(), 0.0001);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -190,7 +190,7 @@ public class EGM2008UtilsTest {
|
|||||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(22.99, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
assertEquals(22.99, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -205,7 +205,7 @@ public class EGM2008UtilsTest {
|
|||||||
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
EGM2008Utils.EGM2008Correction altitude_egm2008 = EGM2008Utils.createCorrection(context, trackPoint.getLocation());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(-85.824, altitude_egm2008.correctAltitude(trackPoint.getLocation()), MAX_BILINEAR_ERROR);
|
assertEquals(-85.824, altitude_egm2008.correctAltitude(trackPoint.getLocation()).toM(), MAX_BILINEAR_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,14 @@ package de.dennisguse.opentracks.util;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,7 +40,7 @@ public class FileUtilsTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testBuildUniqueFileName_new() {
|
public void testBuildUniqueFileName_new() {
|
||||||
String filename = FileUtils.buildUniqueFileName(new File("/dir"), "Filename", "ext");
|
String filename = FileUtils.buildUniqueFileName(FileUtils.getPhotoDir(ApplicationProvider.getApplicationContext()), "Filename", "ext");
|
||||||
assertEquals("Filename.ext", filename);
|
assertEquals("Filename.ext", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,9 +48,14 @@ public class FileUtilsTest {
|
|||||||
* Tests {@link FileUtils#buildUniqueFileName(File, String, String)} when the file exists already.
|
* Tests {@link FileUtils#buildUniqueFileName(File, String, String)} when the file exists already.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testBuildUniqueFileName_exist() {
|
public void testBuildUniqueFileName_exist() throws IOException {
|
||||||
// Expect "/default.prop" to exist on the phone/emulator
|
// given
|
||||||
String filename = FileUtils.buildUniqueFileName(new File("/"), "default", "prop");
|
new File(FileUtils.getPhotoDir(ApplicationProvider.getApplicationContext()), "default.prop").createNewFile();
|
||||||
|
|
||||||
|
//when
|
||||||
|
String filename = FileUtils.buildUniqueFileName(FileUtils.getPhotoDir(ApplicationProvider.getApplicationContext()), "default", "prop");
|
||||||
|
|
||||||
|
// then
|
||||||
assertEquals("default(1).prop", filename);
|
assertEquals("default(1).prop", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ limitations under the License.
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<!-- NOTE: the name of the MAIN/LAUNCHER is used by icon packs; if this is changed, icon packs break.-->
|
||||||
<activity
|
<activity
|
||||||
android:name=".introduction.IntroductionActivity"
|
android:name=".introduction.IntroductionActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
@@ -348,6 +349,7 @@ limitations under the License.
|
|||||||
<activity android:name=".ui.aggregatedStatistics.AggregatedStatisticsActivity" />
|
<activity android:name=".ui.aggregatedStatistics.AggregatedStatisticsActivity" />
|
||||||
|
|
||||||
<activity android:name=".io.file.importer.DirectoryChooserActivity$ExportDirectoryChooserActivity" />
|
<activity android:name=".io.file.importer.DirectoryChooserActivity$ExportDirectoryChooserActivity" />
|
||||||
|
<activity android:name=".io.file.importer.DirectoryChooserActivity$ExportDirectoryChooserOneFileActivity" />
|
||||||
<activity android:name=".io.file.importer.DirectoryChooserActivity$DefaultTrackExportDirectoryChooserActivity" />
|
<activity android:name=".io.file.importer.DirectoryChooserActivity$DefaultTrackExportDirectoryChooserActivity" />
|
||||||
|
|
||||||
<activity android:name=".io.file.exporter.ExportActivity" />
|
<activity android:name=".io.file.exporter.ExportActivity" />
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import android.database.Cursor;
|
|||||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
import android.graphics.drawable.AnimatedVectorDrawable;
|
||||||
import android.location.LocationManager;
|
import android.location.LocationManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Vibrator;
|
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
@@ -246,7 +245,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Recording -> Stop
|
// Recording -> Stop
|
||||||
((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).vibrate(1000);
|
ActivityUtils.vibrate(this, 1000);
|
||||||
updateGpsMenuItem(false, false);
|
updateGpsMenuItem(false, false);
|
||||||
trackRecordingServiceConnection.stopRecording(TrackListActivity.this);
|
trackRecordingServiceConnection.stopRecording(TrackListActivity.this);
|
||||||
viewBinding.trackListFabAction.setImageResource(R.drawable.ic_baseline_record_24);
|
viewBinding.trackListFabAction.setImageResource(R.drawable.ic_baseline_record_24);
|
||||||
@@ -382,6 +381,12 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
|||||||
SearchView searchView = (SearchView) searchMenuItem.getActionView();
|
SearchView searchView = (SearchView) searchMenuItem.getActionView();
|
||||||
searchView.setIconified(false);
|
searchView.setIconified(false);
|
||||||
searchMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
searchMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.getItemId() == R.id.track_list_help) {
|
||||||
|
startActivity(IntentUtils.newIntent(this, HelpActivity.class));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
package de.dennisguse.opentracks;
|
package de.dennisguse.opentracks;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Vibrator;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@@ -45,6 +43,7 @@ import de.dennisguse.opentracks.settings.SettingsActivity;
|
|||||||
import de.dennisguse.opentracks.ui.intervals.IntervalsFragment;
|
import de.dennisguse.opentracks.ui.intervals.IntervalsFragment;
|
||||||
import de.dennisguse.opentracks.ui.markers.MarkerEditActivity;
|
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.ui.util.ActivityUtils;
|
||||||
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.TrackIconUtils;
|
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||||
@@ -137,7 +136,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
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(ContextCompat.getColor(this, 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);
|
ActivityUtils.vibrate(this, 1000);
|
||||||
trackRecordingServiceConnection.stopRecording(TrackRecordingActivity.this);
|
trackRecordingServiceConnection.stopRecording(TrackRecordingActivity.this);
|
||||||
Intent newIntent = IntentUtils.newIntent(TrackRecordingActivity.this, TrackStoppedActivity.class)
|
Intent newIntent = IntentUtils.newIntent(TrackRecordingActivity.this, TrackStoppedActivity.class)
|
||||||
.putExtra(TrackStoppedActivity.EXTRA_TRACK_ID, trackId);
|
.putExtra(TrackStoppedActivity.EXTRA_TRACK_ID, trackId);
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ public class ShareContentProvider extends CustomContentProvider {
|
|||||||
PipeDataWriter<String> pipeDataWriter = (output, uri1, mimeType, opts, args) -> {
|
PipeDataWriter<String> pipeDataWriter = (output, uri1, mimeType, opts, args) -> {
|
||||||
try (FileOutputStream fileOutputStream = new FileOutputStream(output.getFileDescriptor())) {
|
try (FileOutputStream fileOutputStream = new FileOutputStream(output.getFileDescriptor())) {
|
||||||
// TODO handle failure (i.e., do not export an empty file)
|
// TODO handle failure (i.e., do not export an empty file)
|
||||||
trackExporter.writeTrack(tracks.toArray(new Track[0]), fileOutputStream);
|
trackExporter.writeTrack(tracks, fileOutputStream);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, "there occurred an error while sharing a file: " + e);
|
Log.w(TAG, "there occurred an error while sharing a file: " + e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ public abstract class Altitude {
|
|||||||
return altitude_m;
|
return altitude_m;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Altitude replace(double altitude_m);
|
|
||||||
|
|
||||||
public abstract int getLabelId();
|
public abstract int getLabelId();
|
||||||
|
|
||||||
public static class WGS84 extends Altitude {
|
public static class WGS84 extends Altitude {
|
||||||
@@ -31,12 +29,7 @@ public abstract class Altitude {
|
|||||||
return R.string.wgs84;
|
return R.string.wgs84;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Altitude of(double altitude_m) {
|
public static WGS84 of(double altitude_m) {
|
||||||
return new WGS84(altitude_m);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Altitude replace(double altitude_m) {
|
|
||||||
return new WGS84(altitude_m);
|
return new WGS84(altitude_m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,12 +45,7 @@ public abstract class Altitude {
|
|||||||
return R.string.egm2008;
|
return R.string.egm2008;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Altitude of(double altitude_m) {
|
public static EGM2008 of(double altitude_m) {
|
||||||
return new EGM2008(altitude_m);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Altitude replace(double altitude_m) {
|
|
||||||
return new EGM2008(altitude_m);
|
return new EGM2008(altitude_m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package de.dennisguse.opentracks.data.models;
|
||||||
|
|
||||||
|
public class BatteryLevel {
|
||||||
|
|
||||||
|
public static BatteryLevel of(int percentage) {
|
||||||
|
return new BatteryLevel(percentage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final int percentage;
|
||||||
|
|
||||||
|
private BatteryLevel(int percentage) {
|
||||||
|
this.percentage = percentage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPercentage() {
|
||||||
|
return percentage;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,10 @@ public class TrackFilenameGenerator {
|
|||||||
.collect(Collectors.joining(", "));
|
.collect(Collectors.joining(", "));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String format(@NonNull String name, @NonNull TrackFileFormat trackFileFormat) {
|
||||||
|
return FileUtils.sanitizeFileName(name + "." + trackFileFormat.getExtension());
|
||||||
|
}
|
||||||
|
|
||||||
private final String template;
|
private final String template;
|
||||||
|
|
||||||
public TrackFilenameGenerator(@NonNull String template) {
|
public TrackFilenameGenerator(@NonNull String template) {
|
||||||
@@ -44,7 +48,7 @@ public class TrackFilenameGenerator {
|
|||||||
values.put(STARTTIME_TIME_KEY, track.getStartTime().toLocalTime().toString());
|
values.put(STARTTIME_TIME_KEY, track.getStartTime().toLocalTime().toString());
|
||||||
values.put(STARTTIME_DATE_KEY, track.getStartTime().toLocalDate().toString());
|
values.put(STARTTIME_DATE_KEY, track.getStartTime().toLocalDate().toString());
|
||||||
|
|
||||||
return FileUtils.sanitizeFileName(format(template, values)) + "." + trackFileFormat.getExtension();
|
return format(format(template, values), trackFileFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String format(String template, Map<String, String> values) {
|
private static String format(String template, Map<String, String> values) {
|
||||||
@@ -77,10 +81,6 @@ public class TrackFilenameGenerator {
|
|||||||
return String.format(templateCompiled, valueList.toArray());
|
return String.format(templateCompiled, valueList.toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTemplate() {
|
|
||||||
return template;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isValid() {
|
public boolean isValid() {
|
||||||
try {
|
try {
|
||||||
getExample();
|
getExample();
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ import androidx.annotation.NonNull;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@@ -87,15 +85,23 @@ public class CSVTrackExporter implements TrackExporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean writeTrack(Track track, @NonNull OutputStream outputStream) {
|
public boolean writeTrack(@NonNull List<Track> tracks, @NonNull OutputStream outputStream) {
|
||||||
return writeTrack(new Track[]{track}, outputStream);
|
List<Column> columns = List.of(
|
||||||
}
|
new Column("time", null),
|
||||||
|
new Column("trackpoint_type", t -> quote(t.getType().name())),
|
||||||
|
new Column("latitude", t -> t.hasLocation() ? COORDINATE_FORMAT.format(t.getLatitude()) : ""),
|
||||||
|
new Column("longitude", t -> t.hasLocation() ? COORDINATE_FORMAT.format(t.getLongitude()) : ""),
|
||||||
|
new Column("altitude", t -> t.hasAltitude() ? COORDINATE_FORMAT.format(t.getAltitude().toM()) : ""),
|
||||||
|
new Column("accuracy_horizontal", t -> t.hasHorizontalAccuracy() ? DISTANCE_FORMAT.format(t.getHorizontalAccuracy().toM()) : ""),
|
||||||
|
new Column("accuracy_vertical", t -> t.hasVerticalAccuracy() ? DISTANCE_FORMAT.format(t.getVerticalAccuracy().toM()) : ""),
|
||||||
|
|
||||||
@Override
|
new Column("speed", t -> t.hasSpeed() ? SPEED_FORMAT.format(t.getSpeed().toKMH()) : ""),
|
||||||
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
new Column("altitude_gain", t -> t.hasAltitudeGain() ? DISTANCE_FORMAT.format(t.getAltitudeGain()) : ""),
|
||||||
List<Column> columns = Collections.unmodifiableList(Arrays.asList(new Column("time", null), new Column("trackpoint_type", t -> quote(t.getType().name())), new Column("latitude", t -> t.hasLocation() ? COORDINATE_FORMAT.format(t.getLatitude()) : ""), new Column("longitude", t -> t.hasLocation() ? COORDINATE_FORMAT.format(t.getLongitude()) : ""), new Column("altitude", t -> t.hasAltitude() ? COORDINATE_FORMAT.format(t.getAltitude().toM()) : ""), new Column("accuracy_horizontal", t -> t.hasHorizontalAccuracy() ? DISTANCE_FORMAT.format(t.getHorizontalAccuracy().toM()) : ""), new Column("accuracy_vertical", t -> t.hasVerticalAccuracy() ? DISTANCE_FORMAT.format(t.getVerticalAccuracy().toM()) : ""),
|
new Column("altitude_loss", t -> t.hasAltitudeLoss() ? DISTANCE_FORMAT.format(t.getAltitudeLoss()) : ""),
|
||||||
|
new Column("sensor_distance", t -> t.hasSensorDistance() ? DISTANCE_FORMAT.format(t.getSensorDistance().toM()) : ""),
|
||||||
new Column("speed", t -> t.hasSpeed() ? SPEED_FORMAT.format(t.getSpeed().toKMH()) : ""), new Column("altitude_gain", t -> t.hasAltitudeGain() ? DISTANCE_FORMAT.format(t.getAltitudeGain()) : ""), new Column("altitude_loss", t -> t.hasAltitudeLoss() ? DISTANCE_FORMAT.format(t.getAltitudeLoss()) : ""), new Column("sensor_distance", t -> t.hasSensorDistance() ? DISTANCE_FORMAT.format(t.getSensorDistance().toM()) : ""), new Column("heartrate", t -> t.hasHeartRate() ? HEARTRATE_FORMAT.format(t.getHeartRate().getBPM()) : ""), new Column("cadence", t -> t.hasCadence() ? CADENCE_FORMAT.format(t.getCadence().getRPM()) : ""), new Column("power", t -> t.hasPower() ? ALTITUDE_FORMAT.format(t.getPower().getW()) : "")));
|
new Column("heartrate", t -> t.hasHeartRate() ? HEARTRATE_FORMAT.format(t.getHeartRate().getBPM()) : ""),
|
||||||
|
new Column("cadence", t -> t.hasCadence() ? CADENCE_FORMAT.format(t.getCadence().getRPM()) : ""),
|
||||||
|
new Column("power", t -> t.hasPower() ? ALTITUDE_FORMAT.format(t.getPower().getW()) : ""));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
prepare(outputStream);
|
prepare(outputStream);
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package de.dennisguse.opentracks.io.file.exporter;
|
package de.dennisguse.opentracks.io.file.exporter;
|
||||||
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -24,6 +23,7 @@ import android.view.View;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.documentfile.provider.DocumentFile;
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
@@ -31,14 +31,15 @@ import androidx.fragment.app.FragmentActivity;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.data.models.Track;
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
import de.dennisguse.opentracks.data.tables.TracksColumns;
|
|
||||||
import de.dennisguse.opentracks.databinding.ExportActivityBinding;
|
import de.dennisguse.opentracks.databinding.ExportActivityBinding;
|
||||||
import de.dennisguse.opentracks.io.file.ErrorListDialog;
|
import de.dennisguse.opentracks.io.file.ErrorListDialog;
|
||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
|
import de.dennisguse.opentracks.io.file.TrackFilenameGenerator;
|
||||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
import de.dennisguse.opentracks.util.ExportUtils;
|
import de.dennisguse.opentracks.util.ExportUtils;
|
||||||
import de.dennisguse.opentracks.util.FileUtils;
|
import de.dennisguse.opentracks.util.FileUtils;
|
||||||
@@ -47,12 +48,20 @@ import de.dennisguse.opentracks.util.FileUtils;
|
|||||||
* An activity for saving tracks to the external storage.
|
* An activity for saving tracks to the external storage.
|
||||||
*
|
*
|
||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
|
* TODO: This class needs some refactoring.
|
||||||
|
* * It pushes each export job (usually one Track) for export; although export could be run in parallel.
|
||||||
|
* Also this requires that the ExportActivity stays in foreground, so the user has to activily wait.
|
||||||
|
* It would be better to let the ExportService handle this and let it report progress / conflicts to ExportActivity
|
||||||
|
* * File name conflicts are checked in this class instead of the ExportService.
|
||||||
|
* So, for this check actually a different file name might be used than in the ExportService.
|
||||||
|
* * Saved state as an object instead of individual values.
|
||||||
*/
|
*/
|
||||||
public class ExportActivity extends FragmentActivity implements ExportServiceResultReceiver.Receiver {
|
public class ExportActivity extends FragmentActivity implements ExportServiceResultReceiver.Receiver {
|
||||||
|
|
||||||
private static final String TAG = ExportActivity.class.getSimpleName();
|
private static final String TAG = ExportActivity.class.getSimpleName();
|
||||||
|
|
||||||
public static final String EXTRA_DIRECTORY_URI_KEY = "directory_uri";
|
public static final String EXTRA_DIRECTORY_URI_KEY = "directory_uri";
|
||||||
|
public static final String EXTRA_ONE_FILE_KEY = "one_file";
|
||||||
public static final String EXTRA_TRACKFILEFORMAT_KEY = "trackfileformat";
|
public static final String EXTRA_TRACKFILEFORMAT_KEY = "trackfileformat";
|
||||||
|
|
||||||
private static final String BUNDLE_AUTO_CONFLICT = "auto_conflict";
|
private static final String BUNDLE_AUTO_CONFLICT = "auto_conflict";
|
||||||
@@ -64,9 +73,13 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
private static final String BUNDLE_DIRECTORY_FILES = "track_directory_files";
|
private static final String BUNDLE_DIRECTORY_FILES = "track_directory_files";
|
||||||
private static final String BUNDLE_TRACK_ERRORS = "track_errors";
|
private static final String BUNDLE_TRACK_ERRORS = "track_errors";
|
||||||
|
|
||||||
private static final int CONFLICT_NONE = 0;
|
private static final String BUNDLE_EXPORT_TASKS = "export_tasks";
|
||||||
private static final int CONFLICT_OVERWRITE = 1;
|
|
||||||
private static final int CONFLICT_SKIP = 2;
|
private enum ConflictResolutionStrategy {
|
||||||
|
CONFLICT_NONE,
|
||||||
|
CONFLICT_OVERWRITE,
|
||||||
|
CONFLICT_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
private TrackFileFormat trackFileFormat;
|
private TrackFileFormat trackFileFormat;
|
||||||
private Uri directoryUri;
|
private Uri directoryUri;
|
||||||
@@ -87,12 +100,12 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
|
|
||||||
private ArrayList<String> trackErrors = new ArrayList<>();
|
private ArrayList<String> trackErrors = new ArrayList<>();
|
||||||
|
|
||||||
private int autoConflict;
|
private ConflictResolutionStrategy autoConflict;
|
||||||
|
|
||||||
private ContentProviderUtils contentProviderUtils;
|
private ContentProviderUtils contentProviderUtils;
|
||||||
|
|
||||||
// List of tracks to be exported.
|
// List of tracks to be exported.
|
||||||
private final ArrayList<Track> tracks = new ArrayList<>();
|
private ArrayList<ExportTask> exportTasks;
|
||||||
|
|
||||||
private final LinkedBlockingQueue<PendingConflict> conflictsQueue = new LinkedBlockingQueue<>();
|
private final LinkedBlockingQueue<PendingConflict> conflictsQueue = new LinkedBlockingQueue<>();
|
||||||
private final Handler conflictsHandler = new Handler();
|
private final Handler conflictsHandler = new Handler();
|
||||||
@@ -100,7 +113,10 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
private final Runnable conflictsRunnable = new Runnable() {
|
private final Runnable conflictsRunnable = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (conflictsQueue.size() > 0) {
|
if (conflictsQueue.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
PendingConflict conflict = conflictsQueue.peek();
|
PendingConflict conflict = conflictsQueue.peek();
|
||||||
if (conflict.resolve()) {
|
if (conflict.resolve()) {
|
||||||
conflictsQueue.remove(conflict);
|
conflictsQueue.remove(conflict);
|
||||||
@@ -128,7 +144,6 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -139,6 +154,7 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
|
|
||||||
directoryUri = getIntent().getParcelableExtra(EXTRA_DIRECTORY_URI_KEY);
|
directoryUri = getIntent().getParcelableExtra(EXTRA_DIRECTORY_URI_KEY);
|
||||||
trackFileFormat = (TrackFileFormat) getIntent().getSerializableExtra(EXTRA_TRACKFILEFORMAT_KEY);
|
trackFileFormat = (TrackFileFormat) getIntent().getSerializableExtra(EXTRA_TRACKFILEFORMAT_KEY);
|
||||||
|
boolean allInOneFile = getIntent().getBooleanExtra(EXTRA_ONE_FILE_KEY, false);
|
||||||
|
|
||||||
contentProviderUtils = new ContentProviderUtils(this);
|
contentProviderUtils = new ContentProviderUtils(this);
|
||||||
|
|
||||||
@@ -148,14 +164,17 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
resultReceiver = new ExportServiceResultReceiver(new Handler(), this);
|
resultReceiver = new ExportServiceResultReceiver(new Handler(), this);
|
||||||
|
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
autoConflict = CONFLICT_NONE;
|
autoConflict = ConflictResolutionStrategy.CONFLICT_NONE;
|
||||||
setProgress();
|
setProgress();
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
directoryFiles = ExportUtils.getAllFiles(ExportActivity.this, documentFile.getUri());
|
directoryFiles = ExportUtils.getAllFiles(ExportActivity.this, documentFile.getUri());
|
||||||
runOnUiThread(() -> initExport(0));
|
runOnUiThread(() -> {
|
||||||
|
createExportTasks(allInOneFile);
|
||||||
|
nextExport(null);
|
||||||
|
});
|
||||||
}).start();
|
}).start();
|
||||||
} else {
|
} else {
|
||||||
autoConflict = savedInstanceState.getInt(BUNDLE_AUTO_CONFLICT);
|
autoConflict = ConflictResolutionStrategy.valueOf(savedInstanceState.getString(BUNDLE_AUTO_CONFLICT));
|
||||||
trackExportSuccessCount = savedInstanceState.getInt(BUNDLE_SUCCESS_COUNT);
|
trackExportSuccessCount = savedInstanceState.getInt(BUNDLE_SUCCESS_COUNT);
|
||||||
trackExportErrorCount = savedInstanceState.getInt(BUNDLE_ERROR_COUNT);
|
trackExportErrorCount = savedInstanceState.getInt(BUNDLE_ERROR_COUNT);
|
||||||
trackExportOverwrittenCount = savedInstanceState.getInt(BUNDLE_OVERWRITTEN_COUNT);
|
trackExportOverwrittenCount = savedInstanceState.getInt(BUNDLE_OVERWRITTEN_COUNT);
|
||||||
@@ -163,9 +182,9 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
trackExportTotalCount = savedInstanceState.getInt(BUNDLE_TOTAL_COUNT);
|
trackExportTotalCount = savedInstanceState.getInt(BUNDLE_TOTAL_COUNT);
|
||||||
directoryFiles = savedInstanceState.getStringArrayList(BUNDLE_DIRECTORY_FILES);
|
directoryFiles = savedInstanceState.getStringArrayList(BUNDLE_DIRECTORY_FILES);
|
||||||
trackErrors = savedInstanceState.getStringArrayList(BUNDLE_TRACK_ERRORS);
|
trackErrors = savedInstanceState.getStringArrayList(BUNDLE_TRACK_ERRORS);
|
||||||
|
exportTasks = new ArrayList<>(savedInstanceState.getParcelableArrayList(BUNDLE_EXPORT_TASKS));
|
||||||
setProgress();
|
setProgress();
|
||||||
initExport(getTotalDone());
|
nextExport(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
viewBinding.bottomAppBarLayout.bottomAppBarTitle.setText(getString(R.string.export_progress_message, directoryDisplayName));
|
viewBinding.bottomAppBarLayout.bottomAppBarTitle.setText(getString(R.string.export_progress_message, directoryDisplayName));
|
||||||
@@ -175,7 +194,7 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putInt(BUNDLE_AUTO_CONFLICT, autoConflict);
|
outState.putString(BUNDLE_AUTO_CONFLICT, autoConflict.name());
|
||||||
outState.putInt(BUNDLE_SUCCESS_COUNT, trackExportSuccessCount);
|
outState.putInt(BUNDLE_SUCCESS_COUNT, trackExportSuccessCount);
|
||||||
outState.putInt(BUNDLE_ERROR_COUNT, trackExportErrorCount);
|
outState.putInt(BUNDLE_ERROR_COUNT, trackExportErrorCount);
|
||||||
outState.putInt(BUNDLE_OVERWRITTEN_COUNT, trackExportOverwrittenCount);
|
outState.putInt(BUNDLE_OVERWRITTEN_COUNT, trackExportOverwrittenCount);
|
||||||
@@ -183,13 +202,14 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
outState.putInt(BUNDLE_TOTAL_COUNT, trackExportTotalCount);
|
outState.putInt(BUNDLE_TOTAL_COUNT, trackExportTotalCount);
|
||||||
outState.putStringArrayList(BUNDLE_DIRECTORY_FILES, (ArrayList<String>) directoryFiles);
|
outState.putStringArrayList(BUNDLE_DIRECTORY_FILES, (ArrayList<String>) directoryFiles);
|
||||||
outState.putStringArrayList(BUNDLE_TRACK_ERRORS, trackErrors);
|
outState.putStringArrayList(BUNDLE_TRACK_ERRORS, trackErrors);
|
||||||
|
outState.putParcelableArrayList(BUNDLE_EXPORT_TASKS, exportTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
conflictsQueue.clear();
|
conflictsQueue.clear();
|
||||||
tracks.clear();
|
exportTasks.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -205,54 +225,47 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
new Handler().postDelayed(() -> doubleBackToCancel = false, 2000);
|
new Handler().postDelayed(() -> doubleBackToCancel = false, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initExport(int from) {
|
private void createExportTasks(boolean allInOneFile) {
|
||||||
try (Cursor cursor = contentProviderUtils.getTrackCursor(null, null, TracksColumns._ID)) {
|
List<Track> tracks = contentProviderUtils.getTracks();
|
||||||
if (cursor == null) {
|
exportTasks = new ArrayList<>();
|
||||||
onExportEnded();
|
if (allInOneFile) {
|
||||||
return;
|
String filename = "OpenTracks-Backup";
|
||||||
}
|
exportTasks.add(new ExportTask(filename, trackFileFormat, tracks.stream().map(Track::getId).collect(Collectors.toList())));
|
||||||
|
|
||||||
trackExportTotalCount = cursor.getCount();
|
|
||||||
viewBinding.exportProgressTotal.setText("" + trackExportTotalCount);
|
|
||||||
for (int i = from; i < trackExportTotalCount; i++) {
|
|
||||||
cursor.moveToPosition(i);
|
|
||||||
Track track = ContentProviderUtils.createTrack(cursor);
|
|
||||||
tracks.add(track);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tracks.isEmpty()) {
|
|
||||||
export(tracks.get(0));
|
|
||||||
} else {
|
} else {
|
||||||
onExportEnded();
|
exportTasks.addAll(tracks.stream().map(it -> new ExportTask(null, trackFileFormat, List.of(it.getId()))).collect(Collectors.toList()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
trackExportTotalCount = exportTasks.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enqueue track identified by UUID to be exported if not exported already or there is a conflict resolution.
|
* Enqueue track identified by UUID to be exported if not exported already or there is a conflict resolution.
|
||||||
*
|
|
||||||
* @param track Track object.
|
|
||||||
* @param conflictResolution conflict resolution to be applied if needed.
|
|
||||||
*/
|
*/
|
||||||
private void export(Track track, int conflictResolution) {
|
private void export(ExportTask exportTask, ConflictResolutionStrategy conflictResolution) {
|
||||||
boolean fileExists = exportFileExists(track);
|
boolean fileExists = exportFileExists(exportTask);
|
||||||
|
|
||||||
if (fileExists && conflictResolution == CONFLICT_NONE) {
|
if (fileExists && conflictResolution == ConflictResolutionStrategy.CONFLICT_NONE) {
|
||||||
conflict(track);
|
conflict(exportTask);
|
||||||
} else if (fileExists && conflictResolution == CONFLICT_SKIP) {
|
} else if (fileExists && conflictResolution == ConflictResolutionStrategy.CONFLICT_SKIP) {
|
||||||
trackExportSkippedCount++;
|
trackExportSkippedCount++;
|
||||||
onExportCompleted(track);
|
nextExport(exportTask);
|
||||||
} else {
|
} else {
|
||||||
ExportService.enqueue(this, resultReceiver, track.getId(), trackFileFormat, directoryUri);
|
ExportService.enqueue(this, resultReceiver, exportTask, directoryUri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void export(Track track) {
|
private void export(ExportTask exportTask) {
|
||||||
export(track, autoConflict);
|
export(exportTask, autoConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean exportFileExists(Track track) {
|
@Deprecated //TODO Check should be done in ExportService
|
||||||
String filename = PreferencesUtils.getTrackFileformatGenerator().format(track, trackFileFormat);
|
private boolean exportFileExists(ExportTask exportTask) {
|
||||||
|
String filename;
|
||||||
|
if (exportTask.isMultiExport()) {
|
||||||
|
filename = TrackFilenameGenerator.format(exportTask.getFilename(), exportTask.getTrackFileFormat());
|
||||||
|
} else {
|
||||||
|
Track track = contentProviderUtils.getTrack(exportTask.getTrackIds().get(0));
|
||||||
|
filename = PreferencesUtils.getTrackFileformatGenerator().format(track, trackFileFormat);
|
||||||
|
}
|
||||||
return directoryFiles.stream().anyMatch(filename::equals);
|
return directoryFiles.stream().anyMatch(filename::equals);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,31 +282,29 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setProgress() {
|
private void setProgress() {
|
||||||
int done = getTotalDone();
|
viewBinding.exportProgressDone.setText("" + getTotalDone());
|
||||||
|
|
||||||
viewBinding.exportProgressDone.setText("" + done);
|
|
||||||
viewBinding.exportProgressTotal.setText("" + trackExportTotalCount);
|
viewBinding.exportProgressTotal.setText("" + trackExportTotalCount);
|
||||||
|
|
||||||
viewBinding.exportProgressBar.setProgress((int) ((float) done / (float) trackExportTotalCount * 100f));
|
viewBinding.exportProgressBar.setProgress((int) ((float) getTotalDone() / (float) trackExportTotalCount * 100f));
|
||||||
viewBinding.exportProgressSummaryNew.setText(String.valueOf(trackExportSuccessCount));
|
viewBinding.exportProgressSummaryNew.setText("" + trackExportSuccessCount);
|
||||||
viewBinding.exportProgressSummaryOverwrite.setText(String.valueOf(trackExportOverwrittenCount));
|
viewBinding.exportProgressSummaryOverwrite.setText("" + trackExportOverwrittenCount);
|
||||||
viewBinding.exportProgressSummarySkip.setText(String.valueOf(trackExportSkippedCount));
|
viewBinding.exportProgressSummarySkip.setText("" + trackExportSkippedCount);
|
||||||
viewBinding.exportProgressSummaryErrors.setText(String.valueOf(trackExportErrorCount));
|
viewBinding.exportProgressSummaryErrors.setText("" + trackExportErrorCount);
|
||||||
viewBinding.exportProgressSummaryNewGroup.setVisibility(trackExportSuccessCount > 0 ? View.VISIBLE : View.GONE);
|
viewBinding.exportProgressSummaryNewGroup.setVisibility(trackExportSuccessCount > 0 ? View.VISIBLE : View.GONE);
|
||||||
viewBinding.exportProgressSummaryOverwriteGroup.setVisibility(trackExportOverwrittenCount > 0 ? View.VISIBLE : View.GONE);
|
viewBinding.exportProgressSummaryOverwriteGroup.setVisibility(trackExportOverwrittenCount > 0 ? View.VISIBLE : View.GONE);
|
||||||
viewBinding.exportProgressSummarySkipGroup.setVisibility(trackExportSkippedCount > 0 ? View.VISIBLE : View.GONE);
|
viewBinding.exportProgressSummarySkipGroup.setVisibility(trackExportSkippedCount > 0 ? View.VISIBLE : View.GONE);
|
||||||
viewBinding.exportProgressSummaryErrorsGroup.setVisibility(trackExportErrorCount > 0 ? View.VISIBLE : View.GONE);
|
viewBinding.exportProgressSummaryErrorsGroup.setVisibility(trackExportErrorCount > 0 ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onExportCompleted(Track track) {
|
private void nextExport(@Nullable ExportTask exportTask) {
|
||||||
tracks.remove(track);
|
exportTasks.remove(exportTask);
|
||||||
|
|
||||||
setProgress();
|
setProgress();
|
||||||
if (tracks.isEmpty()) {
|
if (exportTasks.isEmpty()) {
|
||||||
onExportEnded();
|
onExportEnded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
export(tracks.get(0));
|
export(exportTasks.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onExportEnded() {
|
private void onExportEnded() {
|
||||||
@@ -318,30 +329,32 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExportSuccess(Track.Id trackId) {
|
public void onExportSuccess(ExportTask exportTask) {
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
if (exportFileExists(exportTask)) {
|
||||||
|
|
||||||
if (exportFileExists(track)) {
|
|
||||||
trackExportOverwrittenCount++;
|
trackExportOverwrittenCount++;
|
||||||
} else {
|
} else {
|
||||||
trackExportSuccessCount++;
|
trackExportSuccessCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
onExportCompleted(track);
|
nextExport(exportTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExportError(Track.Id trackId) {
|
public void onExportError(ExportTask exportTask) {
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
|
||||||
|
|
||||||
trackExportErrorCount++;
|
trackExportErrorCount++;
|
||||||
trackErrors.add(track.getName());
|
String name;
|
||||||
|
if (exportTask.isMultiExport()) {
|
||||||
|
name = exportTask.getFilename();
|
||||||
|
} else {
|
||||||
|
name = contentProviderUtils.getTrack(exportTask.getTrackIds().get(0)).getName();
|
||||||
|
}
|
||||||
|
trackErrors.add(name);
|
||||||
|
|
||||||
onExportCompleted(track);
|
nextExport(exportTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void conflict(Track track) {
|
private void conflict(ExportTask exportTask) {
|
||||||
PendingConflict newConflict = new PendingConflict(track);
|
PendingConflict newConflict = new PendingConflict(exportTask);
|
||||||
conflictsQueue.add(newConflict);
|
conflictsQueue.add(newConflict);
|
||||||
|
|
||||||
if (conflictsQueue.size() == 1) {
|
if (conflictsQueue.size() == 1) {
|
||||||
@@ -353,10 +366,10 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
* Handle conflicts (exporting file already exists).
|
* Handle conflicts (exporting file already exists).
|
||||||
*/
|
*/
|
||||||
private class PendingConflict {
|
private class PendingConflict {
|
||||||
private final Track track;
|
private final ExportTask exportTask;
|
||||||
|
|
||||||
public PendingConflict(Track track) {
|
public PendingConflict(ExportTask exportTask) {
|
||||||
this.track = track;
|
this.exportTask = exportTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -366,14 +379,20 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
* @return true if it could resolve the conflict or false otherwise.
|
* @return true if it could resolve the conflict or false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean resolve() {
|
public boolean resolve() {
|
||||||
if (autoConflict == CONFLICT_NONE) {
|
if (autoConflict == ConflictResolutionStrategy.CONFLICT_NONE) {
|
||||||
viewBinding.exportProgressAlertIcon.setImageDrawable(ContextCompat.getDrawable(ExportActivity.this, R.drawable.ic_report_problem_24));
|
viewBinding.exportProgressAlertIcon.setImageDrawable(ContextCompat.getDrawable(ExportActivity.this, R.drawable.ic_report_problem_24));
|
||||||
viewBinding.exportProgressAlertMsg.setText(getString(R.string.export_track_already_exists_msg, track.getName()));
|
String name;
|
||||||
|
if (exportTask.isMultiExport()) {
|
||||||
|
name = exportTask.getFilename();
|
||||||
|
} else {
|
||||||
|
name = contentProviderUtils.getTrack(exportTask.getTrackIds().get(0)).getName();
|
||||||
|
}
|
||||||
|
viewBinding.exportProgressAlertMsg.setText(getString(R.string.export_track_already_exists_msg, name));
|
||||||
setConflictVisibility(View.VISIBLE);
|
setConflictVisibility(View.VISIBLE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export(track);
|
export(exportTask);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,10 +400,10 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
* Overwrite the export file and set the autoConflict if user set the "do it for all" switch button.
|
* Overwrite the export file and set the autoConflict if user set the "do it for all" switch button.
|
||||||
*/
|
*/
|
||||||
public void overwrite() {
|
public void overwrite() {
|
||||||
export(track, CONFLICT_OVERWRITE);
|
export(exportTask, ConflictResolutionStrategy.CONFLICT_OVERWRITE);
|
||||||
|
|
||||||
if (viewBinding.exportProgressApplyToAll.isChecked()) {
|
if (viewBinding.exportProgressApplyToAll.isChecked()) {
|
||||||
autoConflict = CONFLICT_OVERWRITE;
|
autoConflict = ConflictResolutionStrategy.CONFLICT_OVERWRITE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,10 +411,10 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
* Skip the export file and set the autoConflict if user set the "do it for all" switch button.
|
* Skip the export file and set the autoConflict if user set the "do it for all" switch button.
|
||||||
*/
|
*/
|
||||||
public void skip() {
|
public void skip() {
|
||||||
export(track, CONFLICT_SKIP);
|
export(exportTask, ConflictResolutionStrategy.CONFLICT_SKIP);
|
||||||
|
|
||||||
if (viewBinding.exportProgressApplyToAll.isChecked()) {
|
if (viewBinding.exportProgressApplyToAll.isChecked()) {
|
||||||
autoConflict = CONFLICT_SKIP;
|
autoConflict = ConflictResolutionStrategy.CONFLICT_SKIP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.core.app.JobIntentService;
|
import androidx.core.app.JobIntentService;
|
||||||
import androidx.documentfile.provider.DocumentFile;
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.data.models.Track;
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
@@ -22,16 +25,14 @@ public class ExportService extends JobIntentService {
|
|||||||
private static final int JOB_ID = 1;
|
private static final int JOB_ID = 1;
|
||||||
|
|
||||||
private static final String EXTRA_RECEIVER = "extra_receiver";
|
private static final String EXTRA_RECEIVER = "extra_receiver";
|
||||||
private static final String EXTRA_TRACK_ID = "extra_track_id";
|
private static final String EXTRA_EXPORT_TASK = "export_task";
|
||||||
private static final String EXTRA_TRACK_FILE_FORMAT = "extra_track_file_format";
|
|
||||||
private static final String EXTRA_DIRECTORY_URI = "extra_directory_uri";
|
private static final String EXTRA_DIRECTORY_URI = "extra_directory_uri";
|
||||||
private static final String TAG = ExportService.class.getSimpleName();
|
private static final String TAG = ExportService.class.getSimpleName();
|
||||||
|
|
||||||
public static void enqueue(Context context, ExportServiceResultReceiver receiver, Track.Id trackId, TrackFileFormat trackFileFormat, Uri directoryUri) {
|
public static void enqueue(Context context, ExportServiceResultReceiver receiver, ExportTask exportTask, Uri directoryUri) {
|
||||||
Intent intent = new Intent(context, JobService.class);
|
Intent intent = new Intent(context, JobService.class);
|
||||||
intent.putExtra(EXTRA_RECEIVER, receiver);
|
intent.putExtra(EXTRA_RECEIVER, receiver);
|
||||||
intent.putExtra(EXTRA_TRACK_ID, trackId);
|
intent.putExtra(EXTRA_EXPORT_TASK, exportTask);
|
||||||
intent.putExtra(EXTRA_TRACK_FILE_FORMAT, trackFileFormat);
|
|
||||||
intent.putExtra(EXTRA_DIRECTORY_URI, directoryUri);
|
intent.putExtra(EXTRA_DIRECTORY_URI, directoryUri);
|
||||||
enqueueWork(context, ExportService.class, JOB_ID, intent);
|
enqueueWork(context, ExportService.class, JOB_ID, intent);
|
||||||
}
|
}
|
||||||
@@ -40,13 +41,12 @@ public class ExportService extends JobIntentService {
|
|||||||
protected void onHandleWork(@NonNull Intent intent) {
|
protected void onHandleWork(@NonNull Intent intent) {
|
||||||
// Get all data.
|
// Get all data.
|
||||||
ResultReceiver resultReceiver = intent.getParcelableExtra(EXTRA_RECEIVER);
|
ResultReceiver resultReceiver = intent.getParcelableExtra(EXTRA_RECEIVER);
|
||||||
Track.Id trackId = intent.getParcelableExtra(EXTRA_TRACK_ID);
|
ExportTask exportTask = intent.getParcelableExtra(EXTRA_EXPORT_TASK);
|
||||||
TrackFileFormat trackFileFormat = (TrackFileFormat) intent.getSerializableExtra(EXTRA_TRACK_FILE_FORMAT);
|
|
||||||
Uri directoryUri = intent.getParcelableExtra(EXTRA_DIRECTORY_URI);
|
Uri directoryUri = intent.getParcelableExtra(EXTRA_DIRECTORY_URI);
|
||||||
|
|
||||||
// Prepare resultCode and bundle to send to the receiver.
|
// Prepare resultCode and bundle to send to the receiver.
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putParcelable(ExportServiceResultReceiver.RESULT_EXTRA_TRACK_ID, trackId);
|
bundle.putParcelable(ExportServiceResultReceiver.RESULT_EXTRA_EXPORT_TASK, exportTask);
|
||||||
|
|
||||||
// Build directory file.
|
// Build directory file.
|
||||||
DocumentFile directoryFile = DocumentFile.fromTreeUri(this, directoryUri);
|
DocumentFile directoryFile = DocumentFile.fromTreeUri(this, directoryUri);
|
||||||
@@ -57,9 +57,7 @@ public class ExportService extends JobIntentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Export.
|
// Export.
|
||||||
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(this);
|
boolean success = ExportUtils.exportTrack(this, directoryFile, exportTask);
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
|
||||||
boolean success = ExportUtils.exportTrack(this, trackFileFormat, directoryFile, track);
|
|
||||||
|
|
||||||
// Send result to the receiver.
|
// Send result to the receiver.
|
||||||
int resultCode = success ? ExportServiceResultReceiver.RESULT_CODE_SUCCESS : ExportServiceResultReceiver.RESULT_CODE_ERROR;
|
int resultCode = success ? ExportServiceResultReceiver.RESULT_CODE_SUCCESS : ExportServiceResultReceiver.RESULT_CODE_ERROR;
|
||||||
|
|||||||
+6
-6
@@ -17,7 +17,7 @@ public class ExportServiceResultReceiver extends ResultReceiver {
|
|||||||
public static final int RESULT_CODE_SUCCESS = 1;
|
public static final int RESULT_CODE_SUCCESS = 1;
|
||||||
public static final int RESULT_CODE_ERROR = 0;
|
public static final int RESULT_CODE_ERROR = 0;
|
||||||
|
|
||||||
public static final String RESULT_EXTRA_TRACK_ID = "result_extra_track_id";
|
public static final String RESULT_EXTRA_EXPORT_TASK = "result_extra_export_task";
|
||||||
|
|
||||||
private final Receiver receiver;
|
private final Receiver receiver;
|
||||||
|
|
||||||
@@ -28,19 +28,19 @@ public class ExportServiceResultReceiver extends ResultReceiver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||||
Track.Id trackId = resultData.getParcelable(ExportServiceResultReceiver.RESULT_EXTRA_TRACK_ID);
|
ExportTask exportTask = resultData.getParcelable(ExportServiceResultReceiver.RESULT_EXTRA_EXPORT_TASK);
|
||||||
switch (resultCode) {
|
switch (resultCode) {
|
||||||
case RESULT_CODE_SUCCESS -> receiver.onExportSuccess(trackId);
|
case RESULT_CODE_SUCCESS -> receiver.onExportSuccess(exportTask);
|
||||||
case RESULT_CODE_ERROR -> receiver.onExportError(trackId);
|
case RESULT_CODE_ERROR -> receiver.onExportError(exportTask);
|
||||||
default -> throw new RuntimeException("Unknown resultCode.");
|
default -> throw new RuntimeException("Unknown resultCode.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Receiver {
|
public interface Receiver {
|
||||||
default void onExportSuccess(Track.Id trackId) {
|
default void onExportSuccess(ExportTask exportTask) {
|
||||||
}
|
}
|
||||||
|
|
||||||
default void onExportError(Track.Id trackId) {
|
default void onExportError(ExportTask exportTask) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package de.dennisguse.opentracks.io.file.exporter;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
|
|
||||||
|
public class ExportTask implements Parcelable {
|
||||||
|
|
||||||
|
private final String filename; //TODO Name will only be used when exporting multiple tracks
|
||||||
|
|
||||||
|
private final TrackFileFormat trackFileFormat;
|
||||||
|
|
||||||
|
private final List<Track.Id> trackIds;
|
||||||
|
|
||||||
|
public ExportTask(@Nullable String filename, @NonNull TrackFileFormat trackFileFormat, @NonNull List<Track.Id> trackIds) {
|
||||||
|
this.filename = filename;
|
||||||
|
this.trackFileFormat = trackFileFormat;
|
||||||
|
this.trackIds = trackIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ExportTask(Parcel in) {
|
||||||
|
filename = in.readString();
|
||||||
|
trackFileFormat = TrackFileFormat.valueOf(in.readString());
|
||||||
|
trackIds = in.createTypedArrayList(Track.Id.CREATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TrackFileFormat getTrackFileFormat() {
|
||||||
|
return trackFileFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Track.Id> getTrackIds() {
|
||||||
|
return trackIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMultiExport() {
|
||||||
|
return trackIds.size() > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
ExportTask that = (ExportTask) o;
|
||||||
|
return Objects.equals(filename, that.filename) && trackFileFormat == that.trackFileFormat && Objects.equals(trackIds, that.trackIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(filename, trackFileFormat, trackIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeString(filename);
|
||||||
|
dest.writeString(trackFileFormat.name());
|
||||||
|
dest.writeTypedList(trackIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<ExportTask> CREATOR = new Creator<>() {
|
||||||
|
@Override
|
||||||
|
public ExportTask createFromParcel(Parcel in) {
|
||||||
|
return new ExportTask(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExportTask[] newArray(int size) {
|
||||||
|
return new ExportTask[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -98,12 +98,7 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean writeTrack(Track track, @NonNull OutputStream outputStream) {
|
public boolean writeTrack(List<Track> tracks, @NonNull OutputStream outputStream) {
|
||||||
return writeTrack(new Track[]{track}, outputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
|
||||||
try {
|
try {
|
||||||
prepare(outputStream);
|
prepare(outputStream);
|
||||||
writeHeader();
|
writeHeader();
|
||||||
|
|||||||
@@ -99,18 +99,14 @@ public class KMLTrackExporter implements TrackExporter {
|
|||||||
this.contentProviderUtils = contentProviderUtils;
|
this.contentProviderUtils = contentProviderUtils;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean writeTrack(Track track, @NonNull OutputStream outputStream) {
|
public boolean writeTrack(List<Track> tracks, @NonNull OutputStream outputStream) {
|
||||||
return writeTrack(new Track[]{track}, outputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
|
||||||
try {
|
try {
|
||||||
prepare(outputStream);
|
prepare(outputStream);
|
||||||
writeHeader(tracks);
|
writeHeader(tracks);
|
||||||
for (Track track : tracks) {
|
for (Track track : tracks) {
|
||||||
writeMarkers(track);
|
writeMarkers(track);
|
||||||
}
|
}
|
||||||
boolean hasMultipleTracks = tracks.length > 1;
|
boolean hasMultipleTracks = tracks.size() > 1;
|
||||||
if (hasMultipleTracks) {
|
if (hasMultipleTracks) {
|
||||||
writeMultiTrackBegin();
|
writeMultiTrackBegin();
|
||||||
}
|
}
|
||||||
@@ -222,7 +218,7 @@ public class KMLTrackExporter implements TrackExporter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeHeader(Track[] tracks) {
|
private void writeHeader(List<Track> tracks) {
|
||||||
if (printWriter != null) {
|
if (printWriter != null) {
|
||||||
printWriter.println(
|
printWriter.println(
|
||||||
"""
|
"""
|
||||||
@@ -241,7 +237,7 @@ public class KMLTrackExporter implements TrackExporter {
|
|||||||
printWriter.println("<open>1</open>");
|
printWriter.println("<open>1</open>");
|
||||||
printWriter.println("<visibility>1</visibility>");
|
printWriter.println("<visibility>1</visibility>");
|
||||||
|
|
||||||
Track track = tracks[0];
|
Track track = tracks.get(0);
|
||||||
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
|
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
|
||||||
printWriter.println("<atom:generator>" + StringUtils.formatCData(context.getString(R.string.app_name)) + "</atom:generator>");
|
printWriter.println("<atom:generator>" + StringUtils.formatCData(context.getString(R.string.app_name)) + "</atom:generator>");
|
||||||
|
|
||||||
@@ -293,7 +289,7 @@ public class KMLTrackExporter implements TrackExporter {
|
|||||||
|
|
||||||
private void writeMultiTrackBegin() {
|
private void writeMultiTrackBegin() {
|
||||||
if (printWriter != null) {
|
if (printWriter != null) {
|
||||||
printWriter.println("<Folder id=tour>");
|
printWriter.println("<Folder id=\"tracks\">");
|
||||||
printWriter.println("<name>" + context.getString(R.string.generic_tracks) + "</name>");
|
printWriter.println("<name>" + context.getString(R.string.generic_tracks) + "</name>");
|
||||||
printWriter.println("<open>1</open>");
|
printWriter.println("<open>1</open>");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import java.io.FileNotFoundException;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.List;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
@@ -64,12 +65,7 @@ public class KmzTrackExporter implements TrackExporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean writeTrack(Track track, @NonNull OutputStream outputStream) {
|
public boolean writeTrack(List<Track> tracks, @NonNull OutputStream outputStream) {
|
||||||
return writeTrack(new Track[]{track}, outputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
|
||||||
try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
|
try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
|
||||||
// Add kml file
|
// Add kml file
|
||||||
ZipEntry zipEntry = new ZipEntry(KMZ_KML_FILE);
|
ZipEntry zipEntry = new ZipEntry(KMZ_KML_FILE);
|
||||||
@@ -91,7 +87,7 @@ public class KmzTrackExporter implements TrackExporter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addImages(Context context, Track[] tracks, ZipOutputStream zipOutputStream) throws InterruptedException, IOException {
|
private void addImages(Context context, List<Track> tracks, ZipOutputStream zipOutputStream) throws InterruptedException, IOException {
|
||||||
for (Track track : tracks) {
|
for (Track track : tracks) {
|
||||||
try (Cursor cursor = contentProviderUtils.getMarkerCursor(track.getId(), null, -1)) {
|
try (Cursor cursor = contentProviderUtils.getMarkerCursor(track.getId(), null, -1)) {
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package de.dennisguse.opentracks.io.file.exporter;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.data.models.Track;
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
|
|
||||||
@@ -29,7 +30,5 @@ import de.dennisguse.opentracks.data.models.Track;
|
|||||||
*/
|
*/
|
||||||
public interface TrackExporter {
|
public interface TrackExporter {
|
||||||
|
|
||||||
boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream);
|
boolean writeTrack(List<Track> tracks, @NonNull OutputStream outputStream);
|
||||||
|
|
||||||
boolean writeTrack(Track track, @NonNull OutputStream outputStream);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,6 +101,30 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ExportDirectoryChooserOneFileActivity extends DirectoryChooserActivity {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DocumentFile configureDirectoryChooserIntent(Intent intent) {
|
||||||
|
super.configureDirectoryChooserIntent(intent);
|
||||||
|
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||||
|
return IntentUtils.toDocumentFile(this, PreferencesUtils.getDefaultExportDirectoryUri());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isDirectoryValid(final DocumentFile directoryUri) {
|
||||||
|
return super.isDirectoryValid(directoryUri) && directoryUri.canWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Intent createNextActivityIntent(Uri directoryUri) {
|
||||||
|
Intent intent = IntentUtils.newIntent(this, ExportActivity.class);
|
||||||
|
intent.putExtra(ExportActivity.EXTRA_DIRECTORY_URI_KEY, directoryUri);
|
||||||
|
intent.putExtra(ExportActivity.EXTRA_ONE_FILE_KEY, true);
|
||||||
|
intent.putExtra(ExportActivity.EXTRA_TRACKFILEFORMAT_KEY, PreferencesUtils.getExportTrackFileFormat());
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class DefaultTrackExportDirectoryChooserActivity extends DirectoryChooserActivity {
|
public static class DefaultTrackExportDirectoryChooserActivity extends DirectoryChooserActivity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.data.models.BatteryLevel;
|
||||||
import de.dennisguse.opentracks.data.models.Cadence;
|
import de.dennisguse.opentracks.data.models.Cadence;
|
||||||
import de.dennisguse.opentracks.data.models.Distance;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.data.models.HeartRate;
|
import de.dennisguse.opentracks.data.models.HeartRate;
|
||||||
@@ -48,6 +49,11 @@ public class BluetoothUtils {
|
|||||||
|
|
||||||
public static final UUID CLIENT_CHARACTERISTIC_CONFIG_UUID = new UUID(0x290200001000L, 0x800000805f9b34fbL);
|
public static final UUID CLIENT_CHARACTERISTIC_CONFIG_UUID = new UUID(0x290200001000L, 0x800000805f9b34fbL);
|
||||||
|
|
||||||
|
public static final ServiceMeasurementUUID BATTERY = new ServiceMeasurementUUID(
|
||||||
|
new UUID(0x180F00001000L, 0x800000805f9b34fbL),
|
||||||
|
new UUID(0x2A1900001000L, 0x800000805f9b34fbL)
|
||||||
|
);
|
||||||
|
|
||||||
public static final ServiceMeasurementUUID HEARTRATE = new ServiceMeasurementUUID(
|
public static final ServiceMeasurementUUID HEARTRATE = new ServiceMeasurementUUID(
|
||||||
new UUID(0x180D00001000L, 0x800000805f9b34fbL),
|
new UUID(0x180D00001000L, 0x800000805f9b34fbL),
|
||||||
new UUID(0x2A3700001000L, 0x800000805f9b34fbL)
|
new UUID(0x2A3700001000L, 0x800000805f9b34fbL)
|
||||||
@@ -102,6 +108,17 @@ public class BluetoothUtils {
|
|||||||
return BluetoothUtils.getAdapter(context) != null;
|
return BluetoothUtils.getAdapter(context) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BatteryLevel parseBatteryLevel(BluetoothGattCharacteristic characteristic) {
|
||||||
|
// DOCUMENTATION org.bluetooth.characteristic.battery_level.xml
|
||||||
|
byte[] raw = characteristic.getValue();
|
||||||
|
if (raw.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int batteryLevel = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
|
||||||
|
return BatteryLevel.of(batteryLevel);
|
||||||
|
}
|
||||||
|
|
||||||
public static HeartRate parseHeartRate(BluetoothGattCharacteristic characteristic) {
|
public static HeartRate parseHeartRate(BluetoothGattCharacteristic characteristic) {
|
||||||
//DOCUMENTATION https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.heart_rate_measurement.xml
|
//DOCUMENTATION https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.heart_rate_measurement.xml
|
||||||
byte[] raw = characteristic.getValue();
|
byte[] raw = characteristic.getValue();
|
||||||
|
|||||||
+1
-2
@@ -5,7 +5,6 @@ import android.util.Log;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.data.models.Altitude;
|
|
||||||
import de.dennisguse.opentracks.data.models.TrackPoint;
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
import de.dennisguse.opentracks.util.EGM2008Utils;
|
import de.dennisguse.opentracks.util.EGM2008Utils;
|
||||||
|
|
||||||
@@ -30,6 +29,6 @@ public class EGM2008CorrectionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trackPoint.setAltitude(Altitude.EGM2008.of(egm2008Correction.correctAltitude(trackPoint.getLocation())));
|
trackPoint.setAltitude(egm2008Correction.correctAltitude(trackPoint.getLocation()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,11 +49,6 @@ public class MainSettingsFragment extends PreferenceFragmentCompat {
|
|||||||
((SettingsActivity) getActivity()).openScreen(getString(R.string.settings_api_key));
|
((SettingsActivity) getActivity()).openScreen(getString(R.string.settings_api_key));
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
findPreference(getString(R.string.settings_open_tracks_key)).setOnPreferenceClickListener(preference -> {
|
|
||||||
((SettingsActivity) getActivity()).openScreen(getString(R.string.settings_open_tracks_key));
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
package de.dennisguse.opentracks.settings;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import androidx.preference.PreferenceFragmentCompat;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
|
||||||
|
|
||||||
public class OpenTracksSettingsFragment extends PreferenceFragmentCompat {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
|
||||||
addPreferencesFromResource(R.xml.settings_open_tracks);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
((SettingsActivity) getActivity()).getSupportActionBar().setTitle(R.string.settings_open_tracks_title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -93,8 +93,6 @@ public class SettingsActivity extends AbstractActivity implements ChooseActivity
|
|||||||
fragment = new ImportExportSettingsFragment();
|
fragment = new ImportExportSettingsFragment();
|
||||||
} else if (key.equals(getString(R.string.settings_api_key))) {
|
} else if (key.equals(getString(R.string.settings_api_key))) {
|
||||||
fragment = new PublicAPISettingsFragment();
|
fragment = new PublicAPISettingsFragment();
|
||||||
} else if (key.equals(getString(R.string.settings_open_tracks_key))) {
|
|
||||||
fragment = new OpenTracksSettingsFragment();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fragment;
|
return fragment;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.io.IOException;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.data.models.Altitude;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts WGS84 altitude to EGM2008 (should be close to height above sea level).
|
* Converts WGS84 altitude to EGM2008 (should be close to height above sea level).
|
||||||
@@ -103,7 +104,7 @@ public class EGM2008Utils {
|
|||||||
return indices.getAbsoluteIndex() == getIndices(location).getAbsoluteIndex();
|
return indices.getAbsoluteIndex() == getIndices(location).getAbsoluteIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
public double correctAltitude(@NonNull Location location) {
|
public Altitude.EGM2008 correctAltitude(@NonNull Location location) {
|
||||||
if (!canCorrect(location))
|
if (!canCorrect(location))
|
||||||
throw new RuntimeException("Undulation data not loaded for this location.");
|
throw new RuntimeException("Undulation data not loaded for this location.");
|
||||||
if (!location.hasAltitude())
|
if (!location.hasAltitude())
|
||||||
@@ -134,7 +135,7 @@ public class EGM2008Utils {
|
|||||||
|
|
||||||
double h = 0.003 * undulationRaw - 108;
|
double h = 0.003 * undulationRaw - 108;
|
||||||
|
|
||||||
return location.getAltitude() - h;
|
return Altitude.EGM2008.of(location.getAltitude() - h);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSouthPole() {
|
private boolean isSouthPole() {
|
||||||
|
|||||||
@@ -17,13 +17,16 @@ 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.stream.Collectors;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.data.models.Track;
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
|
import de.dennisguse.opentracks.io.file.TrackFilenameGenerator;
|
||||||
import de.dennisguse.opentracks.io.file.exporter.ExportService;
|
import de.dennisguse.opentracks.io.file.exporter.ExportService;
|
||||||
import de.dennisguse.opentracks.io.file.exporter.ExportServiceResultReceiver;
|
import de.dennisguse.opentracks.io.file.exporter.ExportServiceResultReceiver;
|
||||||
|
import de.dennisguse.opentracks.io.file.exporter.ExportTask;
|
||||||
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
||||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
import de.dennisguse.opentracks.settings.SettingsActivity;
|
import de.dennisguse.opentracks.settings.SettingsActivity;
|
||||||
@@ -44,7 +47,7 @@ public class ExportUtils {
|
|||||||
|
|
||||||
ExportServiceResultReceiver resultReceiver = new ExportServiceResultReceiver(new Handler(), new ExportServiceResultReceiver.Receiver() {
|
ExportServiceResultReceiver resultReceiver = new ExportServiceResultReceiver(new Handler(), new ExportServiceResultReceiver.Receiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onExportError(Track.Id trackId) {
|
public void onExportError(ExportTask unused) {
|
||||||
Intent intent = new Intent(context, SettingsActivity.class);
|
Intent intent = new Intent(context, SettingsActivity.class);
|
||||||
intent.putExtra(SettingsActivity.EXTRAS_CHECK_EXPORT_DIRECTORY, true);
|
intent.putExtra(SettingsActivity.EXTRAS_CHECK_EXPORT_DIRECTORY, true);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
@@ -52,21 +55,29 @@ public class ExportUtils {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ExportService.enqueue(context, resultReceiver, trackId, trackFileFormat, directory.getUri());
|
ExportService.enqueue(context, resultReceiver, new ExportTask(null, trackFileFormat, List.of(trackId)), directory.getUri());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean exportTrack(Context context, TrackFileFormat trackFileFormat, DocumentFile directory, Track track) {
|
public static boolean exportTrack(Context context, DocumentFile directory, ExportTask exportTask) {
|
||||||
TrackExporter trackExporter = trackFileFormat.createTrackExporter(context, new ContentProviderUtils(context));
|
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
||||||
|
List<Track> tracks = exportTask.getTrackIds().stream().map(contentProviderUtils::getTrack).collect(Collectors.toList());
|
||||||
|
Uri exportDocumentFileUri;
|
||||||
|
if (tracks.size() == 1) {
|
||||||
|
exportDocumentFileUri = getExportDocumentFileUri(context, tracks.get(0), exportTask.getTrackFileFormat(), directory);
|
||||||
|
} else {
|
||||||
|
String filename = TrackFilenameGenerator.format(exportTask.getFilename(), exportTask.getTrackFileFormat());
|
||||||
|
exportDocumentFileUri = getExportDocumentFileUri(context, filename, exportTask.getTrackFileFormat(), directory);
|
||||||
|
}
|
||||||
|
|
||||||
Uri exportDocumentFileUri = getExportDocumentFileUri(context, track, trackFileFormat, directory);
|
|
||||||
if (exportDocumentFileUri == null) {
|
if (exportDocumentFileUri == null) {
|
||||||
Log.e(TAG, "Couldn't create document file for export");
|
Log.e(TAG, "Couldn't create document file for export");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TrackExporter trackExporter = exportTask.getTrackFileFormat().createTrackExporter(context, contentProviderUtils);
|
||||||
try (OutputStream outputStream = context.getContentResolver().openOutputStream(exportDocumentFileUri)) {
|
try (OutputStream outputStream = context.getContentResolver().openOutputStream(exportDocumentFileUri)) {
|
||||||
if (trackExporter.writeTrack(track, outputStream)) {
|
if (trackExporter.writeTrack(tracks, outputStream)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (!DocumentFile.fromSingleUri(context, exportDocumentFileUri).delete()) {
|
if (!DocumentFile.fromSingleUri(context, exportDocumentFileUri).delete()) {
|
||||||
@@ -102,6 +113,10 @@ public class ExportUtils {
|
|||||||
|
|
||||||
private static Uri getExportDocumentFileUri(Context context, Track track, TrackFileFormat trackFileFormat, DocumentFile directory) {
|
private static Uri getExportDocumentFileUri(Context context, Track track, TrackFileFormat trackFileFormat, DocumentFile directory) {
|
||||||
String exportFileName = PreferencesUtils.getTrackFileformatGenerator().format(track, trackFileFormat);
|
String exportFileName = PreferencesUtils.getTrackFileformatGenerator().format(track, trackFileFormat);
|
||||||
|
return getExportDocumentFileUri(context, exportFileName, trackFileFormat, directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri getExportDocumentFileUri(Context context, String exportFileName, TrackFileFormat trackFileFormat, DocumentFile directory) {
|
||||||
Uri exportDocumentFileUri = findFile(context, directory.getUri(), exportFileName);
|
Uri exportDocumentFileUri = findFile(context, directory.getUri(), exportFileName);
|
||||||
if (exportDocumentFileUri == null) {
|
if (exportDocumentFileUri == null) {
|
||||||
final DocumentFile file = directory.createFile(trackFileFormat.getMimeType(), exportFileName);
|
final DocumentFile file = directory.createFile(trackFileFormat.getMimeType(), exportFileName);
|
||||||
|
|||||||
@@ -42,4 +42,8 @@ limitations under the License.
|
|||||||
android:id="@+id/track_list_settings"
|
android:id="@+id/track_list_settings"
|
||||||
android:icon="@drawable/ic_settings_24dp"
|
android:icon="@drawable/ic_settings_24dp"
|
||||||
android:title="@string/menu_settings" />
|
android:title="@string/menu_settings" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/track_list_help"
|
||||||
|
android:title="@string/menu_help" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
@@ -491,7 +491,6 @@
|
|||||||
<string name="settings_import_section">Importar</string>
|
<string name="settings_import_section">Importar</string>
|
||||||
<string name="aggregated_stats_filter_no_results">No hay actividades para el filtro especificado</string>
|
<string name="aggregated_stats_filter_no_results">No hay actividades para el filtro especificado</string>
|
||||||
<string name="value_float_mile_hour_recommended">%1$.1f mi/h (recomendado)</string>
|
<string name="value_float_mile_hour_recommended">%1$.1f mi/h (recomendado)</string>
|
||||||
<string name="settings_open_tracks_title">Open Tracks</string>
|
|
||||||
<string name="value_float_kilometer_hour">%1$.1f km/h</string>
|
<string name="value_float_kilometer_hour">%1$.1f km/h</string>
|
||||||
<string name="value_float_kilometer_hour_recommended">%1$.1f km/h (recomendado)</string>
|
<string name="value_float_kilometer_hour_recommended">%1$.1f km/h (recomendado)</string>
|
||||||
<string name="generic_undo">Deshacer</string>
|
<string name="generic_undo">Deshacer</string>
|
||||||
|
|||||||
@@ -520,7 +520,6 @@ limitations under the License.
|
|||||||
<string name="settings_sensors_title">Bluetooth senzory</string>
|
<string name="settings_sensors_title">Bluetooth senzory</string>
|
||||||
<string name="settings_gps_summary">Časový interval, Interval vzdálenosti, Maximální vzdálenost, Přesnost</string>
|
<string name="settings_gps_summary">Časový interval, Interval vzdálenosti, Maximální vzdálenost, Přesnost</string>
|
||||||
<string name="settings_ui_summary">Vzhled, Rozložení záznamu, Téma</string>
|
<string name="settings_ui_summary">Vzhled, Rozložení záznamu, Téma</string>
|
||||||
<string name="settings_open_tracks_title">O programu</string>
|
|
||||||
<string name="settings_open_tracks_summary">Vše o projektu OpenTracks</string>
|
<string name="settings_open_tracks_summary">Vše o projektu OpenTracks</string>
|
||||||
<string name="settings_defaults_title">Výchozí jednotky a aktivity</string>
|
<string name="settings_defaults_title">Výchozí jednotky a aktivity</string>
|
||||||
<string name="settings_ui_title">Uživatelské rozhraní</string>
|
<string name="settings_ui_title">Uživatelské rozhraní</string>
|
||||||
|
|||||||
@@ -537,7 +537,6 @@ Hvis GPS-enheden rapporterer unøjagtige data (f.eks. Placering, hastighed, høj
|
|||||||
<string name="settings_ui_summary">Udseende, Optagelse af layout, Tema</string>
|
<string name="settings_ui_summary">Udseende, Optagelse af layout, Tema</string>
|
||||||
<string name="description_speed_source_gps">GPS</string>
|
<string name="description_speed_source_gps">GPS</string>
|
||||||
<string name="generic_filter">Filter</string>
|
<string name="generic_filter">Filter</string>
|
||||||
<string name="settings_open_tracks_title">Åbne spor</string>
|
|
||||||
<string name="custom_layout_list_edit_name">Skriv navnet på det layout, der skal tilføjes</string>
|
<string name="custom_layout_list_edit_name">Skriv navnet på det layout, der skal tilføjes</string>
|
||||||
<string name="settings_layout_reset_confirm_message">Alle layoutindstillinger vil blive tilbageført til standardværdierne. Dette vil ikke slette spor på enheden.</string>
|
<string name="settings_layout_reset_confirm_message">Alle layoutindstillinger vil blive tilbageført til standardværdierne. Dette vil ikke slette spor på enheden.</string>
|
||||||
<string name="settings_all_reset">Nulstil</string>
|
<string name="settings_all_reset">Nulstil</string>
|
||||||
|
|||||||
@@ -574,6 +574,5 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
|
|||||||
<string name="settings_ui_summary">Erscheinungsbild, Aufzeichnungslayout, Theme</string>
|
<string name="settings_ui_summary">Erscheinungsbild, Aufzeichnungslayout, Theme</string>
|
||||||
<string name="settings_gps_summary">Zeitintervall, Entfernungsintervall, Max Entfernung, Genauigkeit</string>
|
<string name="settings_gps_summary">Zeitintervall, Entfernungsintervall, Max Entfernung, Genauigkeit</string>
|
||||||
<string name="description_speed_nautical">Geschwindigkeit (Knoten)</string>
|
<string name="description_speed_nautical">Geschwindigkeit (Knoten)</string>
|
||||||
<string name="settings_open_tracks_title">Open Tracks</string>
|
|
||||||
<string name="gps_recording_status">%1$s: %2$s</string>
|
<string name="gps_recording_status">%1$s: %2$s</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -542,7 +542,6 @@ limitations under the License.
|
|||||||
<string name="settings_open_tracks_summary">Todo sobre el proyecto OpenTracks</string>
|
<string name="settings_open_tracks_summary">Todo sobre el proyecto OpenTracks</string>
|
||||||
<string name="settings_defaults_title">Unidades y Actividad predeterminadas</string>
|
<string name="settings_defaults_title">Unidades y Actividad predeterminadas</string>
|
||||||
<string name="settings_defaults_summary">Unidades preferidas, Actividad predeterminada, Nombre predeterminado del recorrido</string>
|
<string name="settings_defaults_summary">Unidades preferidas, Actividad predeterminada, Nombre predeterminado del recorrido</string>
|
||||||
<string name="settings_open_tracks_title">Open Tracks</string>
|
|
||||||
<string name="generic_undo">Deshacer</string>
|
<string name="generic_undo">Deshacer</string>
|
||||||
<string name="no_compatible_file_manager_installed">No hay un gestor de archivos compatible instalado</string>
|
<string name="no_compatible_file_manager_installed">No hay un gestor de archivos compatible instalado</string>
|
||||||
<string name="settings_public_api_disabled_toast">La API pública de OpenTracks está deshabilitada: esta se puede activar en los ajustes.</string>
|
<string name="settings_public_api_disabled_toast">La API pública de OpenTracks está deshabilitada: esta se puede activar en los ajustes.</string>
|
||||||
|
|||||||
@@ -498,7 +498,6 @@ limitations under the License.
|
|||||||
<string name="settings_import_export_title">Import/Eksport</string>
|
<string name="settings_import_export_title">Import/Eksport</string>
|
||||||
<string name="settings_gps_title">GPS</string>
|
<string name="settings_gps_title">GPS</string>
|
||||||
<string name="settings_open_tracks_summary">Kõik OpenTracks Projekti Kohta</string>
|
<string name="settings_open_tracks_summary">Kõik OpenTracks Projekti Kohta</string>
|
||||||
<string name="settings_open_tracks_title">OpenTracks</string>
|
|
||||||
<string name="settings_reset_summary">Lähtestage Seaded vaikeväärtustele</string>
|
<string name="settings_reset_summary">Lähtestage Seaded vaikeväärtustele</string>
|
||||||
<string name="settings_recording_customize_layout_title">Kohandage oma salvestuspaigutust</string>
|
<string name="settings_recording_customize_layout_title">Kohandage oma salvestuspaigutust</string>
|
||||||
<string name="settings_recording_customize_layout_select_columns">Andmeväljad rea kohta</string>
|
<string name="settings_recording_customize_layout_select_columns">Andmeväljad rea kohta</string>
|
||||||
|
|||||||
@@ -528,7 +528,6 @@ GPS gailuak datu okerrak salatzen baditu (adibidez, kokapena, abiadura, kota), O
|
|||||||
<string name="settings_defaults_summary">Unitate Hobetsia, Jarduera Lehenetsia, Pistaren Izen Lehenetsia</string>
|
<string name="settings_defaults_summary">Unitate Hobetsia, Jarduera Lehenetsia, Pistaren Izen Lehenetsia</string>
|
||||||
<string name="settings_ui_title">Interfazea</string>
|
<string name="settings_ui_title">Interfazea</string>
|
||||||
<string name="settings_ui_summary">Itxura, Grabazioaren Diseinua, Gaia</string>
|
<string name="settings_ui_summary">Itxura, Grabazioaren Diseinua, Gaia</string>
|
||||||
<string name="settings_open_tracks_title">Ireki Pistak</string>
|
|
||||||
<string name="settings_cycling_sensor">Txirrindularitza</string>
|
<string name="settings_cycling_sensor">Txirrindularitza</string>
|
||||||
<string name="generic_filter">Iragazkia</string>
|
<string name="generic_filter">Iragazkia</string>
|
||||||
<string name="generic_from">Nondik</string>
|
<string name="generic_from">Nondik</string>
|
||||||
|
|||||||
@@ -526,7 +526,6 @@ Si le dispositif GPS signale des données inexactes (par exemple, la localisatio
|
|||||||
<string name="settings_defaults_summary">Unités préférées, Activité par défaut, Suivi du nom par défaut</string>
|
<string name="settings_defaults_summary">Unités préférées, Activité par défaut, Suivi du nom par défaut</string>
|
||||||
<string name="settings_defaults_title">Unités et activité par défaut</string>
|
<string name="settings_defaults_title">Unités et activité par défaut</string>
|
||||||
<string name="settings_open_tracks_summary">A propos du projet OpenTracks</string>
|
<string name="settings_open_tracks_summary">A propos du projet OpenTracks</string>
|
||||||
<string name="settings_open_tracks_title">Open Tracks</string>
|
|
||||||
<string name="generic_undo">Annuler</string>
|
<string name="generic_undo">Annuler</string>
|
||||||
<string name="menu_add_custom_layout">Nouvelle présentation</string>
|
<string name="menu_add_custom_layout">Nouvelle présentation</string>
|
||||||
<string name="generic_filter">Filtre</string>
|
<string name="generic_filter">Filtre</string>
|
||||||
|
|||||||
@@ -208,7 +208,6 @@
|
|||||||
<string name="settings_ui_summary">Dealramh, Leagan Amach Taifeadta, Téama</string>
|
<string name="settings_ui_summary">Dealramh, Leagan Amach Taifeadta, Téama</string>
|
||||||
<string name="settings_sensors_summary">Braiteoirí Rothaíochta, Imlíne Rothaí, Braiteoirí Reatha</string>
|
<string name="settings_sensors_summary">Braiteoirí Rothaíochta, Imlíne Rothaí, Braiteoirí Reatha</string>
|
||||||
<string name="bluetooth_disabled">Cumasaigh Bluetooth le do thoil.</string>
|
<string name="bluetooth_disabled">Cumasaigh Bluetooth le do thoil.</string>
|
||||||
<string name="settings_open_tracks_title">Open Tracks</string>
|
|
||||||
<string name="settings_open_tracks_summary">Gach Maidir Tionscadal OpenTracks</string>
|
<string name="settings_open_tracks_summary">Gach Maidir Tionscadal OpenTracks</string>
|
||||||
<string name="settings_defaults_title">Aonaid agus Gníomhaíocht Réamhshocraithe</string>
|
<string name="settings_defaults_title">Aonaid agus Gníomhaíocht Réamhshocraithe</string>
|
||||||
<string name="settings_ui_title">Comhéadan Úsáideora</string>
|
<string name="settings_ui_title">Comhéadan Úsáideora</string>
|
||||||
|
|||||||
@@ -505,7 +505,6 @@ Se o GPS informa sobre datos pouco precisos (ex.: localización, velocidade, ele
|
|||||||
<string name="value_float_mile_hour_recommended">%1$.1f km/h (recomendado)</string>
|
<string name="value_float_mile_hour_recommended">%1$.1f km/h (recomendado)</string>
|
||||||
<string name="value_float_kilometer_hour_recommended">%1$.1f km/h (recomendado)</string>
|
<string name="value_float_kilometer_hour_recommended">%1$.1f km/h (recomendado)</string>
|
||||||
<string name="stats_clock">Reloxo</string>
|
<string name="stats_clock">Reloxo</string>
|
||||||
<string name="settings_open_tracks_title">Open Tracks</string>
|
|
||||||
<string name="settings_defaults_summary">Unidades preferidas, Actividade por defecto, Nome da ruta</string>
|
<string name="settings_defaults_summary">Unidades preferidas, Actividade por defecto, Nome da ruta</string>
|
||||||
<string name="settings_announcements_summary">A Distancia, Tempo, Voz Velocidade</string>
|
<string name="settings_announcements_summary">A Distancia, Tempo, Voz Velocidade</string>
|
||||||
<string name="settings_open_tracks_summary">Todo Sobre OpenTracks Proxecto</string>
|
<string name="settings_open_tracks_summary">Todo Sobre OpenTracks Proxecto</string>
|
||||||
|
|||||||
@@ -506,7 +506,6 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
|
|||||||
<string name="settings_layout_reset_done">Tutte le impostazioni del layout sono state reimpostate ai valori predefiniti</string>
|
<string name="settings_layout_reset_done">Tutte le impostazioni del layout sono state reimpostate ai valori predefiniti</string>
|
||||||
<string name="settings_generic_sensor">Generico</string>
|
<string name="settings_generic_sensor">Generico</string>
|
||||||
<string name="value_float_kilometer_hour">%1$.1f km/h</string>
|
<string name="value_float_kilometer_hour">%1$.1f km/h</string>
|
||||||
<string name="settings_open_tracks_title">Binari aperti</string>
|
|
||||||
<string name="settings_open_tracks_summary">Tutto a proposito del progetto OpenTracks</string>
|
<string name="settings_open_tracks_summary">Tutto a proposito del progetto OpenTracks</string>
|
||||||
<string name="settings_ui_title">Interfaccia Utente</string>
|
<string name="settings_ui_title">Interfaccia Utente</string>
|
||||||
<string name="settings_ui_summary">Aspetto, Layout durante la registrazione, Tema</string>
|
<string name="settings_ui_summary">Aspetto, Layout durante la registrazione, Tema</string>
|
||||||
|
|||||||
@@ -498,7 +498,6 @@ limitations under the License.
|
|||||||
<string name="value_float_mile_hour">%1$.1f mi/h</string>
|
<string name="value_float_mile_hour">%1$.1f mi/h</string>
|
||||||
<string name="value_float_mile_hour_recommended">%1$.1f mi/h (anbefales)</string>
|
<string name="value_float_mile_hour_recommended">%1$.1f mi/h (anbefales)</string>
|
||||||
<string name="stats_clock">Klokke</string>
|
<string name="stats_clock">Klokke</string>
|
||||||
<string name="settings_open_tracks_title">OpenTracks</string>
|
|
||||||
<string name="settings_defaults_summary">Foretrukne enheter, forvalgsaktivitet, forvalgt spornavn</string>
|
<string name="settings_defaults_summary">Foretrukne enheter, forvalgsaktivitet, forvalgt spornavn</string>
|
||||||
<string name="settings_sensors_summary">Sykkelsensorer, hjulomkrets, løpesensorer</string>
|
<string name="settings_sensors_summary">Sykkelsensorer, hjulomkrets, løpesensorer</string>
|
||||||
<string name="settings_open_tracks_summary">Alt om OpenTracks-prosjektet</string>
|
<string name="settings_open_tracks_summary">Alt om OpenTracks-prosjektet</string>
|
||||||
@@ -603,6 +602,7 @@ limitations under the License.
|
|||||||
<string name="settings_public_api_package_title">Pakkenavn for offentlig API</string>
|
<string name="settings_public_api_package_title">Pakkenavn for offentlig API</string>
|
||||||
<string name="introduction_osm_dashboard">OpenTracks sørger ikke selv for kart. Installer OSMDashboard for å vise opptakene dine på et kart.</string>
|
<string name="introduction_osm_dashboard">OpenTracks sørger ikke selv for kart. Installer OSMDashboard for å vise opptakene dine på et kart.</string>
|
||||||
<string name="help_data_google_play_services_content">Nei</string>
|
<string name="help_data_google_play_services_content">Nei</string>
|
||||||
<string name="settings_sensor_heart_rate_max">Soner: Makspuls (bpm)</string>
|
<string name="settings_sensor_heart_rate_max">Soner: maksimum puls (slag/min)</string>
|
||||||
<string name="settings_api_summary">Fjernkontroll- og statistikk-API for andre programmer</string>
|
<string name="settings_api_summary">Fjernkontroll- og statistikk-API for andre programmer</string>
|
||||||
|
<string name="voice_on_device_speaker_title">Bruk enhetens høyttaler</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -549,7 +549,6 @@ Als het GPS-apparaat onnauwkeurige gegevens rapporteert (bijv. locatie, snelheid
|
|||||||
<string name="settings_recording_customize_layout_select_columns">Gegevensvelden per rij</string>
|
<string name="settings_recording_customize_layout_select_columns">Gegevensvelden per rij</string>
|
||||||
<string name="value_float_mile_hour">%1$.1f mi/u</string>
|
<string name="value_float_mile_hour">%1$.1f mi/u</string>
|
||||||
<string name="value_float_mile_hour_recommended">%1$.1f mi/u (aanbevolen)</string>
|
<string name="value_float_mile_hour_recommended">%1$.1f mi/u (aanbevolen)</string>
|
||||||
<string name="settings_open_tracks_title">Open Tracks</string>
|
|
||||||
<string name="settings_open_tracks_summary">Alles over het OpenTracks Project</string>
|
<string name="settings_open_tracks_summary">Alles over het OpenTracks Project</string>
|
||||||
<string name="activity_type_workout">training</string>
|
<string name="activity_type_workout">training</string>
|
||||||
<string name="settings_layout_reset_confirm_title">Lay-outs terugzetten\?</string>
|
<string name="settings_layout_reset_confirm_title">Lay-outs terugzetten\?</string>
|
||||||
|
|||||||
@@ -536,7 +536,6 @@ limitations under the License.
|
|||||||
<string name="field_remove_from_layout">Usuń</string>
|
<string name="field_remove_from_layout">Usuń</string>
|
||||||
<string name="field_set_primary">Główny</string>
|
<string name="field_set_primary">Główny</string>
|
||||||
<string name="field_set_secondary">Poboczny</string>
|
<string name="field_set_secondary">Poboczny</string>
|
||||||
<string name="settings_open_tracks_title">Otwarte tory</string>
|
|
||||||
<string name="settings_open_tracks_summary">Wszystko o projekcie OpenTacks</string>
|
<string name="settings_open_tracks_summary">Wszystko o projekcie OpenTacks</string>
|
||||||
<string name="settings_defaults_title">Domyślne Jednostki i Aktywności</string>
|
<string name="settings_defaults_title">Domyślne Jednostki i Aktywności</string>
|
||||||
<string name="settings_defaults_summary">Preferowane Jednostki, Domyślne Aktywności, Nazwy Treningów</string>
|
<string name="settings_defaults_summary">Preferowane Jednostki, Domyślne Aktywności, Nazwy Treningów</string>
|
||||||
|
|||||||
@@ -458,7 +458,6 @@
|
|||||||
<string name="settings_ui_title">Interface do usuário</string>
|
<string name="settings_ui_title">Interface do usuário</string>
|
||||||
<string name="settings_defaults_title">Unidades e Atividade Default</string>
|
<string name="settings_defaults_title">Unidades e Atividade Default</string>
|
||||||
<string name="settings_defaults_summary">Unidades Preferidas, Atividade Padrão, Nome Padrão da Pista</string>
|
<string name="settings_defaults_summary">Unidades Preferidas, Atividade Padrão, Nome Padrão da Pista</string>
|
||||||
<string name="settings_open_tracks_title">Trilhas abertas</string>
|
|
||||||
<string name="settings_gps_title">GPS</string>
|
<string name="settings_gps_title">GPS</string>
|
||||||
<string name="settings_reset_summary">Redefinir configurações para valores padrão</string>
|
<string name="settings_reset_summary">Redefinir configurações para valores padrão</string>
|
||||||
<string name="settings_activity_defaults_category">Defaults da atividade</string>
|
<string name="settings_activity_defaults_category">Defaults da atividade</string>
|
||||||
|
|||||||
@@ -440,7 +440,6 @@
|
|||||||
<string name="sensor_state_power_avg">Energia Avg</string>
|
<string name="sensor_state_power_avg">Energia Avg</string>
|
||||||
<string name="sensor_could_not_scan">Não foi possível procurar aparelhos Bluetooth (erro %1$i).</string>
|
<string name="sensor_could_not_scan">Não foi possível procurar aparelhos Bluetooth (erro %1$i).</string>
|
||||||
<string name="bluetooth_disabled">Ative o Bluetooth.</string>
|
<string name="bluetooth_disabled">Ative o Bluetooth.</string>
|
||||||
<string name="settings_open_tracks_title">Trilhas abertas</string>
|
|
||||||
<string name="settings_open_tracks_summary">Tudo sobre o Projeto OpenTracks</string>
|
<string name="settings_open_tracks_summary">Tudo sobre o Projeto OpenTracks</string>
|
||||||
<string name="settings_defaults_title">Unidades e Atividade Default</string>
|
<string name="settings_defaults_title">Unidades e Atividade Default</string>
|
||||||
<string name="settings_defaults_summary">Unidades Preferidas, Atividade Padrão, Nome Padrão da Pista</string>
|
<string name="settings_defaults_summary">Unidades Preferidas, Atividade Padrão, Nome Padrão da Pista</string>
|
||||||
|
|||||||
@@ -444,7 +444,6 @@ limitations under the License.
|
|||||||
<string name="sensor_state_power_avg">Energia Avg</string>
|
<string name="sensor_state_power_avg">Energia Avg</string>
|
||||||
<string name="sensor_could_not_scan">Não foi possível procurar aparelhos Bluetooth (erro %1$i).</string>
|
<string name="sensor_could_not_scan">Não foi possível procurar aparelhos Bluetooth (erro %1$i).</string>
|
||||||
<string name="bluetooth_disabled">Ative o Bluetooth.</string>
|
<string name="bluetooth_disabled">Ative o Bluetooth.</string>
|
||||||
<string name="settings_open_tracks_title">Trilhas abertas</string>
|
|
||||||
<string name="settings_open_tracks_summary">Tudo sobre o Projeto OpenTracks</string>
|
<string name="settings_open_tracks_summary">Tudo sobre o Projeto OpenTracks</string>
|
||||||
<string name="settings_defaults_title">Unidades e Atividade Default</string>
|
<string name="settings_defaults_title">Unidades e Atividade Default</string>
|
||||||
<string name="settings_gps_summary">Intervalo de tempo, Intervalo de distância, Distância máxima, Precisão</string>
|
<string name="settings_gps_summary">Intervalo de tempo, Intervalo de distância, Distância máxima, Precisão</string>
|
||||||
|
|||||||
@@ -505,7 +505,6 @@ limitations under the License.
|
|||||||
<string name="settings_public_api_enabled_summary_off">Только OpenTracks может запускать и останавливать запись.</string>
|
<string name="settings_public_api_enabled_summary_off">Только OpenTracks может запускать и останавливать запись.</string>
|
||||||
<string name="value_float_mile_hour_recommended">%1$.1f миль/ч (рекомендуется)</string>
|
<string name="value_float_mile_hour_recommended">%1$.1f миль/ч (рекомендуется)</string>
|
||||||
<string name="export_cannot_write_to_dir">Невозможно записать в папку экспорта.</string>
|
<string name="export_cannot_write_to_dir">Невозможно записать в папку экспорта.</string>
|
||||||
<string name="settings_open_tracks_title">Open Tracks</string>
|
|
||||||
<string name="settings_open_tracks_summary">Всё о проекте OpenTracks</string>
|
<string name="settings_open_tracks_summary">Всё о проекте OpenTracks</string>
|
||||||
<string name="settings_defaults_summary">Предпочитаемые единицы, активность по умолчанию, название трека</string>
|
<string name="settings_defaults_summary">Предпочитаемые единицы, активность по умолчанию, название трека</string>
|
||||||
<string name="settings_recording_customize_layout_title">Изменить раскладку записи</string>
|
<string name="settings_recording_customize_layout_title">Изменить раскладку записи</string>
|
||||||
|
|||||||
@@ -511,7 +511,6 @@ limitations under the License.
|
|||||||
<string name="settings_defaults_summary">Predvolené jednotky, predvolená aktivita, predvolený názov skladby</string>
|
<string name="settings_defaults_summary">Predvolené jednotky, predvolená aktivita, predvolený názov skladby</string>
|
||||||
<string name="settings_ui_title">Používateľské rozhranie</string>
|
<string name="settings_ui_title">Používateľské rozhranie</string>
|
||||||
<string name="settings_ui_summary">Vzhľad, Rozloženie nahrávania, Téma</string>
|
<string name="settings_ui_summary">Vzhľad, Rozloženie nahrávania, Téma</string>
|
||||||
<string name="settings_open_tracks_title">Otvorené trate</string>
|
|
||||||
<string name="settings_announcements_title">Hlasové oznámenia</string>
|
<string name="settings_announcements_title">Hlasové oznámenia</string>
|
||||||
<string name="settings_gps_title">GPS</string>
|
<string name="settings_gps_title">GPS</string>
|
||||||
<string name="settings_sensors_title">Senzory Bluetooth</string>
|
<string name="settings_sensors_title">Senzory Bluetooth</string>
|
||||||
|
|||||||
@@ -427,7 +427,6 @@ limitations under the License.
|
|||||||
<string name="sensor_state_heart_rate_max">Maks. Kalp atış hızı</string>
|
<string name="sensor_state_heart_rate_max">Maks. Kalp atış hızı</string>
|
||||||
<string name="sensor_could_not_scan">Bluetooth cihazları taranamadı (%1$i hatası).</string>
|
<string name="sensor_could_not_scan">Bluetooth cihazları taranamadı (%1$i hatası).</string>
|
||||||
<string name="bluetooth_disabled">Lütfen Bluetooth\'u etkinleştirin.</string>
|
<string name="bluetooth_disabled">Lütfen Bluetooth\'u etkinleştirin.</string>
|
||||||
<string name="settings_open_tracks_title">Open Tracks</string>
|
|
||||||
<string name="settings_open_tracks_summary">OpenTracks Projesi hakkında her şey</string>
|
<string name="settings_open_tracks_summary">OpenTracks Projesi hakkında her şey</string>
|
||||||
<string name="help_support_title">OpenTracks\'i nasıl destekleyebilirim\?</string>
|
<string name="help_support_title">OpenTracks\'i nasıl destekleyebilirim\?</string>
|
||||||
<string name="export_track_already_exists_msg">%1$s parçası hedef dizinde zaten var.</string>
|
<string name="export_track_already_exists_msg">%1$s parçası hedef dizinde zaten var.</string>
|
||||||
|
|||||||
@@ -516,7 +516,6 @@ limitations under the License.
|
|||||||
<string name="stats_sensors_cadence">Каденція</string>
|
<string name="stats_sensors_cadence">Каденція</string>
|
||||||
<string name="stats_sensors_heart_rate">частота серцебиття</string>
|
<string name="stats_sensors_heart_rate">частота серцебиття</string>
|
||||||
<string name="settings_defaults_summary">Переважні одиниці виміру, активність за замовчуванням, Ім\'я треку за замовчуванням</string>
|
<string name="settings_defaults_summary">Переважні одиниці виміру, активність за замовчуванням, Ім\'я треку за замовчуванням</string>
|
||||||
<string name="settings_open_tracks_title">Відкриті доріжки</string>
|
|
||||||
<string name="settings_open_tracks_summary">Все про проект OpenTracks</string>
|
<string name="settings_open_tracks_summary">Все про проект OpenTracks</string>
|
||||||
<string name="settings_defaults_title">Одиниці виміру і дії за замовчуванням</string>
|
<string name="settings_defaults_title">Одиниці виміру і дії за замовчуванням</string>
|
||||||
<string name="settings_ui_title">Інтерфейс користувача</string>
|
<string name="settings_ui_title">Інтерфейс користувача</string>
|
||||||
|
|||||||
@@ -492,7 +492,6 @@ limitations under the License.
|
|||||||
<string name="value_float_kilometer_hour">%1$.1f km/h</string>
|
<string name="value_float_kilometer_hour">%1$.1f km/h</string>
|
||||||
<string name="value_float_kilometer_hour_recommended">%1$.1f km/h (khuyến khích)</string>
|
<string name="value_float_kilometer_hour_recommended">%1$.1f km/h (khuyến khích)</string>
|
||||||
<string name="stats_clock">Cái đồng hồ</string>
|
<string name="stats_clock">Cái đồng hồ</string>
|
||||||
<string name="settings_open_tracks_title">Mở Bài Hát</string>
|
|
||||||
<string name="settings_reset_summary">Thiết lập lại các thiết Lập để mặc Định giá Trị</string>
|
<string name="settings_reset_summary">Thiết lập lại các thiết Lập để mặc Định giá Trị</string>
|
||||||
<string name="settings_activity_defaults_category">Hoạt động của Mặc định</string>
|
<string name="settings_activity_defaults_category">Hoạt động của Mặc định</string>
|
||||||
<string name="settings_units_category">Đơn vị</string>
|
<string name="settings_units_category">Đơn vị</string>
|
||||||
|
|||||||
@@ -323,7 +323,6 @@ limitations under the License.
|
|||||||
<string name="sensor_state_power_avg">平均功率</string>
|
<string name="sensor_state_power_avg">平均功率</string>
|
||||||
<string name="sensor_could_not_scan">無法掃描藍牙裝置 (錯誤 %1$i).</string>
|
<string name="sensor_could_not_scan">無法掃描藍牙裝置 (錯誤 %1$i).</string>
|
||||||
<string name="bluetooth_disabled">請啟用藍芽。</string>
|
<string name="bluetooth_disabled">請啟用藍芽。</string>
|
||||||
<string name="settings_open_tracks_title">Open Tracks</string>
|
|
||||||
<string name="settings_open_tracks_summary">所有關於 OpenTracks 專案</string>
|
<string name="settings_open_tracks_summary">所有關於 OpenTracks 專案</string>
|
||||||
<string name="settings_defaults_title">預設單位與活動</string>
|
<string name="settings_defaults_title">預設單位與活動</string>
|
||||||
<string name="settings_defaults_summary">首選單位、預設活動、蹤跡預設名稱</string>
|
<string name="settings_defaults_summary">首選單位、預設活動、蹤跡預設名稱</string>
|
||||||
|
|||||||
@@ -579,7 +579,6 @@ limitations under the License.
|
|||||||
<string name="marker_add_photo_canceled">已取消,照片标记没有被添加</string>
|
<string name="marker_add_photo_canceled">已取消,照片标记没有被添加</string>
|
||||||
<string name="sensor_state_cadence_avg">平均步频</string>
|
<string name="sensor_state_cadence_avg">平均步频</string>
|
||||||
<string name="sensor_could_not_scan">无法扫描蓝牙设备(错误:%1$i)。</string>
|
<string name="sensor_could_not_scan">无法扫描蓝牙设备(错误:%1$i)。</string>
|
||||||
<string name="settings_open_tracks_title">Open Tracks</string>
|
|
||||||
<string name="settings_units_category">单位</string>
|
<string name="settings_units_category">单位</string>
|
||||||
<string name="settings_recording_customize_layout_select_columns">每行数据字段数</string>
|
<string name="settings_recording_customize_layout_select_columns">每行数据字段数</string>
|
||||||
<string name="settings_announcements_average_heart_rate">平均心率</string>
|
<string name="settings_announcements_average_heart_rate">平均心率</string>
|
||||||
|
|||||||
@@ -11,8 +11,6 @@
|
|||||||
<bool name="stats_fullscreen_while_recording_default" translatable="false">false</bool>
|
<bool name="stats_fullscreen_while_recording_default" translatable="false">false</bool>
|
||||||
|
|
||||||
<!-- Main settings -->
|
<!-- Main settings -->
|
||||||
<string name="settings_open_tracks_key" translatable="false">settingsOpenTracks</string>
|
|
||||||
|
|
||||||
<string name="settings_defaults_key" translatable="false">settingsDefaults</string>
|
<string name="settings_defaults_key" translatable="false">settingsDefaults</string>
|
||||||
|
|
||||||
<string name="settings_ui_key" translatable="false">settingsUI</string>
|
<string name="settings_ui_key" translatable="false">settingsUI</string>
|
||||||
|
|||||||
@@ -210,12 +210,12 @@ limitations under the License.
|
|||||||
<string name="export_cannot_write_to_dir">Cannot write to export directory.</string>
|
<string name="export_cannot_write_to_dir">Cannot write to export directory.</string>
|
||||||
<string name="export_dir_not_writable">" (not writable!)"</string>
|
<string name="export_dir_not_writable">" (not writable!)"</string>
|
||||||
<string name="export_progress_message">Exporting to %1$s…</string>
|
<string name="export_progress_message">Exporting to %1$s…</string>
|
||||||
<string name="export_track_already_exists_msg">The track %1$s already exists at the destination directory.</string>
|
<string name="export_track_already_exists_msg">The file %1$s already exists at the destination directory.</string>
|
||||||
<string name="export_all_do_it_for_all">do it for all conflicts</string>
|
<string name="export_all_do_it_for_all">do it for all conflicts</string>
|
||||||
<string name="export_track_errors">Tracks not exported</string>
|
<string name="export_track_errors">Files not exported</string>
|
||||||
<string name="export_progress_summary_new_msg">New tracks exported</string>
|
<string name="export_progress_summary_new_msg">New files exported</string>
|
||||||
<string name="export_progress_summary_overwrite_msg">Tracks overwritten</string>
|
<string name="export_progress_summary_overwrite_msg">Files overwritten</string>
|
||||||
<string name="export_progress_summary_skip_msg">Tracks skipped</string>
|
<string name="export_progress_summary_skip_msg">Files skipped</string>
|
||||||
<string name="export_progress_summary_errors_msg">Errors</string>
|
<string name="export_progress_summary_errors_msg">Errors</string>
|
||||||
<!-- External Storage -->
|
<!-- External Storage -->
|
||||||
<!-- Generic -->
|
<!-- Generic -->
|
||||||
@@ -297,7 +297,8 @@ limitations under the License.
|
|||||||
<string name="menu_aggregated_statistics">Aggregated stats</string>
|
<string name="menu_aggregated_statistics">Aggregated stats</string>
|
||||||
<string name="menu_delete">Delete</string>
|
<string name="menu_delete">Delete</string>
|
||||||
<string name="menu_edit">Edit</string>
|
<string name="menu_edit">Edit</string>
|
||||||
<string name="menu_export_all">Export all</string>
|
<string name="menu_export_all">Export all (one file per track)</string>
|
||||||
|
<string name="menu_export_all_one_file">Export all (one file for all tracks)</string>
|
||||||
<string name="menu_help">Help</string>
|
<string name="menu_help">Help</string>
|
||||||
<string name="menu_import_all">Import all</string>
|
<string name="menu_import_all">Import all</string>
|
||||||
<string name="menu_insert_marker">Insert marker</string>
|
<string name="menu_insert_marker">Insert marker</string>
|
||||||
@@ -336,7 +337,6 @@ limitations under the License.
|
|||||||
<string name="sensor_could_not_scan">Could not scan for Bluetooth devices (error %1$i).</string>
|
<string name="sensor_could_not_scan">Could not scan for Bluetooth devices (error %1$i).</string>
|
||||||
<string name="bluetooth_disabled">Please enable Bluetooth.</string>
|
<string name="bluetooth_disabled">Please enable Bluetooth.</string>
|
||||||
|
|
||||||
<string name="settings_open_tracks_title">Open Tracks</string>
|
|
||||||
<string name="settings_open_tracks_summary">All About OpenTracks Project</string>
|
<string name="settings_open_tracks_summary">All About OpenTracks Project</string>
|
||||||
|
|
||||||
<string name="settings_defaults_title">Default Units and Activity</string>
|
<string name="settings_defaults_title">Default Units and Activity</string>
|
||||||
|
|||||||
@@ -58,8 +58,11 @@
|
|||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:icon="@drawable/ic_baseline_info_24"
|
android:icon="@drawable/ic_baseline_info_24"
|
||||||
android:key="@string/settings_open_tracks_key"
|
|
||||||
android:summary="@string/settings_open_tracks_summary"
|
android:summary="@string/settings_open_tracks_summary"
|
||||||
android:title="@string/settings_open_tracks_title" />
|
android:title="@string/about_preference_title">
|
||||||
|
<intent
|
||||||
|
android:targetClass="de.dennisguse.opentracks.AboutActivity"
|
||||||
|
android:targetPackage="@string/applicationId" />
|
||||||
|
</Preference>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|||||||
@@ -26,6 +26,13 @@
|
|||||||
android:targetClass="de.dennisguse.opentracks.io.file.importer.DirectoryChooserActivity$ExportDirectoryChooserActivity"
|
android:targetClass="de.dennisguse.opentracks.io.file.importer.DirectoryChooserActivity$ExportDirectoryChooserActivity"
|
||||||
android:targetPackage="@string/applicationId" />
|
android:targetPackage="@string/applicationId" />
|
||||||
</Preference>
|
</Preference>
|
||||||
|
<Preference
|
||||||
|
android:key="@string/settings_export"
|
||||||
|
android:title="@string/menu_export_all_one_file">
|
||||||
|
<intent
|
||||||
|
android:targetClass="de.dennisguse.opentracks.io.file.importer.DirectoryChooserActivity$ExportDirectoryChooserOneFileActivity"
|
||||||
|
android:targetPackage="@string/applicationId" />
|
||||||
|
</Preference>
|
||||||
<Preference
|
<Preference
|
||||||
android:key="@string/settings_default_export_directory_key"
|
android:key="@string/settings_default_export_directory_key"
|
||||||
android:title="@string/settings_default_export_uri_title">
|
android:title="@string/settings_default_export_uri_title">
|
||||||
@@ -48,5 +55,4 @@
|
|||||||
android:title="@string/settings_export_filename_title"
|
android:title="@string/settings_export_filename_title"
|
||||||
android:defaultValue="@string/export_filename_format_default" />
|
android:defaultValue="@string/export_filename_format_default" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:title="@string/settings_open_tracks_title">
|
|
||||||
|
|
||||||
<Preference android:title="@string/menu_help">
|
|
||||||
<intent
|
|
||||||
android:targetClass="de.dennisguse.opentracks.HelpActivity"
|
|
||||||
android:targetPackage="@string/applicationId" />
|
|
||||||
</Preference>
|
|
||||||
<Preference android:title="@string/about_preference_title">
|
|
||||||
<intent
|
|
||||||
android:targetClass="de.dennisguse.opentracks.AboutActivity"
|
|
||||||
android:targetPackage="@string/applicationId" />
|
|
||||||
</Preference>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
||||||
Reference in New Issue
Block a user