This commit is contained in:
Dennis Guse
2020-01-03 22:34:11 +01:00
parent 27e50b2dd9
commit 09fe35f1ca
38 changed files with 120 additions and 208 deletions
@@ -415,7 +415,7 @@ public class CustomContentProviderUtilsTest {
/** /**
* Tests the method * Tests the method
* {@link ContentProviderUtils#deleteWaypoint(Context, long)} * {@link ContentProviderUtils#deleteWaypoint(long)}
* when there is only one waypoint in the track. * when there is only one waypoint in the track.
*/ */
@Test @Test
@@ -431,14 +431,14 @@ public class CustomContentProviderUtilsTest {
contentProviderUtils.insertWaypoint(waypoint1); contentProviderUtils.insertWaypoint(waypoint1);
// Delete // Delete
contentProviderUtils.deleteWaypoint(context, 1); contentProviderUtils.deleteWaypoint(1);
Assert.assertNull(contentProviderUtils.getWaypoint(1)); Assert.assertNull(contentProviderUtils.getWaypoint(1));
} }
/** /**
* Tests the method * Tests the method
* {@link ContentProviderUtils#deleteWaypoint(Context, long)} * {@link ContentProviderUtils#deleteWaypoint(long)}
* when there is more than one waypoint in the track. * when there is more than one waypoint in the track.
*/ */
@Test @Test
@@ -476,7 +476,7 @@ public class CustomContentProviderUtilsTest {
// Delete // Delete
Assert.assertNotNull(contentProviderUtils.getWaypoint(waypoint1Id)); Assert.assertNotNull(contentProviderUtils.getWaypoint(waypoint1Id));
contentProviderUtils.deleteWaypoint(context, waypoint1Id); contentProviderUtils.deleteWaypoint(waypoint1Id);
Assert.assertNull(contentProviderUtils.getWaypoint(waypoint1Id)); Assert.assertNull(contentProviderUtils.getWaypoint(waypoint1Id));
Assert.assertEquals(MOCK_DESC, contentProviderUtils.getWaypoint(waypoint2Id).getDescription()); Assert.assertEquals(MOCK_DESC, contentProviderUtils.getWaypoint(waypoint2Id).getDescription());
@@ -507,32 +507,6 @@ public class CustomContentProviderUtilsTest {
Assert.assertEquals(4, contentProviderUtils.getNextWaypointNumber(trackId)); Assert.assertEquals(4, contentProviderUtils.getNextWaypointNumber(trackId));
} }
/**
* Tests the method
* {@link ContentProviderUtils#getLastWaypoint(long)}.
*/
@Test
public void testGetLastWaypoint() {
long trackId = System.currentTimeMillis();
Track track = TestDataUtil.getTrack(trackId, 10);
contentProviderUtils.insertTrack(track);
Waypoint waypoint1 = new Waypoint();
waypoint1.setTrackId(trackId);
waypoint1.setDescription("Desc1");
Waypoint waypoint2 = new Waypoint();
waypoint2.setTrackId(trackId);
waypoint2.setDescription("Desc2");
Waypoint waypoint3 = new Waypoint();
waypoint3.setTrackId(trackId);
waypoint3.setDescription("Desc3");
contentProviderUtils.insertWaypoint(waypoint1);
contentProviderUtils.insertWaypoint(waypoint2);
contentProviderUtils.insertWaypoint(waypoint3);
Assert.assertEquals("Desc3", contentProviderUtils.getLastWaypoint(trackId).getDescription());
}
/** /**
* Tests the method {@link ContentProviderUtils#insertWaypoint(Waypoint)} and * Tests the method {@link ContentProviderUtils#insertWaypoint(Waypoint)} and
* {@link ContentProviderUtils#getWaypoint(long)}. * {@link ContentProviderUtils#getWaypoint(long)}.
@@ -47,7 +47,7 @@ public class TrackRecordingServiceTestLooper {
private Context context = ApplicationProvider.getApplicationContext(); private Context context = ApplicationProvider.getApplicationContext();
private ContentProviderUtils providerUtils; private ContentProviderUtils contentProviderUtils;
@BeforeClass @BeforeClass
public static void preSetUp() { public static void preSetUp() {
@@ -67,14 +67,14 @@ public class TrackRecordingServiceTestLooper {
}; };
customContentProvider.attachInfo(context, null); customContentProvider.attachInfo(context, null);
providerUtils = new ContentProviderUtils(context); contentProviderUtils = new ContentProviderUtils(context);
// Let's use default values. // Let's use default values.
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context); SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
sharedPreferences.edit().clear().apply(); sharedPreferences.edit().clear().apply();
// Ensure that the database is empty before every test // Ensure that the database is empty before every test
providerUtils.deleteAllTracks(context); contentProviderUtils.deleteAllTracks(context);
} }
@After @After
@@ -86,7 +86,7 @@ public class TrackRecordingServiceTestLooper {
} }
// Ensure that the database is empty after every test // Ensure that the database is empty after every test
providerUtils.deleteAllTracks(context); contentProviderUtils.deleteAllTracks(context);
} }
@MediumTest @MediumTest
@@ -186,7 +186,7 @@ public class TrackRecordingServiceTestLooper {
@MediumTest @MediumTest
@Test @Test
public void testIntegration_completeRecordingSession() throws TimeoutException { public void testIntegration_completeRecordingSession() throws TimeoutException {
List<Track> tracks = providerUtils.getAllTracks(); List<Track> tracks = contentProviderUtils.getAllTracks();
Assert.assertTrue(tracks.isEmpty()); Assert.assertTrue(tracks.isEmpty());
fullRecordingSession(); fullRecordingSession();
} }
@@ -199,7 +199,7 @@ public class TrackRecordingServiceTestLooper {
long id = service.startNewTrack(); long id = service.startNewTrack();
Assert.assertTrue(id >= 0); Assert.assertTrue(id >= 0);
Assert.assertTrue(service.isRecording()); Assert.assertTrue(service.isRecording());
Track track = providerUtils.getTrack(id); Track track = contentProviderUtils.getTrack(id);
Assert.assertNotNull(track); Assert.assertNotNull(track);
Assert.assertEquals(id, track.getId()); Assert.assertEquals(id, track.getId());
Assert.assertEquals(id, PreferencesUtils.getRecordingTrackId(context)); Assert.assertEquals(id, PreferencesUtils.getRecordingTrackId(context));
@@ -226,7 +226,7 @@ public class TrackRecordingServiceTestLooper {
service.endCurrentTrack(); service.endCurrentTrack();
Assert.assertFalse(service.isRecording()); Assert.assertFalse(service.isRecording());
Assert.assertEquals(-1L, service.getRecordingTrackId()); Assert.assertEquals(-1L, service.getRecordingTrackId());
track = providerUtils.getTrack(id); track = contentProviderUtils.getTrack(id);
Assert.assertNotNull(track); Assert.assertNotNull(track);
Assert.assertEquals(id, track.getId()); Assert.assertEquals(id, track.getId());
TripStatistics tripStatistics = track.getTripStatistics(); TripStatistics tripStatistics = track.getTripStatistics();
@@ -99,7 +99,7 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
// UI elements // UI elements
private ListView listView; private ListView listView;
// Callback when an item is selected in the contextual action mode // Callback when an item is selected in the contextual action mode
private ContextualActionModeCallback contextualActionModeCallback = new ContextualActionModeCallback() { private final ContextualActionModeCallback contextualActionModeCallback = new ContextualActionModeCallback() {
@Override @Override
public void onPrepare(Menu menu, int[] positions, long[] ids, boolean showSelectAll) { public void onPrepare(Menu menu, int[] positions, long[] ids, boolean showSelectAll) {
boolean isSingleSelection = ids.length == 1; boolean isSingleSelection = ids.length == 1;
@@ -104,7 +104,7 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
private boolean recordingTrackPaused; private boolean recordingTrackPaused;
// Callback when an item is selected in the contextual action mode // Callback when an item is selected in the contextual action mode
private ContextualActionModeCallback contextualActionModeCallback = new ContextualActionModeCallback() { private final ContextualActionModeCallback contextualActionModeCallback = new ContextualActionModeCallback() {
@Override @Override
public void onPrepare(Menu menu, int[] positions, long[] ids, boolean showSelectAll) { public void onPrepare(Menu menu, int[] positions, long[] ids, boolean showSelectAll) {
boolean isRecording = PreferencesUtils.isRecording(recordingTrackId); boolean isRecording = PreferencesUtils.isRecording(recordingTrackId);
@@ -195,7 +195,7 @@ public class TrackDetailActivity extends AbstractListActivity implements ChooseA
sharedPreferences = PreferencesUtils.getSharedPreferences(this); sharedPreferences = PreferencesUtils.getSharedPreferences(this);
trackRecordingServiceConnection = new TrackRecordingServiceConnection(this, bindChangedCallback); trackRecordingServiceConnection = new TrackRecordingServiceConnection(this, bindChangedCallback);
trackDataHub = TrackDataHub.newInstance(this); trackDataHub = new TrackDataHub(this);
FragmentPagerAdapter adapter = new FragmentPagerAdapter(getSupportFragmentManager(), 1) { FragmentPagerAdapter adapter = new FragmentPagerAdapter(getSupportFragmentManager(), 1) {
@Override @Override
@@ -13,7 +13,7 @@ import androidx.annotation.Nullable;
*/ */
public class ContentResolverWrapper implements IContentResolver { public class ContentResolverWrapper implements IContentResolver {
private ContentResolver contentResolver; private final ContentResolver contentResolver;
public ContentResolverWrapper(ContentResolver contentResolver) { public ContentResolverWrapper(ContentResolver contentResolver) {
this.contentResolver = contentResolver; this.contentResolver = contentResolver;
@@ -122,7 +122,7 @@ public class ChartView extends View {
private boolean reportSpeed = true; private boolean reportSpeed = true;
private boolean showPointer = false; private boolean showPointer = false;
private GestureDetectorCompat detectorScrollFlingTab = new GestureDetectorCompat(getContext(), new GestureDetector.SimpleOnGestureListener() { private final GestureDetectorCompat detectorScrollFlingTab = new GestureDetectorCompat(getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override @Override
public boolean onDown(MotionEvent e) { public boolean onDown(MotionEvent e) {
@@ -176,7 +176,7 @@ public class ChartView extends View {
} }
}); });
private ScaleGestureDetector detectorZoom = new ScaleGestureDetector(getContext(), new ScaleGestureDetector.SimpleOnScaleGestureListener() { private final ScaleGestureDetector detectorZoom = new ScaleGestureDetector(getContext(), new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@Override @Override
public boolean onScale(ScaleGestureDetector detector) { public boolean onScale(ScaleGestureDetector detector) {
@@ -39,7 +39,7 @@ public class DescriptionGenerator {
private static final String TEXT_LINE_BREAK = "\n"; private static final String TEXT_LINE_BREAK = "\n";
private static final String TEXT_PARAGRAPH_SEPARATOR = "\n\n"; private static final String TEXT_PARAGRAPH_SEPARATOR = "\n\n";
private Context context; private final Context context;
public DescriptionGenerator(Context context) { public DescriptionGenerator(Context context) {
this.context = context; this.context = context;
@@ -106,7 +106,7 @@ public class SearchEngine {
public static final long OLDEST_ALLOWED_TIMESTAMP = 946692000000L; public static final long OLDEST_ALLOWED_TIMESTAMP = 946692000000L;
/** /**
* Comparador for scored results. * Comparator for scored results.
*/ */
private static final Comparator<ScoredResult> SCORED_RESULT_COMPARATOR = new Comparator<ScoredResult>() { private static final Comparator<ScoredResult> SCORED_RESULT_COMPARATOR = new Comparator<ScoredResult>() {
@Override @Override
@@ -45,10 +45,6 @@ import de.dennisguse.opentracks.util.PreferencesUtils;
*/ */
public class TrackDataHub implements DataSourceListener { public class TrackDataHub implements DataSourceListener {
public synchronized static TrackDataHub newInstance(Context context) {
return new TrackDataHub(context, new TrackDataManager(), new ContentProviderUtils(context), TARGET_DISPLAYED_TRACK_POINTS);
}
/** /**
* Target number of track points displayed by the map overlay. * Target number of track points displayed by the map overlay.
* We may display more than this number of points. * We may display more than this number of points.
@@ -90,14 +86,10 @@ public class TrackDataHub implements DataSourceListener {
private long firstSeenLocationId; private long firstSeenLocationId;
private long lastSeenLocationId; private long lastSeenLocationId;
/** public TrackDataHub(Context context) {
* Constructor. this(context, new TrackDataManager(), new ContentProviderUtils(context), TARGET_DISPLAYED_TRACK_POINTS);
* }
* @param context the context
* @param trackDataManager the track data manager
* @param contentProviderUtils the content tracks provider utils
* @param targetNumPoints the target number of points
*/
@VisibleForTesting @VisibleForTesting
private TrackDataHub(Context context, TrackDataManager trackDataManager, ContentProviderUtils contentProviderUtils, int targetNumPoints) { private TrackDataHub(Context context, TrackDataManager trackDataManager, ContentProviderUtils contentProviderUtils, int targetNumPoints) {
this.context = context; this.context = context;
@@ -18,6 +18,8 @@ package de.dennisguse.opentracks.content.data;
import android.location.Location; import android.location.Location;
import androidx.annotation.VisibleForTesting;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -106,6 +108,7 @@ public class Track {
this.tripStatistics = tripStatistics; this.tripStatistics = tripStatistics;
} }
@VisibleForTesting
public void addLocation(Location location) { public void addLocation(Location location) {
locations.add(location); locations.add(location);
} }
@@ -0,0 +1,36 @@
package de.dennisguse.opentracks.content.provider;
import android.database.Cursor;
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
/**
* A cache of track points indexes.
*/
class CachedTrackPointsIndexes {
final int idIndex;
final int longitudeIndex;
final int latitudeIndex;
final int timeIndex;
final int altitudeIndex;
final int accuracyIndex;
final int speedIndex;
final int bearingIndex;
final int sensorHeartRateIndex;
final int sensorCadenceIndex;
final int sensorPowerIndex;
CachedTrackPointsIndexes(Cursor cursor) {
idIndex = cursor.getColumnIndex(TrackPointsColumns._ID);
longitudeIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.LONGITUDE);
latitudeIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.LATITUDE);
timeIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.TIME);
altitudeIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALTITUDE);
accuracyIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.ACCURACY);
speedIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SPEED);
bearingIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.BEARING);
sensorHeartRateIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_HEARTRATE);
sensorCadenceIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_CADENCE);
sensorPowerIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_POWER);
}
}
@@ -57,17 +57,17 @@ public class ContentProviderUtils {
/** /**
* The authority (the first part of the URI) for the app's content provider. * The authority (the first part of the URI) for the app's content provider.
*/ */
static String AUTHORITY_PACKAGE = BuildConfig.APPLICATION_ID + ".content"; static final String AUTHORITY_PACKAGE = BuildConfig.APPLICATION_ID + ".content";
/** /**
* The base URI for the app's content provider. * The base URI for the app's content provider.
*/ */
public static String CONTENT_BASE_URI = "content://" + AUTHORITY_PACKAGE; public static final String CONTENT_BASE_URI = "content://" + AUTHORITY_PACKAGE;
/** /**
* Maximum number of waypoints that will be loaded at one time. * Maximum number of waypoints that will be loaded at one time.
*/ */
public static int MAX_LOADED_WAYPOINTS_POINTS = 10000; public static final int MAX_LOADED_WAYPOINTS_POINTS = 10000;
private final IContentResolver contentResolver; private final IContentResolver contentResolver;
private int defaultCursorBatchSize = 2000; private int defaultCursorBatchSize = 2000;
@@ -107,8 +107,6 @@ public class ContentProviderUtils {
int nameIndex = cursor.getColumnIndexOrThrow(TracksColumns.NAME); int nameIndex = cursor.getColumnIndexOrThrow(TracksColumns.NAME);
int descriptionIndex = cursor.getColumnIndexOrThrow(TracksColumns.DESCRIPTION); int descriptionIndex = cursor.getColumnIndexOrThrow(TracksColumns.DESCRIPTION);
int categoryIndex = cursor.getColumnIndexOrThrow(TracksColumns.CATEGORY); int categoryIndex = cursor.getColumnIndexOrThrow(TracksColumns.CATEGORY);
int startIdIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTID);
int stopIdIndex = cursor.getColumnIndexOrThrow(TracksColumns.STOPID);
int startTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTTIME); int startTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTTIME);
int stopTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.STOPTIME); int stopTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.STOPTIME);
int numPointsIndex = cursor.getColumnIndexOrThrow(TracksColumns.NUMPOINTS); int numPointsIndex = cursor.getColumnIndexOrThrow(TracksColumns.NUMPOINTS);
@@ -240,9 +238,10 @@ public class ContentProviderUtils {
* If no track exists, an empty list is returned. * If no track exists, an empty list is returned.
* NOTE: the returned tracks do not have any track points attached. * NOTE: the returned tracks do not have any track points attached.
*/ */
@VisibleForTesting
public List<Track> getAllTracks() { public List<Track> getAllTracks() {
ArrayList<Track> tracks = new ArrayList<>(); ArrayList<Track> tracks = new ArrayList<>();
try (Cursor cursor = getTrackCursor(null, null, null, TracksColumns._ID)) { try (Cursor cursor = getTrackCursor(null, null, TracksColumns._ID)) {
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
tracks.ensureCapacity(cursor.getCount()); tracks.ensureCapacity(cursor.getCount());
do { do {
@@ -257,7 +256,7 @@ public class ContentProviderUtils {
* Gets the last track or null. * Gets the last track or null.
*/ */
public Track getLastTrack() { public Track getLastTrack() {
try (Cursor cursor = getTrackCursor(null, null, null, TracksColumns.STARTTIME + " DESC")) { try (Cursor cursor = getTrackCursor(null, null, TracksColumns.STARTTIME + " DESC")) {
// Using the same order as shown in the track list // Using the same order as shown in the track list
if (cursor != null && cursor.moveToNext()) { if (cursor != null && cursor.moveToNext()) {
return createTrack(cursor); return createTrack(cursor);
@@ -276,7 +275,7 @@ public class ContentProviderUtils {
if (trackId < 0) { if (trackId < 0) {
return null; return null;
} }
try (Cursor cursor = getTrackCursor(null, TracksColumns._ID + "=?", new String[]{Long.toString(trackId)}, TracksColumns._ID)) { try (Cursor cursor = getTrackCursor(TracksColumns._ID + "=?", new String[]{Long.toString(trackId)}, TracksColumns._ID)) {
if (cursor != null && cursor.moveToNext()) { if (cursor != null && cursor.moveToNext()) {
return createTrack(cursor); return createTrack(cursor);
} }
@@ -293,7 +292,7 @@ public class ContentProviderUtils {
* @param sortOrder the sort order. Can be null * @param sortOrder the sort order. Can be null
*/ */
public Cursor getTrackCursor(String selection, String[] selectionArgs, String sortOrder) { public Cursor getTrackCursor(String selection, String[] selectionArgs, String sortOrder) {
return getTrackCursor(null, selection, selectionArgs, sortOrder); return contentResolver.query(TracksColumns.CONTENT_URI, null, selection, selectionArgs, sortOrder);
} }
/** /**
@@ -348,17 +347,6 @@ public class ContentProviderUtils {
return values; return values;
} }
/**
* Gets a track cursor.
*
* @param projection the projection
* @param selection the selection
* @param selectionArgs the selection arguments
* @param sortOrder the sort oder
*/
private Cursor getTrackCursor(String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return contentResolver.query(TracksColumns.CONTENT_URI, projection, selection, selectionArgs, sortOrder);
}
/** /**
* Creates a waypoint from a cursor. * Creates a waypoint from a cursor.
@@ -446,7 +434,7 @@ public class ContentProviderUtils {
* @param waypointId the waypoint id * @param waypointId the waypoint id
*/ */
public void deleteWaypoint(Context context, long waypointId) { public void deleteWaypoint(long waypointId) {
final Waypoint waypoint = getWaypoint(waypointId); final Waypoint waypoint = getWaypoint(waypointId);
if (waypoint != null && waypoint.hasPhoto()) { if (waypoint != null && waypoint.hasPhoto()) {
Uri uri = waypoint.getPhotoURI(); Uri uri = waypoint.getPhotoURI();
@@ -462,26 +450,6 @@ public class ContentProviderUtils {
contentResolver.delete(WaypointsColumns.CONTENT_URI, WaypointsColumns._ID + "=?", new String[]{Long.toString(waypointId)}); contentResolver.delete(WaypointsColumns.CONTENT_URI, WaypointsColumns._ID + "=?", new String[]{Long.toString(waypointId)});
} }
/**
* Gets the last waypoint for a type. Returns null if it doesn't exist.
*
* @param trackId the track id
*/
public Waypoint getLastWaypoint(long trackId) {
if (trackId < 0) {
return null;
}
String selection = WaypointsColumns.TRACKID + "=?";
String[] selectionArgs = new String[]{Long.toString(trackId)};
try (Cursor cursor = getWaypointCursor(null, selection, selectionArgs, WaypointsColumns._ID + " DESC", 1)) {
if (cursor != null && cursor.moveToFirst()) {
return createWaypoint(cursor);
}
}
return null;
}
/** /**
* Gets the next waypoint number for a type. * Gets the next waypoint number for a type.
* Returns -1 if not able to get the next waypoint number. * Returns -1 if not able to get the next waypoint number.
@@ -974,35 +942,4 @@ public class ContentProviderUtils {
void setDefaultCursorBatchSize(int defaultCursorBatchSize) { void setDefaultCursorBatchSize(int defaultCursorBatchSize) {
this.defaultCursorBatchSize = defaultCursorBatchSize; this.defaultCursorBatchSize = defaultCursorBatchSize;
} }
/**
* A cache of track points indexes.
*/
static class CachedTrackPointsIndexes {
final int idIndex;
final int longitudeIndex;
final int latitudeIndex;
final int timeIndex;
final int altitudeIndex;
final int accuracyIndex;
final int speedIndex;
final int bearingIndex;
final int sensorHeartRateIndex;
final int sensorCadenceIndex;
final int sensorPowerIndex;
CachedTrackPointsIndexes(Cursor cursor) {
idIndex = cursor.getColumnIndex(TrackPointsColumns._ID);
longitudeIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.LONGITUDE);
latitudeIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.LATITUDE);
timeIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.TIME);
altitudeIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALTITUDE);
accuracyIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.ACCURACY);
speedIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SPEED);
bearingIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.BEARING);
sensorHeartRateIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_HEARTRATE);
sensorCadenceIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_CADENCE);
sensorPowerIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_POWER);
}
}
} }
@@ -134,7 +134,6 @@ public abstract class CustomContentProvider extends ContentProvider {
case TRACKPOINTS: case TRACKPOINTS:
return TrackPointsColumns.CONTENT_TYPE; return TrackPointsColumns.CONTENT_TYPE;
case TRACKPOINTS_BY_ID: case TRACKPOINTS_BY_ID:
return TrackPointsColumns.CONTENT_ITEMTYPE;
case TRACKPOINTS_BY_TRACKID: case TRACKPOINTS_BY_TRACKID:
return TrackPointsColumns.CONTENT_ITEMTYPE; return TrackPointsColumns.CONTENT_ITEMTYPE;
case TRACKS: case TRACKS:
@@ -13,7 +13,7 @@ public class TrackPointFactory {
/** /**
* The default {@link TrackPointFactory} which creates a location each time. * The default {@link TrackPointFactory} which creates a location each time.
*/ */
public static TrackPointFactory DEFAULT_LOCATION_FACTORY = new TrackPointFactory(); public static final TrackPointFactory DEFAULT_LOCATION_FACTORY = new TrackPointFactory();
public TrackPoint createLocation() { public TrackPoint createLocation() {
return new TrackPoint(LocationManager.GPS_PROVIDER); return new TrackPoint(LocationManager.GPS_PROVIDER);
@@ -19,7 +19,7 @@ public class TrackPointIterator implements Iterator<TrackPoint>, AutoCloseable {
private final long trackId; private final long trackId;
private final boolean descending; private final boolean descending;
private final TrackPointFactory trackPointFactory; private final TrackPointFactory trackPointFactory;
private final ContentProviderUtils.CachedTrackPointsIndexes indexes; private final CachedTrackPointsIndexes indexes;
private long lastTrackPointId = -1L; private long lastTrackPointId = -1L;
private Cursor cursor; private Cursor cursor;
@@ -35,7 +35,7 @@ public class TrackPointIterator implements Iterator<TrackPoint>, AutoCloseable {
this.trackPointFactory = trackPointFactory; this.trackPointFactory = trackPointFactory;
cursor = getCursor(startTrackPointId); cursor = getCursor(startTrackPointId);
indexes = cursor != null ? new ContentProviderUtils.CachedTrackPointsIndexes(cursor) indexes = cursor != null ? new CachedTrackPointsIndexes(cursor)
: null; : null;
} }
@@ -20,7 +20,6 @@ public enum SensorState {
case CONNECTED: case CONNECTED:
return c.getString(R.string.sensor_state_connected); return c.getString(R.string.sensor_state_connected);
case DISCONNECTING: case DISCONNECTING:
return c.getString(R.string.sensor_state_disconnected);
case DISCONNECTED: case DISCONNECTED:
return c.getString(R.string.sensor_state_disconnected); return c.getString(R.string.sensor_state_disconnected);
default: default:
@@ -2,8 +2,6 @@ package de.dennisguse.opentracks.fragments;
public class ChartDistanceFragment extends ChartFragment { public class ChartDistanceFragment extends ChartFragment {
public static final String CHART_FRAGMENT_TAG = ChartDistanceFragment.class.getSimpleName();
public ChartDistanceFragment() { public ChartDistanceFragment() {
super(true); super(true);
} }
@@ -73,7 +73,7 @@ public abstract class ChartFragment extends Fragment implements TrackDataListene
// Modes of operation // Modes of operation
private boolean chartByDistance; private boolean chartByDistance;
private boolean[] chartShow = new boolean[]{true, true, true, true, true, true}; private final boolean[] chartShow = new boolean[]{true, true, true, true, true, true};
// UI elements // UI elements
private ChartView chartView; private ChartView chartView;
@@ -2,8 +2,6 @@ package de.dennisguse.opentracks.fragments;
public class ChartTimeFragment extends ChartFragment { public class ChartTimeFragment extends ChartFragment {
public static final String CHART_FRAGMENT_TAG = ChartTimeFragment.class.getSimpleName();
public ChartTimeFragment() { public ChartTimeFragment() {
super(false); super(false);
} }
@@ -39,7 +39,7 @@ public class ChooseActivityTypeDialogFragment extends DialogFragment implements
return TrackIconUtils.getAllIconValues().indexOf(iconValue); return TrackIconUtils.getAllIconValues().indexOf(iconValue);
} }
private String preselectedCategory; private final String preselectedCategory;
private ChooseActivityTypeCaller chooseActivityTypeCaller; private ChooseActivityTypeCaller chooseActivityTypeCaller;
@@ -71,7 +71,6 @@ public class ChooseActivityTypeDialogFragment extends DialogFragment implements
int position = getPosition(getContext(), preselectedCategory); int position = getPosition(getContext(), preselectedCategory);
if (position != -1) { if (position != -1) {
imageAdapter.setSelected(position); imageAdapter.setSelected(position);
imageAdapter.notifyDataSetChanged();
} }
gridView.setOnItemClickListener(this); gridView.setOnItemClickListener(this);
@@ -56,12 +56,9 @@ public class ChooseActivityTypeImageAdapter extends BaseAdapter {
return 0; return 0;
} }
public int getSelected() {
return selected;
}
public void setSelected(int position) { public void setSelected(int position) {
selected = position; selected = position;
notifyDataSetChanged();
} }
@Override @Override
@@ -37,7 +37,7 @@ public class ConfirmDeleteDialogFragment extends DialogFragment {
private static final String CONFIRM_DELETE_DIALOG_TAG = "confirmDeleteDialog"; private static final String CONFIRM_DELETE_DIALOG_TAG = "confirmDeleteDialog";
private ConfirmDeleteCaller caller; private ConfirmDeleteCaller caller;
private long[] trackIds; private final long[] trackIds;
public ConfirmDeleteDialogFragment(long[] trackIds) { public ConfirmDeleteDialogFragment(long[] trackIds) {
this.trackIds = trackIds; this.trackIds = trackIds;
@@ -38,7 +38,7 @@ import de.dennisguse.opentracks.util.DialogUtils;
public class DeleteMarkerDialogFragment extends DialogFragment { public class DeleteMarkerDialogFragment extends DialogFragment {
private static final String DELETE_MARKER_DIALOG_TAG = "deleteMarkerDialog"; private static final String DELETE_MARKER_DIALOG_TAG = "deleteMarkerDialog";
private long[] markerIds; private final long[] markerIds;
private DeleteMarkerCaller caller; private DeleteMarkerCaller caller;
@@ -82,7 +82,7 @@ public class DeleteMarkerDialogFragment extends DialogFragment {
public void run() { public void run() {
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(fragmentActivity); ContentProviderUtils contentProviderUtils = new ContentProviderUtils(fragmentActivity);
for (long markerId : markerIds) { for (long markerId : markerIds) {
contentProviderUtils.deleteWaypoint(fragmentActivity, markerId); contentProviderUtils.deleteWaypoint(markerId);
} }
caller.onDeleteMarkerDone(); caller.onDeleteMarkerDone();
} }
@@ -40,10 +40,10 @@ import de.dennisguse.opentracks.io.file.TrackFileFormat;
public class FileTypeDialogFragment extends DialogFragment { public class FileTypeDialogFragment extends DialogFragment {
private static final String FILE_TYPE_DIALOG_TAG = "fileType"; private static final String FILE_TYPE_DIALOG_TAG = "fileType";
private int titleId; private final int titleId;
private FileTypeCaller caller; private FileTypeCaller caller;
private int optionId; private final int optionId;
public FileTypeDialogFragment(int titleId, int optionId) { public FileTypeDialogFragment(int titleId, int optionId) {
this.titleId = titleId; this.titleId = titleId;
@@ -64,7 +64,7 @@ public class MarkerDetailFragment extends Fragment {
private ImageView textGradient; private ImageView textGradient;
private LinearLayout waypointInfo; private LinearLayout waypointInfo;
private Waypoint waypoint; private Waypoint waypoint;
private Runnable hideText = new Runnable() { private final Runnable hideText = new Runnable() {
@Override @Override
public void run() { public void run() {
Animation animation = AnimationUtils.loadAnimation(getActivity(), R.anim.fadeout); Animation animation = AnimationUtils.loadAnimation(getActivity(), R.anim.fadeout);
@@ -219,7 +219,7 @@ public class MarkerDetailFragment extends Fragment {
photoView.setImageResource(MarkerUtils.ICON_ID); photoView.setImageResource(MarkerUtils.ICON_ID);
} }
setName(R.id.marker_detail_waypoint_name, hasPhoto); setName(hasPhoto);
TextView category = getView().findViewById(R.id.marker_detail_waypoint_category); TextView category = getView().findViewById(R.id.marker_detail_waypoint_category);
ListItemUtils.setTextView(getActivity(), category, StringUtils.getCategory(waypoint.getCategory()), hasPhoto); ListItemUtils.setTextView(getActivity(), category, StringUtils.getCategory(waypoint.getCategory()), hasPhoto);
@@ -227,16 +227,16 @@ public class MarkerDetailFragment extends Fragment {
TextView description = getView().findViewById(R.id.marker_detail_waypoint_description); TextView description = getView().findViewById(R.id.marker_detail_waypoint_description);
ListItemUtils.setTextView(getActivity(), description, waypoint.getDescription(), hasPhoto); ListItemUtils.setTextView(getActivity(), description, waypoint.getDescription(), hasPhoto);
setLocation(R.id.marker_detail_waypoint_location, hasPhoto); setLocation(hasPhoto);
} }
private void setName(int resId, boolean addShadow) { private void setName(boolean addShadow) {
TextView textView = getView().findViewById(resId); TextView textView = getView().findViewById(R.id.marker_detail_waypoint_name);
ListItemUtils.setTextView(getActivity(), textView, waypoint.getName(), addShadow); ListItemUtils.setTextView(getActivity(), textView, waypoint.getName(), addShadow);
} }
private void setLocation(int resId, boolean addShadow) { private void setLocation(boolean addShadow) {
TextView textView = getView().findViewById(resId); TextView textView = getView().findViewById(R.id.marker_detail_waypoint_location);
Location location = waypoint.getLocation(); Location location = waypoint.getLocation();
String value; String value;
if (location == null) { if (location == null) {
@@ -65,9 +65,9 @@ public class KmlTrackWriter implements TrackWriter {
private final ContentProviderUtils contentProviderUtils; private final ContentProviderUtils contentProviderUtils;
private PrintWriter printWriter; private PrintWriter printWriter;
private List<Float> powerList = new ArrayList<>(); private final List<Float> powerList = new ArrayList<>();
private List<Float> cadenceList = new ArrayList<>(); private final List<Float> cadenceList = new ArrayList<>();
private List<Float> heartRateList = new ArrayList<>(); private final List<Float> heartRateList = new ArrayList<>();
private Location startLocation; private Location startLocation;
@@ -164,7 +164,7 @@ public class KmlTrackWriter implements TrackWriter {
if (printWriter != null && exportTrackDetail) { if (printWriter != null && exportTrackDetail) {
if (waypoint.hasPhoto() && exportPhotos) { if (waypoint.hasPhoto() && exportPhotos) {
float heading = getHeading(waypoint.getTrackId(), waypoint.getLocation()); float heading = getHeading(waypoint.getTrackId(), waypoint.getLocation());
writePhotoOverlay(waypoint.getName(), waypoint.getCategory(), waypoint.getDescription(), WAYPOINT_STYLE, waypoint.getLocation(), waypoint.getPhotoUrl(), heading); writePhotoOverlay(waypoint.getName(), waypoint.getCategory(), waypoint.getDescription(), waypoint.getLocation(), waypoint.getPhotoUrl(), heading);
} else { } else {
writePlacemark(waypoint.getName(), waypoint.getCategory(), waypoint.getDescription(), WAYPOINT_STYLE, waypoint.getLocation()); writePlacemark(waypoint.getName(), waypoint.getCategory(), waypoint.getDescription(), WAYPOINT_STYLE, waypoint.getLocation());
} }
@@ -321,16 +321,14 @@ public class KmlTrackWriter implements TrackWriter {
/** /**
* Writes a photo overlay. * Writes a photo overlay.
* * @param name the name
* @param name the name
* @param category the category * @param category the category
* @param description the description * @param description the description
* @param styleName the style name
* @param location the location * @param location the location
* @param photoUrl the photo url * @param photoUrl the photo url
* @param heading the heading * @param heading the heading
*/ */
private void writePhotoOverlay(String name, String category, String description, String styleName, Location location, String photoUrl, float heading) { private void writePhotoOverlay(String name, String category, String description, Location location, String photoUrl, float heading) {
if (location != null && exportTrackDetail) { if (location != null && exportTrackDetail) {
printWriter.println("<PhotoOverlay>"); printWriter.println("<PhotoOverlay>");
printWriter.println("<name>" + StringUtils.formatCData(name) + "</name>"); printWriter.println("<name>" + StringUtils.formatCData(name) + "</name>");
@@ -343,7 +341,7 @@ public class KmlTrackWriter implements TrackWriter {
printWriter.print("<tilt>90</tilt>"); printWriter.print("<tilt>90</tilt>");
printWriter.println("</Camera>"); printWriter.println("</Camera>");
printWriter.println("<TimeStamp><when>" + getTime(location) + "</when></TimeStamp>"); printWriter.println("<TimeStamp><when>" + getTime(location) + "</when></TimeStamp>");
printWriter.println("<styleUrl>#" + styleName + "</styleUrl>"); printWriter.println("<styleUrl>#" + KmlTrackWriter.WAYPOINT_STYLE + "</styleUrl>");
writeCategory(category); writeCategory(category);
if (exportPhotos) { if (exportPhotos) {
@@ -52,7 +52,7 @@ public class KmzTrackExporter implements TrackExporter {
private final TrackExporter fileTrackExporter; private final TrackExporter fileTrackExporter;
private final Track[] tracks; private final Track[] tracks;
private boolean exportPhotos; private final boolean exportPhotos;
/** /**
* Constructor. * Constructor.
@@ -493,7 +493,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
// TODO Why private inner class? // TODO Why private inner class?
private class TrackData { private class TrackData {
// The current track // The current track
Track track = new Track(); final Track track = new Track();
// The number of segments processed for the current track // The number of segments processed for the current track
int numberOfSegments = 0; int numberOfSegments = 0;
@@ -508,10 +508,10 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
TripStatisticsUpdater tripStatisticsUpdater; TripStatisticsUpdater tripStatisticsUpdater;
// The import time of the track. // The import time of the track.
long importTime = System.currentTimeMillis(); final long importTime = System.currentTimeMillis();
// The buffered locations // The buffered locations
Location[] bufferedLocations = new Location[MAX_BUFFERED_LOCATIONS]; final Location[] bufferedLocations = new Location[MAX_BUFFERED_LOCATIONS];
// The number of buffered locations // The number of buffered locations
int numBufferedLocations = 0; int numBufferedLocations = 0;
@@ -150,7 +150,7 @@ public class TrackRecordingService extends Service {
private boolean currentSegmentHasLocation; private boolean currentSegmentHasLocation;
private boolean isIdle; // true if idle private boolean isIdle; // true if idle
private ServiceBinder binder = new ServiceBinder(this); private ServiceBinder binder = new ServiceBinder(this);
private LocationListener locationListener = new LocationListener() { private final LocationListener locationListener = new LocationListener() {
@Override @Override
public void onLocationChanged(final Location location) { public void onLocationChanged(final Location location) {
@@ -358,7 +358,7 @@ public class TrackRecordingService extends Service {
track.setTripStatistics(trackTripStatisticsUpdater.getTripStatistics()); track.setTripStatistics(trackTripStatisticsUpdater.getTripStatistics());
contentProviderUtils.updateTrack(track); contentProviderUtils.updateTrack(track);
startRecording(true); startRecording();
return trackId; return trackId;
} }
@@ -382,7 +382,7 @@ public class TrackRecordingService extends Service {
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.e(TAG, "RuntimeException", e); Log.e(TAG, "RuntimeException", e);
} }
startRecording(true); startRecording();
} }
/** /**
@@ -408,15 +408,13 @@ public class TrackRecordingService extends Service {
insertLocation(track, resume, null); insertLocation(track, resume, null);
} }
startRecording(false); startRecording();
} }
/** /**
* Common code for starting a new track, resuming a track, or restarting after phone reboot. * Common code for starting a new track, resuming a track, or restarting after phone reboot.
*
* @param trackStarted true if track is started, false if track is resumed
*/ */
private void startRecording(boolean trackStarted) { private void startRecording() {
// Update instance variables // Update instance variables
remoteSensorManager = new BluetoothRemoteSensorManager(this); remoteSensorManager = new BluetoothRemoteSensorManager(this);
remoteSensorManager.start(); remoteSensorManager.start();
@@ -686,7 +684,7 @@ public class TrackRecordingService extends Service {
} }
try { try {
Uri uri = contentProviderUtils.insertTrackPoint(location, track.getId()); contentProviderUtils.insertTrackPoint(location, track.getId());
trackTripStatisticsUpdater.addLocation(location, recordingDistanceInterval); trackTripStatisticsUpdater.addLocation(location, recordingDistanceInterval);
updateRecordingTrack(track, LocationUtils.isValidLocation(location)); updateRecordingTrack(track, LocationUtils.isValidLocation(location));
} catch (SQLiteException e) { } catch (SQLiteException e) {
@@ -24,9 +24,9 @@ class TrackRecordingServiceNotificationManager {
private final static String CHANNEL_ID = TrackRecordingServiceNotificationManager.class.getSimpleName(); private final static String CHANNEL_ID = TrackRecordingServiceNotificationManager.class.getSimpleName();
private NotificationCompat.Builder notificationBuilder; private final NotificationCompat.Builder notificationBuilder;
private NotificationManager notificationManager; private final NotificationManager notificationManager;
private boolean previousLocationWasAccurate = true; private boolean previousLocationWasAccurate = true;
@@ -57,9 +57,9 @@ public class BluetoothConnectionManager {
private SensorState sensorState; private SensorState sensorState;
private BluetoothGatt bluetoothGatt; private BluetoothGatt bluetoothGatt;
private BluetoothDevice bluetoothDevice; private final BluetoothDevice bluetoothDevice;
private BluetoothGattCallback connectCallback = new BluetoothGattCallback() { private final BluetoothGattCallback connectCallback = new BluetoothGattCallback() {
@Override @Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
switch (newState) { switch (newState) {
@@ -61,11 +61,7 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
stop = false; stop = false;
break; break;
case AudioManager.AUDIOFOCUS_LOSS: case AudioManager.AUDIOFOCUS_LOSS:
stop = true;
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
stop = true;
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
stop = true; stop = true;
break; break;
@@ -74,7 +74,7 @@ public class BluetoothLeAdapter extends BaseAdapter {
public class Device { public class Device {
private String name; private String name;
private String address; private final String address;
public Device(String name, String address) { public Device(String name, String address) {
this.name = name; this.name = name;
@@ -88,10 +88,10 @@ public class BluetoothLePreference extends DialogPreference {
public static class BluetoothLePreferenceDialog extends PreferenceDialogFragmentCompat { public static class BluetoothLePreferenceDialog extends PreferenceDialogFragmentCompat {
private int selectedEntryIndex; private int selectedEntryIndex;
private BluetoothLeAdapter listAdapter = new BluetoothLeAdapter(); private final BluetoothLeAdapter listAdapter = new BluetoothLeAdapter();
private BluetoothLeScanner scanner = null; private BluetoothLeScanner scanner = null;
private ScanCallback scanCallback = new ScanCallback() { private final ScanCallback scanCallback = new ScanCallback() {
@Override @Override
public void onScanResult(int callbackType, ScanResult result) { public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result); super.onScanResult(callbackType, result);
@@ -80,19 +80,6 @@ public class FileUtils {
return buildUniqueFileName(directory, fileBaseName, extension, 0); return buildUniqueFileName(directory, fileBaseName, extension, 0);
} }
/**
* Gets the name from a file name, without the extension.
*
* @param fileName the file name
*/
public static String getName(String fileName) {
int index = fileName.lastIndexOf('.');
if (index == -1) {
return fileName;
}
return fileName.substring(0, index);
}
/** /**
* Gets the extension from a file name. * Gets the extension from a file name.
* Returns null if there is no extension. * Returns null if there is no extension.
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.Editor;
import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.R;
@@ -44,7 +45,7 @@ public class PreferencesUtils {
public static final long RECORDING_TRACK_ID_DEFAULT = -1L; public static final long RECORDING_TRACK_ID_DEFAULT = -1L;
public static long getRecordingTrackId(Context context) { public static long getRecordingTrackId(Context context) {
return PreferencesUtils.getLong(context, R.string.recording_track_id_key, RECORDING_TRACK_ID_DEFAULT); return PreferencesUtils.getLong(context);
} }
public static String getDefaultActivity(Context context) { public static String getDefaultActivity(Context context) {
@@ -134,6 +135,7 @@ public class PreferencesUtils {
* @param keyId the key id * @param keyId the key id
* @param value the value * @param value the value
*/ */
@VisibleForTesting
public static void setInt(Context context, int keyId, int value) { public static void setInt(Context context, int keyId, int value) {
SharedPreferences sharedPreferences = getSharedPreferences(context); SharedPreferences sharedPreferences = getSharedPreferences(context);
Editor editor = sharedPreferences.edit(); Editor editor = sharedPreferences.edit();
@@ -143,13 +145,12 @@ public class PreferencesUtils {
/** /**
* Gets a long preference value. * Gets a long preference value.
*
* @param context the context * @param context the context
* @param keyId the key id *
*/ */
private static long getLong(Context context, int keyId, long defaultValue) { private static long getLong(Context context) {
SharedPreferences sharedPreferences = getSharedPreferences(context); SharedPreferences sharedPreferences = getSharedPreferences(context);
return sharedPreferences.getLong(getKey(context, keyId), defaultValue); return sharedPreferences.getLong(getKey(context, R.string.recording_track_id_key), PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
} }
/** /**
@@ -29,7 +29,7 @@ import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
*/ */
public class TrackUtils { public class TrackUtils {
public static String TRACK_SORT_ORDER = TracksColumns.STARTTIME + " DESC"; public static final String TRACK_SORT_ORDER = TracksColumns.STARTTIME + " DESC";
private TrackUtils() { private TrackUtils() {
} }