Compare commits

...

14 Commits

Author SHA1 Message Date
Dennis Guse c0672c41df Bugfix: crash if heart rate sensor was null (i.e., preference not initialized). 2019-11-29 23:18:49 +01:00
Dennis Guse 4c6601fbc5 Release v3.2.8 2019-11-29 22:58:22 +01:00
edern-appere b99c87d1bd Added French translation for Fdroid. 2019-11-29 22:46:43 +01:00
Dennis Guse 66ffbfe951 Fixed ChartFragment tests.
Initialization of looper was missing.
2019-11-29 22:43:51 +01:00
Dennis Guse 8cb01a1027 Bugfix: sharing a track was not adding the file(s).
While migrating to enable sharing multiple tracks a configuration option was missed.
2019-11-29 22:39:36 +01:00
Dennis Guse 193e5eccbb Cleanup. 2019-11-29 22:39:36 +01:00
Dennis Guse bf7fc28bb0 Bugfix: picture name suffixes were malformed on export and thus could not be re-imported. 2019-11-29 22:39:31 +01:00
Dennis Guse e35cbc343a Add pull request template. 2019-11-29 07:54:39 +01:00
Dennis Guse 1c7b053c8c Fixed MarkerDetailActivity.
The orientation of the layout was not set and thus adding the toolbar broke the UI.
2019-11-28 18:09:11 +01:00
Dennis Guse 88cdcd4b47 Use GestureDetector rather than doing it on our own. 2019-11-27 21:42:05 +01:00
Dennis Guse 1432fed8f9 Removed zoom controls for ChartFragment. 2019-11-27 21:41:53 +01:00
Dennis Guse a14307b9a4 Moved Chart* into own package. 2019-11-27 20:19:12 +01:00
Dennis Guse 3bdce5aa08 Cleanup: use autocloseable. 2019-11-25 23:09:08 +01:00
Dennis Guse d7526f93b8 Cleanup: removed ContentProviderUtils interface. 2019-11-25 23:02:48 +01:00
48 changed files with 1285 additions and 1473 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
---
name: Bug report
about: Report issues of Opentracks features
about: Report issues of OpenTracks features
title: ''
labels: potential bug
assignees: ''
+10
View File
@@ -0,0 +1,10 @@
# Thanks for your contribution.
**Describe the pull request**
A clear and concise description of what the pull request changes/adds.
**Link to the the issue**
(If available): The link to the issue that this pull request solves.
**License agreement**
By opening this pull request, you are providing your contribution under the _Apache License 2.0_ (see [LICENSE.md](LICENSE.md)).
@@ -0,0 +1,10 @@
v3.2.8: OpenTracks
Changes:
- Chart: zoom via gestures
Bugfixes:
- Export via KMZ did not export picture filenames correctly
- Sharing multiple tracks did not include KMZ files
- MarkerDetailActivity's UI was not shown
- Settings crashed if preference of heart rate was not initialized
@@ -0,0 +1,9 @@
OpenTracks est une application de suivi d'activités sportives qui respecte totalement votre vie privée.
Fonctionnalités :
* Suivi d'activité : enregistre vos activités sportives et de plein air
* Photos et repères : ajout de photos et de repères pendant l'enregistrement de l'activité
* Rythme cardiaque : support des capteurs Bluetooth LE
* Export : export des traces au format KML ou GPX
* Pas d'accès internet requis : Internet n'est pas nécessaire pour le fonctionnement de l'application
@@ -0,0 +1 @@
OpenTracks est une application de suivi d'activités sportives qui respecte totalement votre vie privée.
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks;
package de.dennisguse.opentracks.chart;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -23,6 +23,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import de.dennisguse.opentracks.R;
/**
* Tests {@link ChartValueSeries}.
*
@@ -35,21 +35,19 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import de.dennisguse.opentracks.content.ContentProviderUtils.LocationFactory;
import de.dennisguse.opentracks.content.ContentProviderUtils.LocationIterator;
import de.dennisguse.opentracks.content.Waypoint.WaypointType;
import de.dennisguse.opentracks.stats.TripStatistics;
import static org.mockito.Mockito.when;
/**
* A unit test for {@link ContentProviderUtilsImpl}.
* A unit test for {@link ContentProviderUtils}.
*
* @author Bartlomiej Niechwiej
* @author Youtao Liu
*/
@RunWith(MockitoJUnitRunner.class)
public class CustomContentProviderUtilsImplTest {
public class CustomContentProviderUtilsTest {
private static final String NAME_PREFIX = "test name";
private static final String MOCK_DESC = "Mock Next Waypoint Desc!";
private static final String TEST_DESC = "Test Desc!";
@@ -69,13 +67,13 @@ public class CustomContentProviderUtilsImplTest {
@Before
public void setUp() {
providerUtils = ContentProviderUtils.Factory.get(context);
providerUtils = new ContentProviderUtils(context);
providerUtils.deleteAllTracks(context);
}
@Test
public void testLocationIterator_noPoints() {
testIterator(1, 0, 1, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(1, 0, 1, false, LocationFactory.DEFAULT_LOCATION_FACTORY);
}
@Test
@@ -105,36 +103,36 @@ public class CustomContentProviderUtilsImplTest {
@Test
public void testLocationIterator_noBatchAscending() {
testIterator(1, 50, 100, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 50, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(1, 50, 100, false, LocationFactory.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 50, false, LocationFactory.DEFAULT_LOCATION_FACTORY);
}
@Test
public void testLocationIterator_noBatchDescending() {
testIterator(1, 50, 100, true, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 50, true, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(1, 50, 100, true, LocationFactory.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 50, true, LocationFactory.DEFAULT_LOCATION_FACTORY);
}
@Test
public void testLocationIterator_batchAscending() {
testIterator(1, 50, 11, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 25, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(1, 50, 11, false, LocationFactory.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 25, false, LocationFactory.DEFAULT_LOCATION_FACTORY);
}
@Test
public void testLocationIterator_batchDescending() {
testIterator(1, 50, 11, true, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 25, true, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(1, 50, 11, true, LocationFactory.DEFAULT_LOCATION_FACTORY);
testIterator(2, 50, 25, true, LocationFactory.DEFAULT_LOCATION_FACTORY);
}
@Test
public void testLocationIterator_largeTrack() {
testIterator(1, 20000, 2000, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
testIterator(1, 20000, 2000, false, LocationFactory.DEFAULT_LOCATION_FACTORY);
}
private List<Location> testIterator(long trackId, int numPoints, int batchSize, boolean descending, LocationFactory locationFactory) {
long lastPointId = initializeTrack(trackId, numPoints);
((ContentProviderUtilsImpl) providerUtils).setDefaultCursorBatchSize(batchSize);
((ContentProviderUtils) providerUtils).setDefaultCursorBatchSize(batchSize);
List<Location> locations = new ArrayList<Location>(numPoints);
try (LocationIterator it = providerUtils.getTrackPointLocationIterator(trackId, -1L, descending, locationFactory)) {
while (it.hasNext()) {
@@ -173,7 +171,7 @@ public class CustomContentProviderUtilsImplTest {
// Load all inserted locations.
long lastPointId = -1;
int counter = 0;
try (LocationIterator it = providerUtils.getTrackPointLocationIterator(id, -1L, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY)) {
try (LocationIterator it = providerUtils.getTrackPointLocationIterator(id, -1L, false, LocationFactory.DEFAULT_LOCATION_FACTORY)) {
while (it.hasNext()) {
it.next();
lastPointId = it.getLocationId();
@@ -189,7 +187,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#createTrack(Cursor)}.
* Tests the method {@link ContentProviderUtils#createTrack(Cursor)}.
*/
@Test
public void testCreateTrack() {
@@ -216,7 +214,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#deleteAllTracks(Context)}
* Tests the method {@link ContentProviderUtils#deleteAllTracks(Context)}
*/
@Test
public void testDeleteAllTracks() {
@@ -245,7 +243,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#deleteTrack(Context, long)}.
* Tests the method {@link ContentProviderUtils#deleteTrack(Context, long)}.
*/
@Test
public void testDeleteTrack() {
@@ -280,7 +278,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#getAllTracks()}
* Tests the method {@link ContentProviderUtils#getAllTracks()}
*/
@Test
public void testGetAllTracks() {
@@ -293,7 +291,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#getLastTrack()}
* Tests the method {@link ContentProviderUtils#getLastTrack()}
*/
@Test
public void testGetLastTrack() {
@@ -303,7 +301,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#getTrack(long)}
* Tests the method {@link ContentProviderUtils#getTrack(long)}
*/
@Test
public void testGetTrack() {
@@ -313,7 +311,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#updateTrack(Track)}
* Tests the method {@link ContentProviderUtils#updateTrack(Track)}
*/
@Test
public void testUpdateTrack() {
@@ -330,7 +328,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#createContentValues(Waypoint)}.
* Tests the method {@link ContentProviderUtils#createContentValues(Waypoint)}.
*/
@Test
public void testCreateContentValues_waypoint() {
@@ -368,7 +366,7 @@ public class CustomContentProviderUtilsImplTest {
waypoint.setLocation(location);
providerUtils.insertWaypoint(waypoint);
ContentProviderUtilsImpl contentProviderUtils = new ContentProviderUtilsImpl(contentResolverMock);
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(contentResolverMock);
long waypointId = System.currentTimeMillis();
waypoint.setId(waypointId);
@@ -381,7 +379,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#createWaypoint(Cursor)}.
* Tests the method {@link ContentProviderUtils#createWaypoint(Cursor)}.
*/
@Test
public void testCreateWaypoint() {
@@ -416,7 +414,7 @@ public class CustomContentProviderUtilsImplTest {
/**
* Tests the method
* {@link ContentProviderUtilsImpl#deleteWaypoint(Context, long, DescriptionGenerator)}
* {@link ContentProviderUtils#deleteWaypoint(Context, long, DescriptionGenerator)}
* when there is only one waypoint in the track.
*/
@Test
@@ -437,7 +435,7 @@ public class CustomContentProviderUtilsImplTest {
@Override
public String generateWaypointDescription(TripStatistics tripStatistics) {
return CustomContentProviderUtilsImplTest.MOCK_DESC;
return CustomContentProviderUtilsTest.MOCK_DESC;
}
@Override
@@ -452,7 +450,7 @@ public class CustomContentProviderUtilsImplTest {
/**
* Tests the method
* {@link ContentProviderUtilsImpl#deleteWaypoint(Context, long, DescriptionGenerator)}
* {@link ContentProviderUtils#deleteWaypoint(Context, long, DescriptionGenerator)}
* when there is more than one waypoint in the track.
*/
@Test
@@ -495,7 +493,7 @@ public class CustomContentProviderUtilsImplTest {
DescriptionGenerator descriptionGenerator = new DescriptionGenerator() {
@Override
public String generateWaypointDescription(TripStatistics tripStatistics) {
return CustomContentProviderUtilsImplTest.MOCK_DESC;
return CustomContentProviderUtilsTest.MOCK_DESC;
}
@Override
@@ -508,12 +506,12 @@ public class CustomContentProviderUtilsImplTest {
providerUtils.deleteWaypoint(context, waypoint1Id, descriptionGenerator);
Assert.assertNull(providerUtils.getWaypoint(waypoint1Id));
Assert.assertEquals(CustomContentProviderUtilsImplTest.MOCK_DESC, providerUtils.getWaypoint(waypoint2Id)
Assert.assertEquals(CustomContentProviderUtilsTest.MOCK_DESC, providerUtils.getWaypoint(waypoint2Id)
.getDescription());
}
/**
* Tests the method {@link ContentProviderUtilsImpl#getFirstWaypointId(long)}.
* Tests the method {@link ContentProviderUtils#getFirstWaypointId(long)}.
*/
@Test
public void testGetFirstWaypointId() {
@@ -535,7 +533,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#getNextWaypointNumber(long, WaypointType)}.
* Tests the method {@link ContentProviderUtils#getNextWaypointNumber(long, WaypointType)}.
*/
@Test
public void testGetNextWaypointNumber() {
@@ -594,8 +592,8 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#insertWaypoint(Waypoint)} and
* {@link ContentProviderUtilsImpl#getWaypoint(long)}.
* Tests the method {@link ContentProviderUtils#insertWaypoint(Waypoint)} and
* {@link ContentProviderUtils#getWaypoint(long)}.
*/
@Test
public void testInsertAndGetWaypoint() {
@@ -612,7 +610,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#updateWaypoint(Waypoint)}.
* Tests the method {@link ContentProviderUtils#updateWaypoint(Waypoint)}.
*/
@Test
public void testUpdateWaypoint() {
@@ -634,7 +632,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#bulkInsertTrackPoint(Location[], int, long)}.
* Tests the method {@link ContentProviderUtils#bulkInsertTrackPoint(Location[], int, long)}.
*/
@Test
public void testBulkInsertTrackPoint() {
@@ -650,7 +648,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#createTrackPoint(Cursor)}.
* Tests the method {@link ContentProviderUtils#createTrackPoint(Cursor)}.
*/
@Test
public void testCreateTrackPoint() {
@@ -710,7 +708,7 @@ public class CustomContentProviderUtilsImplTest {
/**
* Tests the method
* {@link ContentProviderUtilsImpl#insertTrackPoint(Location, long)}.
* {@link ContentProviderUtils#insertTrackPoint(Location, long)}.
*/
@Test
public void testInsertTrackPoint() {
@@ -724,7 +722,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#getFirstTrackPointId(long)}.
* Tests the method {@link ContentProviderUtils#getFirstTrackPointId(long)}.
*/
@Test
public void testGetFirstTrackPointId() {
@@ -737,7 +735,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#getLastTrackPointId(long)}.
* Tests the method {@link ContentProviderUtils#getLastTrackPointId(long)}.
*/
@Test
public void testGetLastTrackPointId() {
@@ -750,7 +748,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#getLastValidTrackPoint(long)}.
* Tests the method {@link ContentProviderUtils#getLastValidTrackPoint(long)}.
*/
@Test
public void testGetLastValidTrackPoint() {
@@ -764,7 +762,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#getTrackPointCursor(long, long, int, boolean)} in descending.
* Tests the method {@link ContentProviderUtils#getTrackPointCursor(long, long, int, boolean)} in descending.
*/
@Test
public void testGetTrackPointCursor_desc() {
@@ -783,7 +781,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#getTrackPointCursor(long, long, int, boolean)} in ascending.
* Tests the method {@link ContentProviderUtils#getTrackPointCursor(long, long, int, boolean)} in ascending.
*/
@Test
public void testGetTrackPointCursor_asc() {
@@ -802,7 +800,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#getTrackPointLocationIterator(long, long, boolean, LocationFactory)} in descending.
* Tests the method {@link ContentProviderUtils#getTrackPointLocationIterator(long, long, boolean, LocationFactory)} in descending.
*/
@Test
public void testGetTrackPointLocationIterator_desc() {
@@ -818,7 +816,7 @@ public class CustomContentProviderUtilsImplTest {
long startTrackPointId = trackpointIds[9];
LocationIterator locationIterator = providerUtils.getTrackPointLocationIterator(trackId, startTrackPointId, true, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
LocationIterator locationIterator = providerUtils.getTrackPointLocationIterator(trackId, startTrackPointId, true, LocationFactory.DEFAULT_LOCATION_FACTORY);
for (int i = 0; i < trackpointIds.length; i++) {
Assert.assertTrue(locationIterator.hasNext());
Location location = locationIterator.next();
@@ -829,7 +827,7 @@ public class CustomContentProviderUtilsImplTest {
}
/**
* Tests the method {@link ContentProviderUtilsImpl#getTrackPointLocationIterator(long, long, boolean, LocationFactory)} in ascending.
* Tests the method {@link ContentProviderUtils#getTrackPointLocationIterator(long, long, boolean, LocationFactory)} in ascending.
*/
@Test
public void testGetTrackPointLocationIterator_asc() {
@@ -845,7 +843,7 @@ public class CustomContentProviderUtilsImplTest {
long startTrackPointId = trackpointIds[0];
LocationIterator locationIterator = providerUtils.getTrackPointLocationIterator(trackId, startTrackPointId, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
LocationIterator locationIterator = providerUtils.getTrackPointLocationIterator(trackId, startTrackPointId, false, LocationFactory.DEFAULT_LOCATION_FACTORY);
for (int i = 0; i < trackpointIds.length; i++) {
Assert.assertTrue(locationIterator.hasNext());
Location location = locationIterator.next();
@@ -892,7 +890,7 @@ public class CustomContentProviderUtilsImplTest {
/**
* Checks the value of a location.
*
* @param i the index of this location which created in the method {@link CustomContentProviderUtilsImplTest#getTrack(long, int)}
* @param i the index of this location which created in the method {@link CustomContentProviderUtilsTest#getTrack(long, int)}
* @param location the location to be checked
*/
private void checkLocation(int i, Location location) {
@@ -58,7 +58,7 @@ public class SearchEngineTest {
@Before
public void setUp() {
providerUtils = ContentProviderUtils.Factory.get(context);
providerUtils = new ContentProviderUtils(context);
engine = new SearchEngine(providerUtils);
}
@@ -17,17 +17,20 @@
package de.dennisguse.opentracks.fragments;
import android.location.Location;
import android.os.Looper;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import de.dennisguse.opentracks.ChartView;
import de.dennisguse.opentracks.TrackStubUtils;
import de.dennisguse.opentracks.chart.ChartView;
import de.dennisguse.opentracks.content.SensorDataSetLocation;
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
import de.dennisguse.opentracks.util.UnitConversions;
@@ -44,6 +47,17 @@ public class ChartFragmentTest {
private ChartFragment chartFragment;
@BeforeClass
public static void preSetUp() {
// Prepare looper for Android's message queue
if (Looper.myLooper() == null) Looper.prepare();
}
@AfterClass
public static void finalTearDown() {
if (Looper.myLooper() != null) Looper.myLooper().quit();
}
@Before
public void setUp() {
boolean chartByDistance = false;
@@ -89,7 +89,7 @@ public class TrackRecordingServiceTest {
};
customContentProvider.attachInfo(context, null);
providerUtils = ContentProviderUtils.Factory.get(context);
providerUtils = new ContentProviderUtils(context);
// Let's use default values.
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
@@ -68,7 +68,7 @@ public class TrackRecordingServiceTestLooper {
};
customContentProvider.attachInfo(context, null);
providerUtils = ContentProviderUtils.Factory.get(context);
providerUtils = new ContentProviderUtils(context);
// Let's use default values.
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
@@ -60,10 +60,15 @@ public class FileUtilsTest extends TestCase {
*/
public void testSanitizeFileName() {
String name = "Swim\10ming-^across:/the/ pacific (ocean).";
String expected = "Swim_ming-^across_the_ pacific (ocean)_";
String expected = "Swim_ming-^across_the_ pacific (ocean).";
assertEquals(expected, FileUtils.sanitizeFileName(name));
}
public void testSanitizeFileNameWithSuffix() {
String name = "FileName.jpeg";
assertEquals(name, FileUtils.sanitizeFileName(name));
}
/**
* Tests {@link FileUtils#sanitizeFileName(String)} with i18n characters (in Chinese and Russian).
* Verifies that they are allowed.
+2 -2
View File
@@ -16,8 +16,8 @@ limitations under the License.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.dennisguse.opentracks"
android:installLocation="auto"
android:versionCode="3149"
android:versionName="v3.2.7"> <!-- For FDroid. -->
android:versionCode="3162"
android:versionName="v3.2.8"> <!-- For FDroid. -->
<!-- Permission to initialize services -->
<application
android:name=".Startup"
@@ -69,7 +69,7 @@ public class DeleteAsyncTask extends AsyncTask<Void, Integer, Boolean> {
@Override
protected Boolean doInBackground(Void... params) {
ContentProviderUtils contentProviderUtils = ContentProviderUtils.Factory.get(context);
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
if (trackIds.length == 1 && trackIds[0] == -1L) {
contentProviderUtils.deleteAllTracks(context);
@@ -61,7 +61,7 @@ public class MarkerDetailActivity extends AbstractActivity implements DeleteMark
return;
}
ContentProviderUtils contentProviderUtils = ContentProviderUtils.Factory.get(this);
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(this);
Waypoint waypoint = contentProviderUtils.getWaypoint(markerId);
markerIds = new ArrayList<>();
@@ -127,7 +127,7 @@ public class MarkerEditActivity extends AbstractActivity {
if (newMarker) {
statisticsSection.setVisibility(View.GONE);
waypointSection.setVisibility(View.VISIBLE);
int nextWaypointNumber = trackId == -1L ? -1 : ContentProviderUtils.Factory.get(this).getNextWaypointNumber(trackId, WaypointType.WAYPOINT);
int nextWaypointNumber = trackId == -1L ? -1 : new ContentProviderUtils(this).getNextWaypointNumber(trackId, WaypointType.WAYPOINT);
if (nextWaypointNumber == -1) {
nextWaypointNumber = 0;
}
@@ -136,7 +136,7 @@ public class MarkerEditActivity extends AbstractActivity {
waypointMarkerType.setText("");
waypointDescription.setText("");
} else {
waypoint = ContentProviderUtils.Factory.get(this).getWaypoint(markerId);
waypoint = new ContentProviderUtils(this).getWaypoint(markerId);
if (waypoint == null) {
Log.d(TAG, "waypoint is null");
finish();
@@ -182,6 +182,6 @@ public class MarkerEditActivity extends AbstractActivity {
waypoint.setCategory(waypointMarkerType.getText().toString());
waypoint.setDescription(waypointDescription.getText().toString());
}
ContentProviderUtils.Factory.get(this).updateWaypoint(waypoint);
new ContentProviderUtils(this).updateWaypoint(waypoint);
}
}
@@ -130,7 +130,7 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
recordingTrackPaused = PreferencesUtils.isRecordingTrackPausedDefault(this);
contentProviderUtils = ContentProviderUtils.Factory.get(this);
contentProviderUtils = new ContentProviderUtils(this);
sharedPreferences = PreferencesUtils.getSharedPreferences(this);
long trackId = getIntent().getLongExtra(EXTRA_TRACK_ID, -1L);
@@ -170,7 +170,7 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
recordingTrackPaused = PreferencesUtils.isRecordingTrackPausedDefault(this);
contentProviderUtils = ContentProviderUtils.Factory.get(this);
contentProviderUtils = new ContentProviderUtils(this);
sharedPreferences = PreferencesUtils.getSharedPreferences(this);
trackRecordingServiceConnection = new TrackRecordingServiceConnection(this, null);
searchEngine = new SearchEngine(contentProviderUtils);
@@ -189,7 +189,7 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
photoUri = savedInstanceState != null ? (Uri) savedInstanceState.getParcelable(PHOTO_URI_KEY) : null;
hasPhoto = savedInstanceState != null && savedInstanceState.getBoolean(HAS_PHOTO_KEY, false);
contentProviderUtils = ContentProviderUtils.Factory.get(this);
contentProviderUtils = new ContentProviderUtils(this);
handleIntent(getIntent());
sharedPreferences = PreferencesUtils.getSharedPreferences(this);
@@ -73,7 +73,7 @@ public class TrackEditActivity extends AbstractActivity implements ChooseActivit
return;
}
contentProviderUtils = ContentProviderUtils.Factory.get(this);
contentProviderUtils = new ContentProviderUtils(this);
track = contentProviderUtils.getTrack(trackId);
if (track == null) {
Log.e(TAG, "No track for " + trackId);
@@ -245,7 +245,7 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
recordingTrackPaused = PreferencesUtils.isRecordingTrackPausedDefault(this);
contentProviderUtils = ContentProviderUtils.Factory.get(this);
contentProviderUtils = new ContentProviderUtils(this);
sharedPreferences = PreferencesUtils.getSharedPreferences(this);
trackRecordingServiceConnection = new TrackRecordingServiceConnection(this, bindChangedCallback);
@@ -14,7 +14,7 @@
* the License.
*/
package de.dennisguse.opentracks;
package de.dennisguse.opentracks.chart;
import android.content.Context;
import android.graphics.Canvas;
@@ -14,7 +14,7 @@
* the License.
*/
package de.dennisguse.opentracks;
package de.dennisguse.opentracks.chart;
import android.content.Context;
import android.content.Intent;
@@ -27,15 +27,19 @@ import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.Scroller;
import androidx.core.view.GestureDetectorCompat;
import java.text.NumberFormat;
import java.util.ArrayList;
import de.dennisguse.opentracks.MarkerDetailActivity;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.Waypoint;
import de.dennisguse.opentracks.stats.ExtremityMonitor;
import de.dennisguse.opentracks.util.IntentUtils;
@@ -44,6 +48,7 @@ import de.dennisguse.opentracks.util.UnitConversions;
/**
* Visualization of the chart.
* Provides support for zooming (via pinch), scrolling, flinging, and selecting shown markers (single touch).
*
* @author Sandor Dornbush
* @author Leif Hendrik Wilden
@@ -91,8 +96,6 @@ public class ChartView extends View {
private final int markerHeight;
private final Scroller scroller;
private double maxX = 1.0;
private VelocityTracker velocityTracker = null;
private float lastMotionEventX = -1;
private int zoomLevel = 1;
private int leftBorder = BORDER;
@@ -112,11 +115,76 @@ public class ChartView extends View {
private boolean reportSpeed = true;
private boolean showPointer = false;
/**
* Constructor.
*
* @param context the context
*/
private GestureDetectorCompat detectorScrollFlingTab = new GestureDetectorCompat(getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
if (!scroller.isFinished()) {
scroller.abortAnimation();
}
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (Math.abs(distanceX) > 0) {
int availableToScroll = effectiveWidth * (zoomLevel - 1) - getScrollX();
if (availableToScroll > 0) {
scrollBy(Math.min(availableToScroll, (int) distanceX));
}
}
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
fling((int) -velocityX);
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent event) {
// Check if the y event is within markerHeight of the marker center
if (Math.abs(event.getY() - topBorder - spacer - markerHeight / 2) < markerHeight) {
int minDistance = Integer.MAX_VALUE;
Waypoint nearestWaypoint = null;
synchronized (waypoints) {
for (Waypoint waypoint : waypoints) {
int distance = Math.abs(getX(getWaypointXValue(waypoint)) - (int) event.getX() - getScrollX());
if (distance < minDistance) {
minDistance = distance;
nearestWaypoint = waypoint;
}
}
}
if (nearestWaypoint != null && minDistance < markerWidth) {
Intent intent = IntentUtils.newIntent(getContext(), MarkerDetailActivity.class)
.putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, nearestWaypoint.getId());
getContext().startActivity(intent);
return true;
}
}
return false;
}
});
private ScaleGestureDetector detectorZoom = new ScaleGestureDetector(getContext(), new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactor = detector.getScaleFactor();
if (scaleFactor >= 1.1f) {
zoomIn();
return true;
} else if (scaleFactor <= 0.9) {
zoomOut();
return true;
}
return false;
}
});
public ChartView(Context context, boolean chartByDistance) {
super(context);
this.chartByDistance = chartByDistance;
@@ -223,16 +291,6 @@ public class ChartView extends View {
series[index].setEnabled(enabled);
}
/**
* Sets chart by distance.
* It is expected that after changing this value, data will be reloaded.
*
* @param value true for by distance, false for by time
*/
public void setChartByDistance(boolean value) {
chartByDistance = value;
}
/**
* Sets metric units.
*
@@ -411,79 +469,14 @@ public class ChartView extends View {
@Override
public boolean onTouchEvent(MotionEvent event) {
if (velocityTracker == null) {
velocityTracker = VelocityTracker.obtain();
}
velocityTracker.addMovement(event);
float x = event.getX();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Stop the fling
if (!scroller.isFinished()) {
scroller.abortAnimation();
}
lastMotionEventX = x;
break;
case MotionEvent.ACTION_MOVE:
if (lastMotionEventX == -1) {
break;
}
// Scroll to follow the motion event
int deltaX = (int) (lastMotionEventX - x);
lastMotionEventX = x;
if (deltaX < 0) {
if (getScrollX() > 0) {
scrollBy(deltaX);
}
} else if (deltaX > 0) {
int availableToScroll = effectiveWidth * (zoomLevel - 1) - getScrollX();
if (availableToScroll > 0) {
scrollBy(Math.min(availableToScroll, deltaX));
}
}
break;
case MotionEvent.ACTION_UP:
// Check if the y event is within markerHeight of the marker center
if (Math.abs(event.getY() - topBorder - spacer - markerHeight / 2) < markerHeight) {
int minDistance = Integer.MAX_VALUE;
Waypoint nearestWaypoint = null;
synchronized (waypoints) {
for (int i = 0; i < waypoints.size(); i++) {
Waypoint waypoint = waypoints.get(i);
int distance = Math.abs(getX(getWaypointXValue(waypoint)) - (int) event.getX() - getScrollX());
if (distance < minDistance) {
minDistance = distance;
nearestWaypoint = waypoint;
}
}
}
if (nearestWaypoint != null && minDistance < markerWidth) {
Intent intent = IntentUtils.newIntent(getContext(), MarkerDetailActivity.class)
.putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, nearestWaypoint.getId());
getContext().startActivity(intent);
return true;
}
}
VelocityTracker myVelocityTracker = velocityTracker;
myVelocityTracker.computeCurrentVelocity(1000);
int initialVelocity = (int) myVelocityTracker.getXVelocity();
if (Math.abs(initialVelocity) > ViewConfiguration.getMinimumFlingVelocity()) {
fling(-initialVelocity);
}
if (velocityTracker != null) {
velocityTracker.recycle();
velocityTracker = null;
}
break;
}
return true;
boolean isZoom = detectorZoom.onTouchEvent(event);
boolean isScrollTab = detectorScrollFlingTab.onTouchEvent(event);
return isZoom || isScrollTab;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
updateEffectiveDimensionsIfChanged(
View.MeasureSpec.getSize(widthMeasureSpec), View.MeasureSpec.getSize(heightMeasureSpec));
updateEffectiveDimensionsIfChanged(View.MeasureSpec.getSize(widthMeasureSpec), View.MeasureSpec.getSize(heightMeasureSpec));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@@ -633,8 +626,7 @@ public class ChartView extends View {
private String getXAxisLabel() {
Context context = getContext();
if (chartByDistance) {
return metricUnits ? context.getString(R.string.unit_kilometer)
: context.getString(R.string.unit_mile);
return metricUnits ? context.getString(R.string.unit_kilometer) : context.getString(R.string.unit_mile);
} else {
return context.getString(R.string.description_time);
}
@@ -734,8 +726,7 @@ public class ChartView extends View {
* @param yValue the y value
* @return the marker width.
*/
private float drawYAxisMarker(
ChartValueSeries chartValueSeries, Canvas canvas, int xPosition, int yValue) {
private float drawYAxisMarker(ChartValueSeries chartValueSeries, Canvas canvas, int xPosition, int yValue) {
String marker = chartValueSeries.formatMarker(yValue);
Paint paint = chartValueSeries.getMarkerPaint();
Rect rect = getRect(paint, marker);
@@ -870,8 +861,7 @@ public class ChartView extends View {
topBorder = (int) (density * BORDER + titleDimensions[0] * (titleDimensions[1] + spacer));
Rect xAxisLabelRect = getRect(axisPaint, getXAxisLabel());
// border + x axis marker + spacer + .5 x axis label
bottomBorder = (int) (density * BORDER + getRect(xAxisMarkerPaint, "1").height() + spacer
+ (xAxisLabelRect.height() / 2));
bottomBorder = (int) (density * BORDER + getRect(xAxisMarkerPaint, "1").height() + spacer + (xAxisLabelRect.height() / 2));
rightBorder = (int) (density * BORDER + xAxisLabelRect.width() + spacer);
updateEffectiveDimensions();
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,20 @@
package de.dennisguse.opentracks.content;
import android.location.Location;
import android.location.LocationManager;
/**
* Creates a new {@link SensorDataSetLocation}.
* An implementation can create new instances or reuse existing instances for optimization.
*/
public class LocationFactory {
/**
* The default {@link LocationFactory} which creates a location each time.
*/
public static LocationFactory DEFAULT_LOCATION_FACTORY = new LocationFactory();
public Location createLocation() {
return new SensorDataSetLocation(LocationManager.GPS_PROVIDER);
}
}
@@ -0,0 +1,22 @@
package de.dennisguse.opentracks.content;
import android.database.Cursor;
import android.location.Location;
import java.util.Iterator;
/**
* A lightweight wrapper around the original {@link Cursor} with a method to clean up.
*/
public interface LocationIterator extends Iterator<Location>, AutoCloseable {
/**
* Gets the most recently retrieved track point id by {@link #next()}.
*/
long getLocationId();
/**
* Closes the iterator.
*/
void close();
}
@@ -198,7 +198,7 @@ public class ShareContentProvider extends CustomContentProvider implements ICont
@Nullable
@Override
public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException {
ContentProviderUtils contentProviderUtils = new ContentProviderUtilsImpl(this);
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(this);
long[] trackIds = parseURI(uri);
final Track[] tracks = new Track[trackIds.length];
@@ -30,7 +30,6 @@ import java.util.EnumSet;
import java.util.Set;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.ContentProviderUtils.LocationIterator;
import de.dennisguse.opentracks.util.LocationUtils;
import de.dennisguse.opentracks.util.PreferencesUtils;
@@ -45,7 +44,7 @@ public class TrackDataHub implements DataSourceListener {
* Target number of track points displayed by the map overlay.
* We may display more than this number of points.
*/
static final int TARGET_DISPLAYED_TRACK_POINTS = 5000;
private static final int TARGET_DISPLAYED_TRACK_POINTS = 5000;
/**
* Maximum number of waypoints to displayed.
@@ -97,8 +96,7 @@ public class TrackDataHub implements DataSourceListener {
}
public synchronized static TrackDataHub newInstance(Context context) {
return new TrackDataHub(context, new TrackDataManager(), ContentProviderUtils.Factory.get(
context), TARGET_DISPLAYED_TRACK_POINTS);
return new TrackDataHub(context, new TrackDataManager(), new ContentProviderUtils(context), TARGET_DISPLAYED_TRACK_POINTS);
}
public void start() {
@@ -448,7 +446,7 @@ public class TrackDataHub implements DataSourceListener {
int samplingFrequency = -1;
boolean includeNextPoint = false;
try (LocationIterator locationIterator = contentProviderUtils.getTrackPointLocationIterator(selectedTrackId, localLastSeenLocationId + 1, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY)) {
try (LocationIterator locationIterator = contentProviderUtils.getTrackPointLocationIterator(selectedTrackId, localLastSeenLocationId + 1, false, LocationFactory.DEFAULT_LOCATION_FACTORY)) {
while (locationIterator.hasNext()) {
Location location = locationIterator.next();
@@ -22,7 +22,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ZoomControls;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -33,9 +32,9 @@ import androidx.fragment.app.FragmentActivity;
import java.util.ArrayList;
import java.util.EnumSet;
import de.dennisguse.opentracks.ChartView;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TrackDetailActivity;
import de.dennisguse.opentracks.chart.ChartView;
import de.dennisguse.opentracks.content.SensorDataSetLocation;
import de.dennisguse.opentracks.content.Track;
import de.dennisguse.opentracks.content.TrackDataHub;
@@ -77,10 +76,9 @@ public abstract class ChartFragment extends Fragment implements TrackDataListene
// UI elements
private ChartView chartView;
private ZoomControls zoomControls;
/**
* A runnable that will enable/disable zoom controls and orange pointer as appropriate and redraw.
* A runnable that will set the orange pointer as appropriate and redraw.
*/
private final Runnable updateChart = new Runnable() {
@Override
@@ -89,8 +87,6 @@ public abstract class ChartFragment extends Fragment implements TrackDataListene
return;
}
zoomControls.setIsZoomInEnabled(chartView.canZoomIn());
zoomControls.setIsZoomOutEnabled(chartView.canZoomOut());
chartView.setShowPointer(isSelectedTrackRecording());
chartView.invalidate();
}
@@ -112,21 +108,7 @@ public abstract class ChartFragment extends Fragment implements TrackDataListene
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.chart, container, false);
zoomControls = view.findViewById(R.id.chart_zoom_controls);
zoomControls.setOnZoomInClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
zoomIn();
}
});
zoomControls.setOnZoomOutClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
zoomOut();
}
});
return view;
return inflater.inflate(R.layout.chart, container, false);
}
@Override
@@ -401,18 +383,6 @@ public abstract class ChartFragment extends Fragment implements TrackDataListene
}
}
private void zoomIn() {
chartView.zoomIn();
zoomControls.setIsZoomInEnabled(chartView.canZoomIn());
zoomControls.setIsZoomOutEnabled(chartView.canZoomOut());
}
private void zoomOut() {
chartView.zoomOut();
zoomControls.setIsZoomInEnabled(chartView.canZoomIn());
zoomControls.setIsZoomOutEnabled(chartView.canZoomOut());
}
/**
* Runs a runnable on the UI thread if possible.
*
@@ -81,7 +81,7 @@ public class DeleteMarkerDialogFragment extends DialogFragment {
new Thread(new Runnable() {
@Override
public void run() {
ContentProviderUtils contentProviderUtils = ContentProviderUtils.Factory.get(fragmentActivity);
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(fragmentActivity);
for (long markerId : markerIds) {
contentProviderUtils.deleteWaypoint(fragmentActivity,
markerId, new DescriptionGeneratorImpl(fragmentActivity));
@@ -110,7 +110,7 @@ public class MarkerDetailFragment extends Fragment {
getFragmentManager().popBackStack();
return;
}
contentProviderUtils = ContentProviderUtils.Factory.get(getActivity());
contentProviderUtils = new ContentProviderUtils(getActivity());
handler = new Handler();
setHasOptionsMenu(true);
}
@@ -173,10 +173,12 @@ public enum TrackFileFormat {
private static final String MIME_KML = "application/vnd.google-earth.kml+xml";
public TrackExporter newTrackExporter(Context context, Track[] tracks, TrackExporterListener trackExporterListener) {
ContentProviderUtils contentProviderUtils = ContentProviderUtils.Factory.get(context);
TrackWriter trackWriter = this.newTrackWriter(context, tracks.length > 1);
return new FileTrackExporter(contentProviderUtils, trackWriter, tracks, trackExporterListener);
private static TrackExporter newKmzTrackExporter(Context context, TrackWriter trackWriter, Track[] tracks, TrackExporterListener trackExporterListener, boolean exportPhotos) {
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
FileTrackExporter fileTrackExporter = new FileTrackExporter(contentProviderUtils, trackWriter, tracks, trackExporterListener);
return new KmzTrackExporter(contentProviderUtils, fileTrackExporter, tracks, exportPhotos);
}
/**
@@ -184,12 +186,10 @@ public enum TrackFileFormat {
*/
public abstract String getMimeType();
private static TrackExporter newKmzTrackExporter(Context context, TrackWriter trackWriter, Track[] tracks, TrackExporterListener trackExporterListener, boolean exportPhotos) {
ContentProviderUtils contentProviderUtils = ContentProviderUtils.Factory.get(context);
FileTrackExporter fileTrackExporter = new FileTrackExporter(contentProviderUtils, trackWriter, tracks, trackExporterListener);
return new KmzTrackExporter(contentProviderUtils, fileTrackExporter, tracks, exportPhotos);
public TrackExporter newTrackExporter(Context context, Track[] tracks, TrackExporterListener trackExporterListener) {
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
TrackWriter trackWriter = this.newTrackWriter(context, tracks.length > 1);
return new FileTrackExporter(contentProviderUtils, trackWriter, tracks, trackExporterListener);
}
/**
@@ -68,7 +68,7 @@ public class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
this.trackFileFormat = trackFileFormat;
this.directory = directory;
context = exportActivity.getApplicationContext();
contentProviderUtils = ContentProviderUtils.Factory.get(context);
contentProviderUtils = new ContentProviderUtils(context);
completed = false;
processedTrackCount = 0;
@@ -26,7 +26,8 @@ import androidx.annotation.NonNull;
import java.io.OutputStream;
import de.dennisguse.opentracks.content.ContentProviderUtils;
import de.dennisguse.opentracks.content.ContentProviderUtils.LocationIterator;
import de.dennisguse.opentracks.content.LocationFactory;
import de.dennisguse.opentracks.content.LocationIterator;
import de.dennisguse.opentracks.content.SensorDataSetLocation;
import de.dennisguse.opentracks.content.Track;
import de.dennisguse.opentracks.content.Waypoint;
@@ -63,7 +64,7 @@ public class FileTrackExporter implements TrackExporter {
}
@Override
public boolean writeTrack(Context context, @NonNull OutputStream outputStream) {
public boolean writeTrack(@NonNull Context context, @NonNull OutputStream outputStream) {
try {
trackWriter.prepare(outputStream);
trackWriter.writeHeader(tracks);
@@ -209,7 +210,7 @@ public class FileTrackExporter implements TrackExporter {
*
* @author Jimmy Shih
*/
private class TrackWriterLocationFactory implements ContentProviderUtils.LocationFactory {
private class TrackWriterLocationFactory extends LocationFactory {
Location currentLocation;
Location lastLocation;
@@ -89,7 +89,7 @@ public class KmlTrackWriter implements TrackWriter {
this.exportSensorData = exportSensorData;
this.exportPhotos = exportPhotos;
this.descriptionGenerator = new DescriptionGeneratorImpl(context);
this.contentProviderUtils = ContentProviderUtils.Factory.get(context);
this.contentProviderUtils = new ContentProviderUtils(context);
}
@Override
@@ -19,7 +19,6 @@ package de.dennisguse.opentracks.io.file.exporter;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.OutputStream;
@@ -37,5 +36,5 @@ public interface TrackExporter {
* @param context the context
* @param outputStream the output stream
*/
boolean writeTrack(@Nullable Context context, @NonNull OutputStream outputStream);
boolean writeTrack(@NonNull Context context, @NonNull OutputStream outputStream);
}
@@ -39,8 +39,9 @@ import javax.xml.parsers.SAXParserFactory;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.content.ContentProviderUtils;
import de.dennisguse.opentracks.content.ContentProviderUtils.LocationIterator;
import de.dennisguse.opentracks.content.DescriptionGeneratorImpl;
import de.dennisguse.opentracks.content.LocationFactory;
import de.dennisguse.opentracks.content.LocationIterator;
import de.dennisguse.opentracks.content.Track;
import de.dennisguse.opentracks.content.Waypoint;
import de.dennisguse.opentracks.content.Waypoint.WaypointType;
@@ -165,7 +166,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
TripStatisticsUpdater trackTripStatisticstrackUpdater = new TripStatisticsUpdater(track.getTripStatistics().getStartTime());
TripStatisticsUpdater markerTripStatisticsUpdater = new TripStatisticsUpdater(track.getTripStatistics().getStartTime());
try (LocationIterator locationIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), -1L, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY)) {
try (LocationIterator locationIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), -1L, false, LocationFactory.DEFAULT_LOCATION_FACTORY)) {
while (true) {
if (waypoint == null) {
@@ -55,7 +55,7 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
* @param context the context
*/
public GpxFileTrackImporter(Context context) {
this(context, ContentProviderUtils.Factory.get(context));
this(context, new ContentProviderUtils(context));
}
@VisibleForTesting
@@ -45,7 +45,9 @@ public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
private static final String TAG = ImportAsyncTask.class.getSimpleName();
private final TrackFileFormat trackFileFormat;
private final String path;
private final Context context;
// TODO Can be removed, or?
private Context context;
// TODO Use weak reference
private ImportActivity importActivity;
private WakeLock wakeLock;
@@ -100,7 +102,7 @@ public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
@Override
protected Boolean doInBackground(Void... params) {
try {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
Thread.currentThread().setPriority(Thread.MAX_PRIORITY); // TODO Should be set to previous level at the end of this method.
// Get the wake lock if not recording or paused
boolean isRecording = PreferencesUtils.isRecording(importActivity);
boolean isPaused = PreferencesUtils.isRecordingTrackPaused(importActivity);
@@ -149,9 +151,11 @@ public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
@Override
protected void onCancelled() {
context = null;
completed = true;
if (importActivity != null) {
importActivity.onAsyncTaskCompleted(importTrackCount, totalTrackCount);
importActivity = null;
}
}
@@ -163,17 +167,17 @@ public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
private boolean importFile(final File file) {
TrackImporter trackImporter;
if (trackFileFormat == TrackFileFormat.GPX) {
trackImporter = new GpxFileTrackImporter(context);
trackImporter = new GpxFileTrackImporter(importActivity);
} else { //KML or KMZ
String extension = FileUtils.getExtension(file.getName());
if (TrackFileFormat.KML_ONLY_TRACK.getExtension().equals(extension)) {
trackImporter = new KmlFileTrackImporter(context, -1L);
trackImporter = new KmlFileTrackImporter(importActivity, -1L);
} else {
ContentProviderUtils contentProviderUtils = ContentProviderUtils.Factory.get(context);
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(importActivity);
Uri uri = contentProviderUtils.insertTrack(new Track());
long newId = Long.parseLong(uri.getLastPathSegment());
trackImporter = new KmzTrackImporter(context, newId);
trackImporter = new KmzTrackImporter(importActivity, newId);
}
}
@@ -81,7 +81,7 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
* @param importTrackId track id to import to. -1L to import to a new track.
*/
public KmlFileTrackImporter(Context context, long importTrackId) {
this(context, importTrackId, ContentProviderUtils.Factory.get(context));
this(context, importTrackId, new ContentProviderUtils(context));
}
@VisibleForTesting
@@ -72,7 +72,7 @@ public class KmzTrackImporter implements TrackImporter {
return -1L;
}
String fileName = zipEntry.getName();
if (fileName.equals(KmzTrackExporter.KMZ_KML_FILE)) {
if (KmzTrackExporter.KMZ_KML_FILE.equals(fileName)) {
trackId = parseKml(zipInputStream);
if (trackId == -1L) {
Log.d(TAG, "Unable to parse kml in kmz");
@@ -102,7 +102,7 @@ public class KmzTrackImporter implements TrackImporter {
*/
private void cleanImport(long trackId) {
if (PreferencesUtils.isRecording(trackId)) {
ContentProviderUtils contentProviderUtils = ContentProviderUtils.Factory.get(context);
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
contentProviderUtils.deleteTrack(context, trackId);
}
@@ -125,15 +125,10 @@ public class KmzTrackImporter implements TrackImporter {
* @return the imported track id or -1L
*/
private long parseKml(ZipInputStream zipInputStream) throws IOException {
ByteArrayInputStream byteArrayInputStream = null;
try {
KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter(context, importTrackId);
byteArrayInputStream = new ByteArrayInputStream(getKml(zipInputStream));
KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter(context, importTrackId);
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(getKml(zipInputStream))) {
return kmlFileTrackImporter.importFile(byteArrayInputStream);
} finally {
if (byteArrayInputStream != null) {
byteArrayInputStream.close();
}
}
}
@@ -160,12 +155,10 @@ public class KmzTrackImporter implements TrackImporter {
* @param fileName the file name
*/
private void readImageFile(ZipInputStream zipInputStream, String fileName) throws IOException {
if (importTrackId == -1L) {
return;
}
if (fileName.equals("")) {
if (importTrackId == -1L || fileName.equals("")) {
return;
}
File dir = FileUtils.getPhotoDir(importTrackId);
FileUtils.ensureDirectoryExists(dir);
File file = new File(dir, fileName);
@@ -43,9 +43,10 @@ import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TrackDetailActivity;
import de.dennisguse.opentracks.TrackListActivity;
import de.dennisguse.opentracks.content.ContentProviderUtils;
import de.dennisguse.opentracks.content.ContentProviderUtils.LocationIterator;
import de.dennisguse.opentracks.content.CustomContentProvider;
import de.dennisguse.opentracks.content.DescriptionGeneratorImpl;
import de.dennisguse.opentracks.content.LocationFactory;
import de.dennisguse.opentracks.content.LocationIterator;
import de.dennisguse.opentracks.content.SensorDataSetLocation;
import de.dennisguse.opentracks.content.Track;
import de.dennisguse.opentracks.content.Waypoint;
@@ -214,7 +215,7 @@ public class TrackRecordingService extends Service {
public void onCreate() {
super.onCreate();
executorService = Executors.newSingleThreadExecutor();
contentProviderUtils = ContentProviderUtils.Factory.get(this);
contentProviderUtils = new ContentProviderUtils(this);
handler = new Handler();
locationManagerConnector = new LocationManagerConnector(this, handler.getLooper());
voiceExecutor = new PeriodicTaskExecutor(this, new AnnouncementPeriodicTaskFactory());
@@ -506,7 +507,7 @@ public class TrackRecordingService extends Service {
}
markerTripStatisticsUpdater = new TripStatisticsUpdater(markerStartTime);
try (LocationIterator locationIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), -1L, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY)) {
try (LocationIterator locationIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), -1L, false, LocationFactory.DEFAULT_LOCATION_FACTORY)) {
while (locationIterator.hasNext()) {
Location location = locationIterator.next();
@@ -147,7 +147,7 @@ public class BluetoothLePreference extends DialogPreference {
BluetoothLePreference preference = (BluetoothLePreference) getPreference();
String deviceSelected = preference.getValue();
if (!deviceNone.equals(deviceSelected)) {
if (deviceSelected != null && !deviceNone.equals(deviceSelected)) {
listAdapter.add(preference.getValue(), preference.getValue());
selectedEntryIndex = 1;
}
@@ -204,12 +204,13 @@ public class FileUtils {
*
* @param name name
*/
// TODO Check if this function is still needed.
public static String sanitizeFileName(String name) {
StringBuilder builder = new StringBuilder(name.length());
for (int i = 0; i < name.length(); i++) {
int codePoint = name.codePointAt(i);
char character = name.charAt(i);
if (Character.isLetterOrDigit(character) || codePoint > 127 || isSpecialFat32(character)) {
if (Character.isLetterOrDigit(character) || codePoint > 127 || isSpecialFat32(character) || character == '.') {
builder.appendCodePoint(codePoint);
} else {
builder.append("_");
@@ -76,7 +76,7 @@ public class IntentUtils {
}
String trackDescription = "";
if (trackIds.length == 1) {
Track track = ContentProviderUtils.Factory.get(context).getTrack(trackIds[0]);
Track track = new ContentProviderUtils(context).getTrack(trackIds[0]);
trackDescription = track == null ? "" : new DescriptionGeneratorImpl(context).generateTrackDescription(track, false);
}
@@ -89,13 +89,13 @@ public class IntentUtils {
uris.add(uriAndMime.first);
mime = uriAndMime.second;
}
return new Intent(action)
.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.share_track_subject))
.putExtra(Intent.EXTRA_TEXT, context.getString(R.string.share_track_share_file_body, trackDescription))
.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
.setType(mime)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
.setAction(Intent.ACTION_SEND_MULTIPLE)
.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.share_track_subject))
.putExtra(Intent.EXTRA_TEXT, context.getString(R.string.share_track_share_file_body, trackDescription));
}
public static void showCoordinateOnMap(Context context, Waypoint waypoint) {
+4 -18
View File
@@ -14,22 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/chart_view_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/chart_view_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical" />
<ZoomControls
android:id="@+id/chart_zoom_controls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:gravity="right"
android:paddingRight="8dp" />
</LinearLayout>
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical" />
@@ -15,7 +15,8 @@ limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar" />