mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-11-05 07:34:45 +01:00
Autoformatted all classes (non-testing).
This commit is contained in:
@@ -20,7 +20,6 @@ import android.location.Location;
|
|||||||
|
|
||||||
import com.google.android.apps.mytracks.content.SensorDataSetLocation;
|
import com.google.android.apps.mytracks.content.SensorDataSetLocation;
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.content.sensor.Sensor.SensorDataSet;
|
|
||||||
import com.google.android.apps.mytracks.content.sensor.SensorDataSet;
|
import com.google.android.apps.mytracks.content.sensor.SensorDataSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,13 +30,13 @@ import com.google.android.apps.mytracks.content.sensor.SensorDataSet;
|
|||||||
*/
|
*/
|
||||||
public class TrackStubUtils {
|
public class TrackStubUtils {
|
||||||
|
|
||||||
|
public static final double INITIAL_ALTITUDE = 22;
|
||||||
|
public static final long INITIAL_TIME = 1000L;
|
||||||
static final String LOCATION_PROVIDER = "gps";
|
static final String LOCATION_PROVIDER = "gps";
|
||||||
static final double INITIAL_LATITUDE = 22;
|
static final double INITIAL_LATITUDE = 22;
|
||||||
static final double INITIAL_LONGITUDE = 22;
|
static final double INITIAL_LONGITUDE = 22;
|
||||||
public static final double INITIAL_ALTITUDE = 22;
|
|
||||||
static final float INITIAL_ACCURACY = 5;
|
static final float INITIAL_ACCURACY = 5;
|
||||||
static final float INITIAL_SPEED = 10;
|
static final float INITIAL_SPEED = 10;
|
||||||
public static final long INITIAL_TIME = 1000L;
|
|
||||||
static final float INITIAL_BEARING = 3.0f;
|
static final float INITIAL_BEARING = 3.0f;
|
||||||
// Used to change the value of latitude, longitude, and altitude.
|
// Used to change the value of latitude, longitude, and altitude.
|
||||||
static final double DIFFERENCE = 0.01;
|
static final double DIFFERENCE = 0.01;
|
||||||
|
|||||||
+3
-3
@@ -50,13 +50,12 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
*/
|
*/
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class CustomContentProviderUtilsImplTest {
|
public class CustomContentProviderUtilsImplTest {
|
||||||
private Context context;
|
|
||||||
private ContentProviderUtils providerUtils;
|
|
||||||
|
|
||||||
private static final String NAME_PREFIX = "test name";
|
private static final String NAME_PREFIX = "test name";
|
||||||
private static final String MOCK_DESC = "Mock Next Waypoint Desc!";
|
private static final String MOCK_DESC = "Mock Next Waypoint Desc!";
|
||||||
private static final String TEST_DESC = "Test Desc!";
|
private static final String TEST_DESC = "Test Desc!";
|
||||||
private static final String TEST_DESC_NEW = "Test Desc new!";
|
private static final String TEST_DESC_NEW = "Test Desc new!";
|
||||||
|
private Context context;
|
||||||
|
private ContentProviderUtils providerUtils;
|
||||||
private double INITIAL_LATITUDE = 37.0;
|
private double INITIAL_LATITUDE = 37.0;
|
||||||
private double INITIAL_LONGITUDE = -57.0;
|
private double INITIAL_LONGITUDE = -57.0;
|
||||||
private double ALTITUDE_INTERVAL = 2.5;
|
private double ALTITUDE_INTERVAL = 2.5;
|
||||||
@@ -872,6 +871,7 @@ public class CustomContentProviderUtilsImplTest {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a location.
|
* Creates a location.
|
||||||
|
*
|
||||||
* @param i the index to set the value of location.
|
* @param i the index to set the value of location.
|
||||||
* @return created location
|
* @return created location
|
||||||
*/
|
*/
|
||||||
|
|||||||
+88
-89
@@ -605,6 +605,94 @@ public class TrackDataHubTest {
|
|||||||
AndroidMock.reset(contentProviderUtils, dataSource, trackDataListener1, trackDataListener2);
|
AndroidMock.reset(contentProviderUtils, dataSource, trackDataListener1, trackDataListener2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the method {@link TrackDataHub#start()}.
|
||||||
|
*/
|
||||||
|
public void testRegisterTracksTableListener() {
|
||||||
|
Capture<ContentObserver> observerCapture = new Capture<ContentObserver>();
|
||||||
|
dataSource.registerContentObserver(eq(TracksColumns.CONTENT_URI), capture(observerCapture));
|
||||||
|
Track track = TrackStubUtils.createTrack(1);
|
||||||
|
expect(contentProviderUtils.getTrack(capture(new Capture<Long>()))).andReturn(track);
|
||||||
|
// Make the track id is unique.
|
||||||
|
PreferencesUtils.setLong(context, R.string.recording_track_id_key, System.currentTimeMillis());
|
||||||
|
trackDataListener1.onTrackUpdated(track);
|
||||||
|
replay();
|
||||||
|
trackDataHub.start();
|
||||||
|
trackDataHub.registerTrackDataListener(
|
||||||
|
trackDataListener1, EnumSet.of(TrackDataType.TRACKS_TABLE));
|
||||||
|
verifyAndReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the method {@link TrackDataHub#start()}.
|
||||||
|
*/
|
||||||
|
public void testRegisterWaypointsTableListener() {
|
||||||
|
Capture<ContentObserver> observerCapture = new Capture<ContentObserver>();
|
||||||
|
dataSource.registerContentObserver(eq(WaypointsColumns.CONTENT_URI), capture(observerCapture));
|
||||||
|
expect(contentProviderUtils.getWaypointCursor(
|
||||||
|
capture(new Capture<Long>()), capture(new Capture<Long>()),
|
||||||
|
capture(new Capture<Integer>()))).andReturn(null);
|
||||||
|
trackDataListener1.clearWaypoints();
|
||||||
|
trackDataListener1.onNewWaypointsDone();
|
||||||
|
replay();
|
||||||
|
trackDataHub.start();
|
||||||
|
trackDataHub.registerTrackDataListener(
|
||||||
|
trackDataListener1, EnumSet.of(TrackDataType.WAYPOINTS_TABLE));
|
||||||
|
verifyAndReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the method {@link TrackDataHub#notifyPreferenceChanged(String)} when
|
||||||
|
* the key is R.string.min_required_accuracy_key.
|
||||||
|
*/
|
||||||
|
public void testNotifyPreferenceChanged_minRequiredAccuracy() {
|
||||||
|
int value = 1;
|
||||||
|
PreferencesUtils.setInt(context, R.string.recording_gps_accuracy_key, value);
|
||||||
|
trackDataHub.notifyPreferenceChanged(PreferencesUtils
|
||||||
|
.getKey(context, R.string.recording_gps_accuracy_key));
|
||||||
|
assertEquals(value, trackDataHub.getRecordingGpsAccuracy());
|
||||||
|
PreferencesUtils.setInt(context, R.string.recording_gps_accuracy_key, value + 1);
|
||||||
|
trackDataHub.notifyPreferenceChanged(PreferencesUtils
|
||||||
|
.getKey(context, R.string.recording_gps_accuracy_key));
|
||||||
|
assertEquals(value + 1, trackDataHub.getRecordingGpsAccuracy());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the method {@link TrackDataHub#notifyPreferenceChanged(String)} when
|
||||||
|
* the key is R.string.metric_units_key.
|
||||||
|
*/
|
||||||
|
public void testNotifyPreferenceChanged_metricUnitsNoNotify() {
|
||||||
|
String imperialUnits = context.getString(R.string.stats_units_imperial);
|
||||||
|
|
||||||
|
PreferencesUtils.setString(context, R.string.stats_units_key, imperialUnits);
|
||||||
|
trackDataHub.notifyPreferenceChanged(
|
||||||
|
PreferencesUtils.getKey(context, R.string.stats_units_key));
|
||||||
|
assertEquals(false, trackDataHub.isMetricUnits());
|
||||||
|
PreferencesUtils.setString(
|
||||||
|
context, R.string.stats_units_key, PreferencesUtils.STATS_UNITS_DEFAULT);
|
||||||
|
trackDataHub.notifyPreferenceChanged(
|
||||||
|
PreferencesUtils.getKey(context, R.string.stats_units_key));
|
||||||
|
assertEquals(true, trackDataHub.isMetricUnits());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the method {@link TrackDataHub#notifyPreferenceChanged(String)} when
|
||||||
|
* the key is R.string.metric_units_key.
|
||||||
|
*/
|
||||||
|
public void testNotifyPreferenceChanged_reportSpeedNoNotify() {
|
||||||
|
String value = context.getString(R.string.stats_rate_pace);
|
||||||
|
PreferencesUtils.setString(context, R.string.stats_rate_key, value);
|
||||||
|
trackDataHub.notifyPreferenceChanged(PreferencesUtils
|
||||||
|
.getKey(context, R.string.stats_rate_key));
|
||||||
|
assertEquals(false, trackDataHub.isReportSpeed());
|
||||||
|
|
||||||
|
value = context.getString(R.string.stats_rate_speed);
|
||||||
|
PreferencesUtils.setString(context, R.string.stats_rate_key, value);
|
||||||
|
trackDataHub.notifyPreferenceChanged(PreferencesUtils
|
||||||
|
.getKey(context, R.string.stats_rate_key));
|
||||||
|
assertEquals(true, trackDataHub.isReportSpeed());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fixed size cursor answer.
|
* Fixed size cursor answer.
|
||||||
*
|
*
|
||||||
@@ -717,93 +805,4 @@ public class TrackDataHubTest {
|
|||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link TrackDataHub#start()}.
|
|
||||||
*/
|
|
||||||
public void testRegisterTracksTableListener() {
|
|
||||||
Capture<ContentObserver> observerCapture = new Capture<ContentObserver>();
|
|
||||||
dataSource.registerContentObserver(eq(TracksColumns.CONTENT_URI), capture(observerCapture));
|
|
||||||
Track track = TrackStubUtils.createTrack(1);
|
|
||||||
expect(contentProviderUtils.getTrack(capture(new Capture<Long>()))).andReturn(track);
|
|
||||||
// Make the track id is unique.
|
|
||||||
PreferencesUtils.setLong(context, R.string.recording_track_id_key, System.currentTimeMillis());
|
|
||||||
trackDataListener1.onTrackUpdated(track);
|
|
||||||
replay();
|
|
||||||
trackDataHub.start();
|
|
||||||
trackDataHub.registerTrackDataListener(
|
|
||||||
trackDataListener1, EnumSet.of(TrackDataType.TRACKS_TABLE));
|
|
||||||
verifyAndReset();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link TrackDataHub#start()}.
|
|
||||||
*/
|
|
||||||
public void testRegisterWaypointsTableListener() {
|
|
||||||
Capture<ContentObserver> observerCapture = new Capture<ContentObserver>();
|
|
||||||
dataSource.registerContentObserver(eq(WaypointsColumns.CONTENT_URI), capture(observerCapture));
|
|
||||||
expect(contentProviderUtils.getWaypointCursor(
|
|
||||||
capture(new Capture<Long>()), capture(new Capture<Long>()),
|
|
||||||
capture(new Capture<Integer>()))).andReturn(null);
|
|
||||||
trackDataListener1.clearWaypoints();
|
|
||||||
trackDataListener1.onNewWaypointsDone();
|
|
||||||
replay();
|
|
||||||
trackDataHub.start();
|
|
||||||
trackDataHub.registerTrackDataListener(
|
|
||||||
trackDataListener1, EnumSet.of(TrackDataType.WAYPOINTS_TABLE));
|
|
||||||
verifyAndReset();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link TrackDataHub#notifyPreferenceChanged(String)} when
|
|
||||||
* the key is R.string.min_required_accuracy_key.
|
|
||||||
*/
|
|
||||||
public void testNotifyPreferenceChanged_minRequiredAccuracy() {
|
|
||||||
int value = 1;
|
|
||||||
PreferencesUtils.setInt(context, R.string.recording_gps_accuracy_key, value);
|
|
||||||
trackDataHub.notifyPreferenceChanged(PreferencesUtils
|
|
||||||
.getKey(context, R.string.recording_gps_accuracy_key));
|
|
||||||
assertEquals(value, trackDataHub.getRecordingGpsAccuracy());
|
|
||||||
PreferencesUtils.setInt(context, R.string.recording_gps_accuracy_key, value + 1);
|
|
||||||
trackDataHub.notifyPreferenceChanged(PreferencesUtils
|
|
||||||
.getKey(context, R.string.recording_gps_accuracy_key));
|
|
||||||
assertEquals(value + 1, trackDataHub.getRecordingGpsAccuracy());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link TrackDataHub#notifyPreferenceChanged(String)} when
|
|
||||||
* the key is R.string.metric_units_key.
|
|
||||||
*/
|
|
||||||
public void testNotifyPreferenceChanged_metricUnitsNoNotify() {
|
|
||||||
String imperialUnits = context.getString(R.string.stats_units_imperial);
|
|
||||||
|
|
||||||
PreferencesUtils.setString(context, R.string.stats_units_key, imperialUnits);
|
|
||||||
trackDataHub.notifyPreferenceChanged(
|
|
||||||
PreferencesUtils.getKey(context, R.string.stats_units_key));
|
|
||||||
assertEquals(false, trackDataHub.isMetricUnits());
|
|
||||||
PreferencesUtils.setString(
|
|
||||||
context, R.string.stats_units_key, PreferencesUtils.STATS_UNITS_DEFAULT);
|
|
||||||
trackDataHub.notifyPreferenceChanged(
|
|
||||||
PreferencesUtils.getKey(context, R.string.stats_units_key));
|
|
||||||
assertEquals(true, trackDataHub.isMetricUnits());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link TrackDataHub#notifyPreferenceChanged(String)} when
|
|
||||||
* the key is R.string.metric_units_key.
|
|
||||||
*/
|
|
||||||
public void testNotifyPreferenceChanged_reportSpeedNoNotify() {
|
|
||||||
String value = context.getString(R.string.stats_rate_pace);
|
|
||||||
PreferencesUtils.setString(context, R.string.stats_rate_key, value);
|
|
||||||
trackDataHub.notifyPreferenceChanged(PreferencesUtils
|
|
||||||
.getKey(context, R.string.stats_rate_key));
|
|
||||||
assertEquals(false, trackDataHub.isReportSpeed());
|
|
||||||
|
|
||||||
value = context.getString(R.string.stats_rate_speed);
|
|
||||||
PreferencesUtils.setString(context, R.string.stats_rate_key, value);
|
|
||||||
trackDataHub.notifyPreferenceChanged(PreferencesUtils
|
|
||||||
.getKey(context, R.string.stats_rate_key));
|
|
||||||
assertEquals(true, trackDataHub.isReportSpeed());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-22
@@ -16,8 +16,11 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.io.file.importer;
|
package com.google.android.apps.mytracks.io.file.importer;
|
||||||
|
|
||||||
import static com.google.android.testing.mocking.AndroidMock.eq;
|
import android.content.ContentUris;
|
||||||
import static com.google.android.testing.mocking.AndroidMock.expect;
|
import android.location.Location;
|
||||||
|
import android.location.LocationManager;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils.Factory;
|
import com.google.android.apps.mytracks.content.ContentProviderUtils.Factory;
|
||||||
@@ -29,17 +32,14 @@ import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory;
|
|||||||
import com.google.android.testing.mocking.AndroidMock;
|
import com.google.android.testing.mocking.AndroidMock;
|
||||||
import com.google.android.testing.mocking.UsesMocks;
|
import com.google.android.testing.mocking.UsesMocks;
|
||||||
|
|
||||||
import android.content.ContentUris;
|
import org.easymock.Capture;
|
||||||
import android.location.Location;
|
|
||||||
import android.location.LocationManager;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.test.AndroidTestCase;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.SimpleTimeZone;
|
import java.util.SimpleTimeZone;
|
||||||
|
|
||||||
import org.easymock.Capture;
|
import static com.google.android.testing.mocking.AndroidMock.eq;
|
||||||
|
import static com.google.android.testing.mocking.AndroidMock.expect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class for testing file track importers.
|
* Abstract class for testing file track importers.
|
||||||
@@ -67,6 +67,18 @@ public class AbstractTestFileTrackImporter extends AndroidTestCase {
|
|||||||
"yyyy-MM-dd'T'hh:mm:ss'Z'", Locale.US);
|
"yyyy-MM-dd'T'hh:mm:ss'Z'", Locale.US);
|
||||||
protected static final SimpleDateFormat DATE_FORMAT_1 = new SimpleDateFormat(
|
protected static final SimpleDateFormat DATE_FORMAT_1 = new SimpleDateFormat(
|
||||||
"yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US);
|
"yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US);
|
||||||
|
protected static final long TRACK_ID_0 = 1;
|
||||||
|
protected static final long TRACK_ID_1 = 2;
|
||||||
|
protected static final long TRACK_POINT_ID_0 = 1;
|
||||||
|
protected static final long TRACK_POINT_ID_1 = 2;
|
||||||
|
protected static final long TRACK_POINT_ID_3 = 4;
|
||||||
|
protected static final long WAYPOINT_ID_0 = 1;
|
||||||
|
protected static final Uri TRACK_ID_0_URI = ContentUris.appendId(
|
||||||
|
TracksColumns.CONTENT_URI.buildUpon(), TRACK_ID_0).build();
|
||||||
|
protected static final Uri TRACK_ID_1_URI = ContentUris.appendId(
|
||||||
|
TracksColumns.CONTENT_URI.buildUpon(), TRACK_ID_1).build();
|
||||||
|
protected static final Uri WAYPOINT_ID_O_URI = ContentUris.appendId(
|
||||||
|
WaypointsColumns.CONTENT_URI.buildUpon(), WAYPOINT_ID_0).build();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
/*
|
/*
|
||||||
@@ -78,20 +90,6 @@ public class AbstractTestFileTrackImporter extends AndroidTestCase {
|
|||||||
DATE_FORMAT_1.setTimeZone(utc);
|
DATE_FORMAT_1.setTimeZone(utc);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static final long TRACK_ID_0 = 1;
|
|
||||||
protected static final long TRACK_ID_1 = 2;
|
|
||||||
protected static final long TRACK_POINT_ID_0 = 1;
|
|
||||||
protected static final long TRACK_POINT_ID_1 = 2;
|
|
||||||
protected static final long TRACK_POINT_ID_3 = 4;
|
|
||||||
protected static final long WAYPOINT_ID_0 = 1;
|
|
||||||
|
|
||||||
protected static final Uri TRACK_ID_0_URI = ContentUris.appendId(
|
|
||||||
TracksColumns.CONTENT_URI.buildUpon(), TRACK_ID_0).build();
|
|
||||||
protected static final Uri TRACK_ID_1_URI = ContentUris.appendId(
|
|
||||||
TracksColumns.CONTENT_URI.buildUpon(), TRACK_ID_1).build();
|
|
||||||
protected static final Uri WAYPOINT_ID_O_URI = ContentUris.appendId(
|
|
||||||
WaypointsColumns.CONTENT_URI.buildUpon(), WAYPOINT_ID_0).build();
|
|
||||||
|
|
||||||
protected ContentProviderUtils contentProviderUtils;
|
protected ContentProviderUtils contentProviderUtils;
|
||||||
|
|
||||||
private Factory oldMyTracksProviderUtilsFactory;
|
private Factory oldMyTracksProviderUtilsFactory;
|
||||||
|
|||||||
+28
-29
@@ -16,20 +16,20 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.io.file.importer;
|
package com.google.android.apps.mytracks.io.file.importer;
|
||||||
|
|
||||||
import static com.google.android.testing.mocking.AndroidMock.eq;
|
import android.location.Location;
|
||||||
import static com.google.android.testing.mocking.AndroidMock.expect;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
import com.google.android.testing.mocking.AndroidMock;
|
import com.google.android.testing.mocking.AndroidMock;
|
||||||
|
|
||||||
import android.location.Location;
|
import org.easymock.Capture;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import org.easymock.Capture;
|
import static com.google.android.testing.mocking.AndroidMock.eq;
|
||||||
|
import static com.google.android.testing.mocking.AndroidMock.expect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link GpxFileTrackImporter}.
|
* Tests for {@link GpxFileTrackImporter}.
|
||||||
@@ -38,6 +38,30 @@ import org.easymock.Capture;
|
|||||||
*/
|
*/
|
||||||
public class GpxFileTrackImporterTest extends AbstractTestFileTrackImporter {
|
public class GpxFileTrackImporterTest extends AbstractTestFileTrackImporter {
|
||||||
|
|
||||||
|
private static final String VALID_ONE_TRACK_ONE_SEGMENT_GPX = "<gpx><trk>"
|
||||||
|
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<trkseg>"
|
||||||
|
+ getTrackPoint(0, TRACK_TIME_0) + getTrackPoint(1, TRACK_TIME_1) + "</trkseg></trk></gpx>";
|
||||||
|
private static final String VALID_ONE_TRACK_TWO_SEGMENTS_GPX = "<gpx><trk>"
|
||||||
|
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<trkseg>"
|
||||||
|
+ getTrackPoint(0, TRACK_TIME_0) + getTrackPoint(1, TRACK_TIME_1) + "</trkseg><trkseg>"
|
||||||
|
+ getTrackPoint(2, TRACK_TIME_2) + getTrackPoint(3, TRACK_TIME_3) + "</trkseg></trk></gpx>";
|
||||||
|
private static final String VALID_ONE_TRACK_TWO_SEGMENTS_NO_TIME_GPX = "<gpx><trk>"
|
||||||
|
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<trkseg>"
|
||||||
|
+ getTrackPoint(0, null) + getTrackPoint(1, null) + "</trkseg><trkseg>"
|
||||||
|
+ getTrackPoint(2, null) + getTrackPoint(3, null) + "</trkseg></trk></gpx>";
|
||||||
|
private static final String INVALID_XML_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.substring(
|
||||||
|
0, VALID_ONE_TRACK_ONE_SEGMENT_GPX.length() - 50);
|
||||||
|
private static final String INVALID_LOCATION_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.replaceAll(
|
||||||
|
Double.toString(TRACK_LATITUDE), "1000.0");
|
||||||
|
private static final String INVALID_TIME_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.replaceAll(
|
||||||
|
TRACK_TIME_0, "invalid");
|
||||||
|
private static final String INVALID_ALTITUDE_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.replaceAll(
|
||||||
|
Double.toString(TRACK_ELEVATION), "invalid");
|
||||||
|
private static final String INVALID_LATITUDE_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.replaceAll(
|
||||||
|
Double.toString(TRACK_LATITUDE), "invalid");
|
||||||
|
private static final String INVALID_LONGITUDE_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.replaceAll(
|
||||||
|
Double.toString(TRACK_LONGITUDE), "invalid");
|
||||||
|
|
||||||
private static String getNameAndDescription(String name, String description) {
|
private static String getNameAndDescription(String name, String description) {
|
||||||
return "<name><![CDATA[" + name + "]]></name>" + "<desc><![CDATA[" + description + "]]></desc>";
|
return "<name><![CDATA[" + name + "]]></name>" + "<desc><![CDATA[" + description + "]]></desc>";
|
||||||
}
|
}
|
||||||
@@ -56,31 +80,6 @@ public class GpxFileTrackImporterTest extends AbstractTestFileTrackImporter {
|
|||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String VALID_ONE_TRACK_ONE_SEGMENT_GPX = "<gpx><trk>"
|
|
||||||
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<trkseg>"
|
|
||||||
+ getTrackPoint(0, TRACK_TIME_0) + getTrackPoint(1, TRACK_TIME_1) + "</trkseg></trk></gpx>";
|
|
||||||
private static final String VALID_ONE_TRACK_TWO_SEGMENTS_GPX = "<gpx><trk>"
|
|
||||||
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<trkseg>"
|
|
||||||
+ getTrackPoint(0, TRACK_TIME_0) + getTrackPoint(1, TRACK_TIME_1) + "</trkseg><trkseg>"
|
|
||||||
+ getTrackPoint(2, TRACK_TIME_2) + getTrackPoint(3, TRACK_TIME_3) + "</trkseg></trk></gpx>";
|
|
||||||
private static final String VALID_ONE_TRACK_TWO_SEGMENTS_NO_TIME_GPX = "<gpx><trk>"
|
|
||||||
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<trkseg>"
|
|
||||||
+ getTrackPoint(0, null) + getTrackPoint(1, null) + "</trkseg><trkseg>"
|
|
||||||
+ getTrackPoint(2, null) + getTrackPoint(3, null) + "</trkseg></trk></gpx>";
|
|
||||||
|
|
||||||
private static final String INVALID_XML_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.substring(
|
|
||||||
0, VALID_ONE_TRACK_ONE_SEGMENT_GPX.length() - 50);
|
|
||||||
private static final String INVALID_LOCATION_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.replaceAll(
|
|
||||||
Double.toString(TRACK_LATITUDE), "1000.0");
|
|
||||||
private static final String INVALID_TIME_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.replaceAll(
|
|
||||||
TRACK_TIME_0, "invalid");
|
|
||||||
private static final String INVALID_ALTITUDE_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.replaceAll(
|
|
||||||
Double.toString(TRACK_ELEVATION), "invalid");
|
|
||||||
private static final String INVALID_LATITUDE_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.replaceAll(
|
|
||||||
Double.toString(TRACK_LATITUDE), "invalid");
|
|
||||||
private static final String INVALID_LONGITUDE_GPX = VALID_ONE_TRACK_ONE_SEGMENT_GPX.replaceAll(
|
|
||||||
Double.toString(TRACK_LONGITUDE), "invalid");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests one track with one segment.
|
* Tests one track with one segment.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+16
-16
@@ -16,20 +16,20 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.io.file.importer;
|
package com.google.android.apps.mytracks.io.file.importer;
|
||||||
|
|
||||||
import static com.google.android.testing.mocking.AndroidMock.eq;
|
import android.location.Location;
|
||||||
import static com.google.android.testing.mocking.AndroidMock.expect;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
import com.google.android.testing.mocking.AndroidMock;
|
import com.google.android.testing.mocking.AndroidMock;
|
||||||
|
|
||||||
import android.location.Location;
|
import org.easymock.Capture;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import org.easymock.Capture;
|
import static com.google.android.testing.mocking.AndroidMock.eq;
|
||||||
|
import static com.google.android.testing.mocking.AndroidMock.expect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link KmlFileTrackImporter}.
|
* Tests for {@link KmlFileTrackImporter}.
|
||||||
@@ -38,6 +38,18 @@ import org.easymock.Capture;
|
|||||||
*/
|
*/
|
||||||
public class KmlFileTrackImporterTest extends AbstractTestFileTrackImporter {
|
public class KmlFileTrackImporterTest extends AbstractTestFileTrackImporter {
|
||||||
|
|
||||||
|
private static final String VALID_ONE_TRACK_ONE_SEGMENT_GPX =
|
||||||
|
"<kml xmlns:gx=\"http://www.google.com/kml/ext/2.2\"><Placemark>"
|
||||||
|
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<gx:MultiTrack><gx:Track>"
|
||||||
|
+ getTrackPoint(0, TRACK_TIME_0) + getTrackPoint(1, TRACK_TIME_1)
|
||||||
|
+ "</gx:Track></gx:MultiTrack></Placemark></kml>";
|
||||||
|
private static final String VALID_ONE_TRACK_TWO_SEGMENTS_GPX =
|
||||||
|
"<kml xmlns:gx=\"http://www.google.com/kml/ext/2.2\"><Placemark>"
|
||||||
|
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<gx:MultiTrack><gx:Track>"
|
||||||
|
+ getTrackPoint(0, TRACK_TIME_0) + getTrackPoint(1, TRACK_TIME_1) + "</gx:Track><gx:Track>"
|
||||||
|
+ getTrackPoint(2, TRACK_TIME_2) + getTrackPoint(3, TRACK_TIME_3)
|
||||||
|
+ "</gx:Track></gx:MultiTrack></Placemark></kml>";
|
||||||
|
|
||||||
private static String getNameAndDescription(String name, String description) {
|
private static String getNameAndDescription(String name, String description) {
|
||||||
return "<name><![CDATA[" + name + "]]></name><description><![CDATA[" + description
|
return "<name><![CDATA[" + name + "]]></name><description><![CDATA[" + description
|
||||||
+ "]]></description>";
|
+ "]]></description>";
|
||||||
@@ -53,18 +65,6 @@ public class KmlFileTrackImporterTest extends AbstractTestFileTrackImporter {
|
|||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String VALID_ONE_TRACK_ONE_SEGMENT_GPX =
|
|
||||||
"<kml xmlns:gx=\"http://www.google.com/kml/ext/2.2\"><Placemark>"
|
|
||||||
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<gx:MultiTrack><gx:Track>"
|
|
||||||
+ getTrackPoint(0, TRACK_TIME_0) + getTrackPoint(1, TRACK_TIME_1)
|
|
||||||
+ "</gx:Track></gx:MultiTrack></Placemark></kml>";
|
|
||||||
private static final String VALID_ONE_TRACK_TWO_SEGMENTS_GPX =
|
|
||||||
"<kml xmlns:gx=\"http://www.google.com/kml/ext/2.2\"><Placemark>"
|
|
||||||
+ getNameAndDescription(TRACK_NAME_0, TRACK_DESCRIPTION_0) + "<gx:MultiTrack><gx:Track>"
|
|
||||||
+ getTrackPoint(0, TRACK_TIME_0) + getTrackPoint(1, TRACK_TIME_1) + "</gx:Track><gx:Track>"
|
|
||||||
+ getTrackPoint(2, TRACK_TIME_2) + getTrackPoint(3, TRACK_TIME_3)
|
|
||||||
+ "</gx:Track></gx:MultiTrack></Placemark></kml>";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests one track with one segment.
|
* Tests one track with one segment.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+9
-9
@@ -16,14 +16,14 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.io.file.importer;
|
package com.google.android.apps.mytracks.io.file.importer;
|
||||||
|
|
||||||
import com.google.android.testing.mocking.AndroidMock;
|
|
||||||
|
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import com.google.android.testing.mocking.AndroidMock;
|
||||||
|
|
||||||
import org.easymock.IArgumentMatcher;
|
import org.easymock.IArgumentMatcher;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locations matcher. Workaround because of capture bug 2617107 in easymock:
|
* Locations matcher. Workaround because of capture bug 2617107 in easymock:
|
||||||
* http://sourceforge.net/tracker/?func=detail&aid=2617107&group_id=82958&atid=567837
|
* http://sourceforge.net/tracker/?func=detail&aid=2617107&group_id=82958&atid=567837
|
||||||
@@ -32,6 +32,12 @@ import org.easymock.IArgumentMatcher;
|
|||||||
*/
|
*/
|
||||||
public class LocationsMatcher implements IArgumentMatcher {
|
public class LocationsMatcher implements IArgumentMatcher {
|
||||||
|
|
||||||
|
private final Location[] expectedLocations;
|
||||||
|
|
||||||
|
private LocationsMatcher(Location[] expected) {
|
||||||
|
this.expectedLocations = expected;
|
||||||
|
}
|
||||||
|
|
||||||
public static Location[] eqLoc(Location expected) {
|
public static Location[] eqLoc(Location expected) {
|
||||||
return eqLoc(new Location[]{expected});
|
return eqLoc(new Location[]{expected});
|
||||||
}
|
}
|
||||||
@@ -42,12 +48,6 @@ public class LocationsMatcher implements IArgumentMatcher {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Location[] expectedLocations;
|
|
||||||
|
|
||||||
private LocationsMatcher(Location[] expected) {
|
|
||||||
this.expectedLocations = expected;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void appendTo(StringBuffer buf) {
|
public void appendTo(StringBuffer buf) {
|
||||||
buf.append("eqLoc(").append(Arrays.toString(expectedLocations)).append(")");
|
buf.append("eqLoc(").append(Arrays.toString(expectedLocations)).append(")");
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,6 @@ import junit.framework.TestCase;
|
|||||||
*/
|
*/
|
||||||
public class AdaptiveLocationListenerPolicyTest extends TestCase {
|
public class AdaptiveLocationListenerPolicyTest extends TestCase {
|
||||||
|
|
||||||
private AdaptiveLocationListenerPolicy adocationListenerPolicy;
|
|
||||||
private static final long MIN = 1000;
|
private static final long MIN = 1000;
|
||||||
private static final long MAX = 3000;
|
private static final long MAX = 3000;
|
||||||
private static final int MIN_DISTANCE = 10;
|
private static final int MIN_DISTANCE = 10;
|
||||||
@@ -32,6 +31,7 @@ public class AdaptiveLocationListenerPolicyTest extends TestCase {
|
|||||||
private static final long NEW_IDLE_TIME_NORMAL = 5000;
|
private static final long NEW_IDLE_TIME_NORMAL = 5000;
|
||||||
private static final long NEW_IDLE_TIME_SMALL = 2000;
|
private static final long NEW_IDLE_TIME_SMALL = 2000;
|
||||||
private static final long NEW_IDLE_TIME_LESS_THAN_MIN = 500;
|
private static final long NEW_IDLE_TIME_LESS_THAN_MIN = 500;
|
||||||
|
private AdaptiveLocationListenerPolicy adocationListenerPolicy;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
|
|||||||
+3
-3
@@ -15,14 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.services;
|
package com.google.android.apps.mytracks.services;
|
||||||
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
import com.google.android.testing.mocking.UsesMocks;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.test.ServiceTestCase;
|
import android.test.ServiceTestCase;
|
||||||
|
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
import com.google.android.testing.mocking.UsesMocks;
|
||||||
|
|
||||||
import org.easymock.EasyMock;
|
import org.easymock.EasyMock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+60
-60
@@ -38,8 +38,8 @@ import android.test.suitebuilder.annotation.SmallTest;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.android.apps.mytracks.content.CustomContentProvider;
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.CustomContentProvider;
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||||
@@ -79,24 +79,6 @@ public class TrackRecordingServiceTest extends ServiceTestCase<TestRecordingServ
|
|||||||
super(TestRecordingService.class);
|
super(TestRecordingService.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A context wrapper with the user provided {@link ContentResolver}. TODO:
|
|
||||||
* Move to test utils package.
|
|
||||||
*/
|
|
||||||
public static class MockContext extends ContextWrapper {
|
|
||||||
private final ContentResolver contentResolver;
|
|
||||||
|
|
||||||
public MockContext(ContentResolver contentResolver, Context base) {
|
|
||||||
super(base);
|
|
||||||
this.contentResolver = contentResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ContentResolver getContentResolver() {
|
|
||||||
return contentResolver;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IBinder bindService(Intent intent) {
|
protected IBinder bindService(Intent intent) {
|
||||||
if (getService() != null) {
|
if (getService() != null) {
|
||||||
@@ -328,47 +310,6 @@ public class TrackRecordingServiceTest extends ServiceTestCase<TestRecordingServ
|
|||||||
assertEquals(-1L, service.getRecordingTrackId());
|
assertEquals(-1L, service.getRecordingTrackId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Synchronous/waitable broadcast receiver to be used in testing.
|
|
||||||
*/
|
|
||||||
private class BlockingBroadcastReceiver extends BroadcastReceiver {
|
|
||||||
private static final long MAX_WAIT_TIME_MS = 10000;
|
|
||||||
private List<Intent> receivedIntents = new ArrayList<Intent>();
|
|
||||||
|
|
||||||
public List<Intent> getReceivedIntents() {
|
|
||||||
return receivedIntents;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context ctx, Intent intent) {
|
|
||||||
Log.d("Test", "Got broadcast: " + intent);
|
|
||||||
synchronized (receivedIntents) {
|
|
||||||
receivedIntents.add(intent);
|
|
||||||
receivedIntents.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean waitUntilReceived(int receiveCount) {
|
|
||||||
long deadline = System.currentTimeMillis() + MAX_WAIT_TIME_MS;
|
|
||||||
synchronized (receivedIntents) {
|
|
||||||
while (receivedIntents.size() < receiveCount) {
|
|
||||||
try {
|
|
||||||
// Wait releases synchronized lock until it returns
|
|
||||||
receivedIntents.wait(500);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
if (System.currentTimeMillis() > deadline) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
public void testStartNewTrack_noRecording() throws Exception {
|
public void testStartNewTrack_noRecording() throws Exception {
|
||||||
// NOTICE: due to the way Android permissions work, if this fails,
|
// NOTICE: due to the way Android permissions work, if this fails,
|
||||||
@@ -757,4 +698,63 @@ public class TrackRecordingServiceTest extends ServiceTestCase<TestRecordingServ
|
|||||||
trackRecordingService.insertTrackPoint(location);
|
trackRecordingService.insertTrackPoint(location);
|
||||||
Thread.sleep(200);
|
Thread.sleep(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A context wrapper with the user provided {@link ContentResolver}. TODO:
|
||||||
|
* Move to test utils package.
|
||||||
|
*/
|
||||||
|
public static class MockContext extends ContextWrapper {
|
||||||
|
private final ContentResolver contentResolver;
|
||||||
|
|
||||||
|
public MockContext(ContentResolver contentResolver, Context base) {
|
||||||
|
super(base);
|
||||||
|
this.contentResolver = contentResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ContentResolver getContentResolver() {
|
||||||
|
return contentResolver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronous/waitable broadcast receiver to be used in testing.
|
||||||
|
*/
|
||||||
|
private class BlockingBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
private static final long MAX_WAIT_TIME_MS = 10000;
|
||||||
|
private List<Intent> receivedIntents = new ArrayList<Intent>();
|
||||||
|
|
||||||
|
public List<Intent> getReceivedIntents() {
|
||||||
|
return receivedIntents;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context ctx, Intent intent) {
|
||||||
|
Log.d("Test", "Got broadcast: " + intent);
|
||||||
|
synchronized (receivedIntents) {
|
||||||
|
receivedIntents.add(intent);
|
||||||
|
receivedIntents.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean waitUntilReceived(int receiveCount) {
|
||||||
|
long deadline = System.currentTimeMillis() + MAX_WAIT_TIME_MS;
|
||||||
|
synchronized (receivedIntents) {
|
||||||
|
while (receivedIntents.size() < receiveCount) {
|
||||||
|
try {
|
||||||
|
// Wait releases synchronized lock until it returns
|
||||||
|
receivedIntents.wait(500);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
if (System.currentTimeMillis() > deadline) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+222
-203
@@ -15,16 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.services.tasks;
|
package com.google.android.apps.mytracks.services.tasks;
|
||||||
|
|
||||||
import static com.google.android.testing.mocking.AndroidMock.capture;
|
|
||||||
import static com.google.android.testing.mocking.AndroidMock.eq;
|
|
||||||
import static com.google.android.testing.mocking.AndroidMock.expect;
|
|
||||||
import static com.google.android.testing.mocking.AndroidMock.same;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
|
||||||
import com.google.android.testing.mocking.AndroidMock;
|
|
||||||
import com.google.android.testing.mocking.UsesMocks;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.speech.tts.TextToSpeech;
|
import android.speech.tts.TextToSpeech;
|
||||||
import android.speech.tts.TextToSpeech.OnInitListener;
|
import android.speech.tts.TextToSpeech.OnInitListener;
|
||||||
@@ -33,12 +23,22 @@ import android.telephony.PhoneStateListener;
|
|||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.test.AndroidTestCase;
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
|
import com.google.android.testing.mocking.AndroidMock;
|
||||||
|
import com.google.android.testing.mocking.UsesMocks;
|
||||||
|
|
||||||
|
import org.easymock.Capture;
|
||||||
|
import org.easymock.EasyMock;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import org.easymock.Capture;
|
import static com.google.android.testing.mocking.AndroidMock.capture;
|
||||||
import org.easymock.EasyMock;
|
import static com.google.android.testing.mocking.AndroidMock.eq;
|
||||||
|
import static com.google.android.testing.mocking.AndroidMock.expect;
|
||||||
|
import static com.google.android.testing.mocking.AndroidMock.same;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link AnnouncementPeriodicTask}.
|
* Tests for {@link AnnouncementPeriodicTask}.
|
||||||
@@ -61,197 +61,6 @@ public class AnnouncementPeriodicTaskTest extends AndroidTestCase {
|
|||||||
private TextToSpeechDelegate ttsDelegate;
|
private TextToSpeechDelegate ttsDelegate;
|
||||||
private TextToSpeechInterface tts;
|
private TextToSpeechInterface tts;
|
||||||
|
|
||||||
/**
|
|
||||||
* Mockable interface that we delegate TTS calls to.
|
|
||||||
*/
|
|
||||||
interface TextToSpeechInterface {
|
|
||||||
int addEarcon(String earcon, String packagename, int resourceId);
|
|
||||||
int addEarcon(String earcon, String filename);
|
|
||||||
int addSpeech(String text, String packagename, int resourceId);
|
|
||||||
int addSpeech(String text, String filename);
|
|
||||||
boolean areDefaultsEnforced();
|
|
||||||
String getDefaultEngine();
|
|
||||||
Locale getLanguage();
|
|
||||||
int isLanguageAvailable(Locale loc);
|
|
||||||
boolean isSpeaking();
|
|
||||||
int playEarcon(String earcon, int queueMode,
|
|
||||||
HashMap<String, String> params);
|
|
||||||
int playSilence(long durationInMs, int queueMode,
|
|
||||||
HashMap<String, String> params);
|
|
||||||
int setEngineByPackageName(String enginePackageName);
|
|
||||||
int setLanguage(Locale loc);
|
|
||||||
int setOnUtteranceCompletedListener(OnUtteranceCompletedListener listener);
|
|
||||||
int setPitch(float pitch);
|
|
||||||
int setSpeechRate(float speechRate);
|
|
||||||
void shutdown();
|
|
||||||
int speak(String text, int queueMode, HashMap<String, String> params);
|
|
||||||
int stop();
|
|
||||||
int synthesizeToFile(String text, HashMap<String, String> params,
|
|
||||||
String filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subclass of {@link TextToSpeech} which delegates calls to the interface
|
|
||||||
* above.
|
|
||||||
* The logic here is stupid and the author is ashamed of having to write it
|
|
||||||
* like this, but basically the issue is that TextToSpeech cannot be mocked
|
|
||||||
* without running its constructor, its constructor runs async operations
|
|
||||||
* which call other methods (and then if the methods are part of a mock we'd
|
|
||||||
* have to set a behavior, but we can't 'cause the object hasn't been fully
|
|
||||||
* built yet).
|
|
||||||
* The logic is that calls made during the constructor (when tts is not yet
|
|
||||||
* set) will go up to the original class, but after tts is set we'll forward
|
|
||||||
* them all to the mock.
|
|
||||||
*/
|
|
||||||
private class TextToSpeechDelegate
|
|
||||||
extends TextToSpeech implements TextToSpeechInterface {
|
|
||||||
public TextToSpeechDelegate(Context context, OnInitListener listener) {
|
|
||||||
super(context, listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int addEarcon(String earcon, String packagename, int resourceId) {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.addEarcon(earcon, packagename, resourceId);
|
|
||||||
}
|
|
||||||
return tts.addEarcon(earcon, packagename, resourceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int addEarcon(String earcon, String filename) {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.addEarcon(earcon, filename);
|
|
||||||
}
|
|
||||||
return tts.addEarcon(earcon, filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int addSpeech(String text, String packagename, int resourceId) {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.addSpeech(text, packagename, resourceId);
|
|
||||||
}
|
|
||||||
return tts.addSpeech(text, packagename, resourceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int addSpeech(String text, String filename) {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.addSpeech(text, filename);
|
|
||||||
}
|
|
||||||
return tts.addSpeech(text, filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Locale getLanguage() {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.getLanguage();
|
|
||||||
}
|
|
||||||
return tts.getLanguage();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int isLanguageAvailable(Locale loc) {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.isLanguageAvailable(loc);
|
|
||||||
}
|
|
||||||
return tts.isLanguageAvailable(loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSpeaking() {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.isSpeaking();
|
|
||||||
}
|
|
||||||
return tts.isSpeaking();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int playEarcon(String earcon, int queueMode,
|
|
||||||
HashMap<String, String> params) {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.playEarcon(earcon, queueMode, params);
|
|
||||||
}
|
|
||||||
return tts.playEarcon(earcon, queueMode, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int playSilence(long durationInMs, int queueMode,
|
|
||||||
HashMap<String, String> params) {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.playSilence(durationInMs, queueMode, params);
|
|
||||||
}
|
|
||||||
return tts.playSilence(durationInMs, queueMode, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int setLanguage(Locale loc) {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.setLanguage(loc);
|
|
||||||
}
|
|
||||||
return tts.setLanguage(loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int setOnUtteranceCompletedListener(
|
|
||||||
OnUtteranceCompletedListener listener) {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.setOnUtteranceCompletedListener(listener);
|
|
||||||
}
|
|
||||||
return tts.setOnUtteranceCompletedListener(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int setPitch(float pitch) {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.setPitch(pitch);
|
|
||||||
}
|
|
||||||
return tts.setPitch(pitch);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int setSpeechRate(float speechRate) {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.setSpeechRate(speechRate);
|
|
||||||
}
|
|
||||||
return tts.setSpeechRate(speechRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void shutdown() {
|
|
||||||
if (tts == null) {
|
|
||||||
super.shutdown();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
tts.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int speak(
|
|
||||||
String text, int queueMode, HashMap<String, String> params) {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.speak(text, queueMode, params);
|
|
||||||
}
|
|
||||||
return tts.speak(text, queueMode, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int stop() {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.stop();
|
|
||||||
}
|
|
||||||
return tts.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int synthesizeToFile(String text, HashMap<String, String> params,
|
|
||||||
String filename) {
|
|
||||||
if (tts == null) {
|
|
||||||
return super.synthesizeToFile(text, params, filename);
|
|
||||||
}
|
|
||||||
return tts.synthesizeToFile(text, params, filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@UsesMocks({
|
@UsesMocks({
|
||||||
AnnouncementPeriodicTask.class,
|
AnnouncementPeriodicTask.class,
|
||||||
StringUtils.class,
|
StringUtils.class,
|
||||||
@@ -530,4 +339,214 @@ public class AnnouncementPeriodicTaskTest extends AndroidTestCase {
|
|||||||
AndroidMock.replay(mockTask);
|
AndroidMock.replay(mockTask);
|
||||||
task.start();
|
task.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mockable interface that we delegate TTS calls to.
|
||||||
|
*/
|
||||||
|
interface TextToSpeechInterface {
|
||||||
|
int addEarcon(String earcon, String packagename, int resourceId);
|
||||||
|
|
||||||
|
int addEarcon(String earcon, String filename);
|
||||||
|
|
||||||
|
int addSpeech(String text, String packagename, int resourceId);
|
||||||
|
|
||||||
|
int addSpeech(String text, String filename);
|
||||||
|
|
||||||
|
boolean areDefaultsEnforced();
|
||||||
|
|
||||||
|
String getDefaultEngine();
|
||||||
|
|
||||||
|
Locale getLanguage();
|
||||||
|
|
||||||
|
int isLanguageAvailable(Locale loc);
|
||||||
|
|
||||||
|
boolean isSpeaking();
|
||||||
|
|
||||||
|
int playEarcon(String earcon, int queueMode,
|
||||||
|
HashMap<String, String> params);
|
||||||
|
|
||||||
|
int playSilence(long durationInMs, int queueMode,
|
||||||
|
HashMap<String, String> params);
|
||||||
|
|
||||||
|
int setEngineByPackageName(String enginePackageName);
|
||||||
|
|
||||||
|
int setLanguage(Locale loc);
|
||||||
|
|
||||||
|
int setOnUtteranceCompletedListener(OnUtteranceCompletedListener listener);
|
||||||
|
|
||||||
|
int setPitch(float pitch);
|
||||||
|
|
||||||
|
int setSpeechRate(float speechRate);
|
||||||
|
|
||||||
|
void shutdown();
|
||||||
|
|
||||||
|
int speak(String text, int queueMode, HashMap<String, String> params);
|
||||||
|
|
||||||
|
int stop();
|
||||||
|
|
||||||
|
int synthesizeToFile(String text, HashMap<String, String> params,
|
||||||
|
String filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclass of {@link TextToSpeech} which delegates calls to the interface
|
||||||
|
* above.
|
||||||
|
* The logic here is stupid and the author is ashamed of having to write it
|
||||||
|
* like this, but basically the issue is that TextToSpeech cannot be mocked
|
||||||
|
* without running its constructor, its constructor runs async operations
|
||||||
|
* which call other methods (and then if the methods are part of a mock we'd
|
||||||
|
* have to set a behavior, but we can't 'cause the object hasn't been fully
|
||||||
|
* built yet).
|
||||||
|
* The logic is that calls made during the constructor (when tts is not yet
|
||||||
|
* set) will go up to the original class, but after tts is set we'll forward
|
||||||
|
* them all to the mock.
|
||||||
|
*/
|
||||||
|
private class TextToSpeechDelegate
|
||||||
|
extends TextToSpeech implements TextToSpeechInterface {
|
||||||
|
public TextToSpeechDelegate(Context context, OnInitListener listener) {
|
||||||
|
super(context, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int addEarcon(String earcon, String packagename, int resourceId) {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.addEarcon(earcon, packagename, resourceId);
|
||||||
|
}
|
||||||
|
return tts.addEarcon(earcon, packagename, resourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int addEarcon(String earcon, String filename) {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.addEarcon(earcon, filename);
|
||||||
|
}
|
||||||
|
return tts.addEarcon(earcon, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int addSpeech(String text, String packagename, int resourceId) {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.addSpeech(text, packagename, resourceId);
|
||||||
|
}
|
||||||
|
return tts.addSpeech(text, packagename, resourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int addSpeech(String text, String filename) {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.addSpeech(text, filename);
|
||||||
|
}
|
||||||
|
return tts.addSpeech(text, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Locale getLanguage() {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.getLanguage();
|
||||||
|
}
|
||||||
|
return tts.getLanguage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int isLanguageAvailable(Locale loc) {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.isLanguageAvailable(loc);
|
||||||
|
}
|
||||||
|
return tts.isLanguageAvailable(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSpeaking() {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.isSpeaking();
|
||||||
|
}
|
||||||
|
return tts.isSpeaking();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int playEarcon(String earcon, int queueMode,
|
||||||
|
HashMap<String, String> params) {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.playEarcon(earcon, queueMode, params);
|
||||||
|
}
|
||||||
|
return tts.playEarcon(earcon, queueMode, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int playSilence(long durationInMs, int queueMode,
|
||||||
|
HashMap<String, String> params) {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.playSilence(durationInMs, queueMode, params);
|
||||||
|
}
|
||||||
|
return tts.playSilence(durationInMs, queueMode, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int setLanguage(Locale loc) {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.setLanguage(loc);
|
||||||
|
}
|
||||||
|
return tts.setLanguage(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int setOnUtteranceCompletedListener(
|
||||||
|
OnUtteranceCompletedListener listener) {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.setOnUtteranceCompletedListener(listener);
|
||||||
|
}
|
||||||
|
return tts.setOnUtteranceCompletedListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int setPitch(float pitch) {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.setPitch(pitch);
|
||||||
|
}
|
||||||
|
return tts.setPitch(pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int setSpeechRate(float speechRate) {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.setSpeechRate(speechRate);
|
||||||
|
}
|
||||||
|
return tts.setSpeechRate(speechRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shutdown() {
|
||||||
|
if (tts == null) {
|
||||||
|
super.shutdown();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tts.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int speak(
|
||||||
|
String text, int queueMode, HashMap<String, String> params) {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.speak(text, queueMode, params);
|
||||||
|
}
|
||||||
|
return tts.speak(text, queueMode, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int stop() {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.stop();
|
||||||
|
}
|
||||||
|
return tts.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int synthesizeToFile(String text, HashMap<String, String> params,
|
||||||
|
String filename) {
|
||||||
|
if (tts == null) {
|
||||||
|
return super.synthesizeToFile(text, params, filename);
|
||||||
|
}
|
||||||
|
return tts.synthesizeToFile(text, params, filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ package com.google.android.apps.mytracks.util;
|
|||||||
|
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link FileUtils}.
|
* Tests for {@link FileUtils}.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import androidx.fragment.app.FragmentActivity;
|
|||||||
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author Jimmy Shih
|
* @author Jimmy Shih
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractActivity extends FragmentActivity {
|
public abstract class AbstractActivity extends FragmentActivity {
|
||||||
|
|||||||
@@ -51,17 +51,8 @@ import java.util.ArrayList;
|
|||||||
*/
|
*/
|
||||||
public abstract class AbstractTrackActivity extends AbstractActivity implements ConfirmDeleteCaller {
|
public abstract class AbstractTrackActivity extends AbstractActivity implements ConfirmDeleteCaller {
|
||||||
|
|
||||||
private static final int DELETE_REQUEST_CODE = 3;
|
|
||||||
protected static final int GPS_REQUEST_CODE = 6;
|
protected static final int GPS_REQUEST_CODE = 6;
|
||||||
|
private static final int DELETE_REQUEST_CODE = 3;
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
if (requestCode == DELETE_REQUEST_CODE) {
|
|
||||||
onDeleted();
|
|
||||||
} else {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void configureListViewContextualMenu(final ListView listView, final ContextualActionModeCallback contextualActionModeCallback) {
|
public static void configureListViewContextualMenu(final ListView listView, final ContextualActionModeCallback contextualActionModeCallback) {
|
||||||
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
|
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
|
||||||
@@ -166,6 +157,15 @@ public abstract class AbstractTrackActivity extends AbstractActivity implements
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
if (requestCode == DELETE_REQUEST_CODE) {
|
||||||
|
onDeleted();
|
||||||
|
} else {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete tracks.
|
* Delete tracks.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -16,14 +16,14 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks;
|
package com.google.android.apps.mytracks;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
import com.google.android.apps.mytracks.util.StatsUtils;
|
import com.google.android.apps.mytracks.util.StatsUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -15,24 +15,24 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks;
|
package com.google.android.apps.mytracks;
|
||||||
|
|
||||||
import static android.content.Intent.ACTION_BOOT_COMPLETED;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.services.TrackRecordingService;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.services.TrackRecordingService;
|
||||||
|
|
||||||
|
import static android.content.Intent.ACTION_BOOT_COMPLETED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class react to the BOOT_COMPLETED broadcast.
|
* This class react to the BOOT_COMPLETED broadcast.
|
||||||
*
|
* <p>
|
||||||
* One example of a broadcast message that this class is interested in,
|
* One example of a broadcast message that this class is interested in,
|
||||||
* is notification about the phone boot. We may want to resume a previously
|
* is notification about the phone boot. We may want to resume a previously
|
||||||
* started tracking session if the phone crashed (hopefully not), or the user
|
* started tracking session if the phone crashed (hopefully not), or the user
|
||||||
* decided to swap the battery or some external event occurred which forced
|
* decided to swap the battery or some external event occurred which forced
|
||||||
* a phone reboot.
|
* a phone reboot.
|
||||||
*
|
* <p>
|
||||||
* This class simply delegates to {@link TrackRecordingService} to make a
|
* This class simply delegates to {@link TrackRecordingService} to make a
|
||||||
* decision whether to continue with the previous track (if any), or just
|
* decision whether to continue with the previous track (if any), or just
|
||||||
* abandon it.
|
* abandon it.
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import android.graphics.Paint;
|
|||||||
import android.graphics.Paint.Align;
|
import android.graphics.Paint.Align;
|
||||||
import android.graphics.Paint.Style;
|
import android.graphics.Paint.Style;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.stats.ExtremityMonitor;
|
import com.google.android.apps.mytracks.stats.ExtremityMonitor;
|
||||||
@@ -104,6 +105,13 @@ public class ChartValueSeries {
|
|||||||
path = new Path();
|
path = new Path();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the series is enabled.
|
||||||
|
*/
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the series enabled value.
|
* Sets the series enabled value.
|
||||||
*
|
*
|
||||||
@@ -113,13 +121,6 @@ public class ChartValueSeries {
|
|||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the series is enabled.
|
|
||||||
*/
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the series has data.
|
* Returns true if the series has data.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -71,30 +71,27 @@ public class ChartView extends View {
|
|||||||
|
|
||||||
private static final NumberFormat X_NUMBER_FORMAT = NumberFormat.getIntegerInstance();
|
private static final NumberFormat X_NUMBER_FORMAT = NumberFormat.getIntegerInstance();
|
||||||
private static final NumberFormat X_FRACTION_FORMAT = NumberFormat.getNumberInstance();
|
private static final NumberFormat X_FRACTION_FORMAT = NumberFormat.getNumberInstance();
|
||||||
|
private static final int BORDER = 8;
|
||||||
|
private static final int SPACER = 4;
|
||||||
|
private static final int Y_AXIS_OFFSET = 16;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
X_FRACTION_FORMAT.setMaximumFractionDigits(1);
|
X_FRACTION_FORMAT.setMaximumFractionDigits(1);
|
||||||
X_FRACTION_FORMAT.setMinimumFractionDigits(1);
|
X_FRACTION_FORMAT.setMinimumFractionDigits(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int BORDER = 8;
|
|
||||||
private static final int SPACER = 4;
|
|
||||||
private static final int Y_AXIS_OFFSET = 16;
|
|
||||||
|
|
||||||
private final ChartValueSeries[] series = new ChartValueSeries[NUM_SERIES];
|
private final ChartValueSeries[] series = new ChartValueSeries[NUM_SERIES];
|
||||||
private final ArrayList<double[]> chartData = new ArrayList<>();
|
private final ArrayList<double[]> chartData = new ArrayList<>();
|
||||||
private final ArrayList<Waypoint> waypoints = new ArrayList<>();
|
private final ArrayList<Waypoint> waypoints = new ArrayList<>();
|
||||||
private final ExtremityMonitor xExtremityMonitor = new ExtremityMonitor();
|
private final ExtremityMonitor xExtremityMonitor = new ExtremityMonitor();
|
||||||
private double maxX = 1.0;
|
|
||||||
|
|
||||||
private final Paint axisPaint;
|
private final Paint axisPaint;
|
||||||
private final Paint xAxisMarkerPaint;
|
private final Paint xAxisMarkerPaint;
|
||||||
private final Paint gridPaint;
|
private final Paint gridPaint;
|
||||||
|
|
||||||
private final Drawable pointer;
|
private final Drawable pointer;
|
||||||
private final int markerWidth;
|
private final int markerWidth;
|
||||||
private final int markerHeight;
|
private final int markerHeight;
|
||||||
|
|
||||||
private final Scroller scroller;
|
private final Scroller scroller;
|
||||||
|
private double maxX = 1.0;
|
||||||
private VelocityTracker velocityTracker = null;
|
private VelocityTracker velocityTracker = null;
|
||||||
private float lastMotionEventX = -1;
|
private float lastMotionEventX = -1;
|
||||||
private int zoomLevel = 1;
|
private int zoomLevel = 1;
|
||||||
|
|||||||
@@ -23,15 +23,15 @@ package com.google.android.apps.mytracks;
|
|||||||
*/
|
*/
|
||||||
public class Constants {
|
public class Constants {
|
||||||
|
|
||||||
private Constants() {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum number of waypoints that will be loaded at one time.
|
* Maximum number of waypoints that will be loaded at one time.
|
||||||
*/
|
*/
|
||||||
public static final int MAX_LOADED_WAYPOINTS_POINTS = 10000;
|
public static final int MAX_LOADED_WAYPOINTS_POINTS = 10000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The settings file name.
|
* The settings file name.
|
||||||
*/
|
*/
|
||||||
public static final String SETTINGS_NAME = "SettingsActivity";
|
public static final String SETTINGS_NAME = "SettingsActivity";
|
||||||
|
|
||||||
|
private Constants() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,15 +16,15 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks;
|
package com.google.android.apps.mytracks;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.util.DialogUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.util.DialogUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An activity for delete tracks.
|
* An activity for delete tracks.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -28,10 +28,9 @@ import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
|||||||
*/
|
*/
|
||||||
public class DeleteAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
public class DeleteAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||||
|
|
||||||
private DeleteActivity deleteActivity;
|
|
||||||
private final long[] trackIds;
|
private final long[] trackIds;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
private DeleteActivity deleteActivity;
|
||||||
// true if the AsyncTask has completed
|
// true if the AsyncTask has completed
|
||||||
private boolean completed;
|
private boolean completed;
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,6 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks;
|
package com.google.android.apps.mytracks;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
|
||||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
|
||||||
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
|
|
||||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
|
||||||
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -33,6 +25,14 @@ import android.widget.AutoCompleteTextView;
|
|||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
|
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||||
|
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
|
||||||
|
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||||
|
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An activity to add/edit a marker.
|
* An activity to add/edit a marker.
|
||||||
*
|
*
|
||||||
@@ -40,11 +40,9 @@ import android.widget.EditText;
|
|||||||
*/
|
*/
|
||||||
public class MarkerEditActivity extends AbstractActivity {
|
public class MarkerEditActivity extends AbstractActivity {
|
||||||
|
|
||||||
private static final String TAG = MarkerEditActivity.class.getSimpleName();
|
|
||||||
|
|
||||||
public static final String EXTRA_TRACK_ID = "track_id";
|
public static final String EXTRA_TRACK_ID = "track_id";
|
||||||
public static final String EXTRA_MARKER_ID = "marker_id";
|
public static final String EXTRA_MARKER_ID = "marker_id";
|
||||||
|
private static final String TAG = MarkerEditActivity.class.getSimpleName();
|
||||||
private long trackId;
|
private long trackId;
|
||||||
private long markerId;
|
private long markerId;
|
||||||
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
||||||
|
|||||||
@@ -66,30 +66,10 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
|
|||||||
WaypointsColumns.NAME, WaypointsColumns.DESCRIPTION, WaypointsColumns.CATEGORY,
|
WaypointsColumns.NAME, WaypointsColumns.DESCRIPTION, WaypointsColumns.CATEGORY,
|
||||||
WaypointsColumns.TYPE, WaypointsColumns.TIME, WaypointsColumns.PHOTOURL,
|
WaypointsColumns.TYPE, WaypointsColumns.TIME, WaypointsColumns.PHOTOURL,
|
||||||
WaypointsColumns.LATITUDE, WaypointsColumns.LONGITUDE};
|
WaypointsColumns.LATITUDE, WaypointsColumns.LONGITUDE};
|
||||||
|
private ContentProviderUtils contentProviderUtils;
|
||||||
// Callback when an item is selected in the contextual action mode
|
private SharedPreferences sharedPreferences;
|
||||||
private ContextualActionModeCallback contextualActionModeCallback = new ContextualActionModeCallback() {
|
private long recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
||||||
@Override
|
private boolean recordingTrackPaused = PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT;
|
||||||
public void onPrepare(Menu menu, int[] positions, long[] ids, boolean showSelectAll) {
|
|
||||||
boolean isSingleSelection = ids.length == 1;
|
|
||||||
|
|
||||||
menu.findItem(R.id.list_context_menu_share).setVisible(false);
|
|
||||||
menu.findItem(R.id.list_context_menu_show_on_map).setVisible(isSingleSelection);
|
|
||||||
menu.findItem(R.id.list_context_menu_edit).setVisible(isSingleSelection);
|
|
||||||
menu.findItem(R.id.list_context_menu_delete).setVisible(true);
|
|
||||||
/*
|
|
||||||
* Set select all to the same visibility as delete since delete is the
|
|
||||||
* only action that can be applied to multiple markers.
|
|
||||||
*/
|
|
||||||
menu.findItem(R.id.list_context_menu_select_all).setVisible(showSelectAll);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onClick(int itemId, int[] positions, long[] ids) {
|
|
||||||
return handleContextItem(itemId, ids);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that sharedPreferenceChangeListener cannot be an anonymous inner
|
* Note that sharedPreferenceChangeListener cannot be an anonymous inner
|
||||||
* class. Anonymous inner class will get garbage collected.
|
* class. Anonymous inner class will get garbage collected.
|
||||||
@@ -115,18 +95,32 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private ContentProviderUtils contentProviderUtils;
|
|
||||||
private SharedPreferences sharedPreferences;
|
|
||||||
|
|
||||||
private long recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
|
||||||
private boolean recordingTrackPaused = PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT;
|
|
||||||
|
|
||||||
private Track track;
|
private Track track;
|
||||||
private ResourceCursorAdapter resourceCursorAdapter;
|
private ResourceCursorAdapter resourceCursorAdapter;
|
||||||
|
|
||||||
// UI elements
|
// UI elements
|
||||||
private ListView listView;
|
private ListView listView;
|
||||||
|
// Callback when an item is selected in the contextual action mode
|
||||||
|
private ContextualActionModeCallback contextualActionModeCallback = new ContextualActionModeCallback() {
|
||||||
|
@Override
|
||||||
|
public void onPrepare(Menu menu, int[] positions, long[] ids, boolean showSelectAll) {
|
||||||
|
boolean isSingleSelection = ids.length == 1;
|
||||||
|
|
||||||
|
menu.findItem(R.id.list_context_menu_share).setVisible(false);
|
||||||
|
menu.findItem(R.id.list_context_menu_show_on_map).setVisible(isSingleSelection);
|
||||||
|
menu.findItem(R.id.list_context_menu_edit).setVisible(isSingleSelection);
|
||||||
|
menu.findItem(R.id.list_context_menu_delete).setVisible(true);
|
||||||
|
/*
|
||||||
|
* Set select all to the same visibility as delete since delete is the
|
||||||
|
* only action that can be applied to multiple markers.
|
||||||
|
*/
|
||||||
|
menu.findItem(R.id.list_context_menu_select_all).setVisible(showSelectAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onClick(int itemId, int[] positions, long[] ids) {
|
||||||
|
return handleContextItem(itemId, ids);
|
||||||
|
}
|
||||||
|
};
|
||||||
private MenuItem insertMarkerMenuItem;
|
private MenuItem insertMarkerMenuItem;
|
||||||
private MenuItem searchMenuItem;
|
private MenuItem searchMenuItem;
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ import java.util.SortedSet;
|
|||||||
* An activity to display a list of search results.
|
* An activity to display a list of search results.
|
||||||
*
|
*
|
||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
*
|
* <p>
|
||||||
* TODO: allow to refine search (present search in context menu)
|
* TODO: allow to refine search (present search in context menu)
|
||||||
*/
|
*/
|
||||||
public class SearchListActivity extends AbstractTrackActivity implements DeleteMarkerCaller, ConfirmDeleteDialogFragment.ConfirmDeleteCaller {
|
public class SearchListActivity extends AbstractTrackActivity implements DeleteMarkerCaller, ConfirmDeleteDialogFragment.ConfirmDeleteCaller {
|
||||||
@@ -94,37 +94,21 @@ public class SearchListActivity extends AbstractTrackActivity implements DeleteM
|
|||||||
|
|
||||||
private static final String TRACK_ID_FIELD = "trackId";
|
private static final String TRACK_ID_FIELD = "trackId";
|
||||||
private static final String MARKER_ID_FIELD = "markerId";
|
private static final String MARKER_ID_FIELD = "markerId";
|
||||||
|
private ContentProviderUtils contentProviderUtils;
|
||||||
private final OnSharedPreferenceChangeListener
|
private SharedPreferences sharedPreferences;
|
||||||
sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
||||||
@Override
|
private SearchEngine searchEngine;
|
||||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
private SearchRecentSuggestions searchRecentSuggestions;
|
||||||
if (key == null || key.equals(PreferencesUtils.getKey(SearchListActivity.this, R.string.stats_units_key))) {
|
private ArrayAdapter<Map<String, Object>> arrayAdapter;
|
||||||
metricUnits = PreferencesUtils.isMetricUnits(SearchListActivity.this);
|
private boolean metricUnits = true;
|
||||||
}
|
private long recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
||||||
if (key == null || key.equals(PreferencesUtils.getKey(SearchListActivity.this, R.string.recording_track_id_key))) {
|
|
||||||
recordingTrackId = PreferencesUtils.getLong(SearchListActivity.this, R.string.recording_track_id_key);
|
|
||||||
}
|
|
||||||
if (key == null || key.equals(PreferencesUtils.getKey(SearchListActivity.this, R.string.recording_track_paused_key))) {
|
|
||||||
recordingTrackPaused = PreferencesUtils.getBoolean(SearchListActivity.this, R.string.recording_track_paused_key, PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT);
|
|
||||||
}
|
|
||||||
if (key != null) {
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
arrayAdapter.notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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 ContextualActionModeCallback contextualActionModeCallback = new ContextualActionModeCallback() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onClick(int itemId, int[] positions, long[] ids) {
|
public boolean onClick(int itemId, int[] positions, long[] ids) {
|
||||||
return handleContextItem(itemId, positions);
|
return handleContextItem(itemId, positions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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 = recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
boolean isRecording = recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
||||||
@@ -153,17 +137,30 @@ public class SearchListActivity extends AbstractTrackActivity implements DeleteM
|
|||||||
menu.findItem(R.id.list_context_menu_select_all).setVisible(false);
|
menu.findItem(R.id.list_context_menu_select_all).setVisible(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private ContentProviderUtils contentProviderUtils;
|
|
||||||
private SharedPreferences sharedPreferences;
|
|
||||||
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
|
||||||
private SearchEngine searchEngine;
|
|
||||||
private SearchRecentSuggestions searchRecentSuggestions;
|
|
||||||
private ArrayAdapter<Map<String, Object>> arrayAdapter;
|
|
||||||
|
|
||||||
private boolean metricUnits = true;
|
|
||||||
private long recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
|
||||||
private boolean recordingTrackPaused = PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT;
|
private boolean recordingTrackPaused = PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT;
|
||||||
|
private final OnSharedPreferenceChangeListener
|
||||||
|
sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
||||||
|
if (key == null || key.equals(PreferencesUtils.getKey(SearchListActivity.this, R.string.stats_units_key))) {
|
||||||
|
metricUnits = PreferencesUtils.isMetricUnits(SearchListActivity.this);
|
||||||
|
}
|
||||||
|
if (key == null || key.equals(PreferencesUtils.getKey(SearchListActivity.this, R.string.recording_track_id_key))) {
|
||||||
|
recordingTrackId = PreferencesUtils.getLong(SearchListActivity.this, R.string.recording_track_id_key);
|
||||||
|
}
|
||||||
|
if (key == null || key.equals(PreferencesUtils.getKey(SearchListActivity.this, R.string.recording_track_paused_key))) {
|
||||||
|
recordingTrackPaused = PreferencesUtils.getBoolean(SearchListActivity.this, R.string.recording_track_paused_key, PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT);
|
||||||
|
}
|
||||||
|
if (key != null) {
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
arrayAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
|||||||
@@ -18,16 +18,17 @@ package com.google.android.apps.mytracks;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import androidx.fragment.app.FragmentPagerAdapter;
|
|
||||||
import androidx.viewpager.widget.ViewPager;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TabHost;
|
import android.widget.TabHost;
|
||||||
import android.widget.TabHost.TabContentFactory;
|
import android.widget.TabHost.TabContentFactory;
|
||||||
import android.widget.TabWidget;
|
import android.widget.TabWidget;
|
||||||
|
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.fragment.app.FragmentPagerAdapter;
|
||||||
|
import androidx.viewpager.widget.ViewPager;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,45 +53,6 @@ public class TabsAdapter extends FragmentPagerAdapter implements TabHost.OnTabCh
|
|||||||
private final ViewPager viewPager;
|
private final ViewPager viewPager;
|
||||||
private final ArrayList<TabInfo> tabInfos = new ArrayList<>();
|
private final ArrayList<TabInfo> tabInfos = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
|
||||||
* An object to hold a tab's info.
|
|
||||||
*
|
|
||||||
* @author Jimmy Shih
|
|
||||||
*/
|
|
||||||
private static final class TabInfo {
|
|
||||||
|
|
||||||
private final Class<?> clss;
|
|
||||||
private final Bundle bundle;
|
|
||||||
|
|
||||||
public TabInfo(Class<?> clss, Bundle bunlde) {
|
|
||||||
this.clss = clss;
|
|
||||||
this.bundle = bunlde;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A dummy {@link TabContentFactory} that creates an empty view to satisfy the
|
|
||||||
* {@link TabHost} API.
|
|
||||||
*
|
|
||||||
* @author Jimmy Shih
|
|
||||||
*/
|
|
||||||
private static class DummyTabFactory implements TabHost.TabContentFactory {
|
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
public DummyTabFactory(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View createTabContent(String tag) {
|
|
||||||
View view = new View(context);
|
|
||||||
view.setMinimumWidth(0);
|
|
||||||
view.setMinimumHeight(0);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager viewPager) {
|
public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager viewPager) {
|
||||||
super(activity.getSupportFragmentManager());
|
super(activity.getSupportFragmentManager());
|
||||||
this.context = activity;
|
this.context = activity;
|
||||||
@@ -129,7 +91,8 @@ public class TabsAdapter extends FragmentPagerAdapter implements TabHost.OnTabCh
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
|
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPageSelected(int position) {
|
public void onPageSelected(int position) {
|
||||||
@@ -146,5 +109,45 @@ public class TabsAdapter extends FragmentPagerAdapter implements TabHost.OnTabCh
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPageScrollStateChanged(int state) {}
|
public void onPageScrollStateChanged(int state) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object to hold a tab's info.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
private static final class TabInfo {
|
||||||
|
|
||||||
|
private final Class<?> clss;
|
||||||
|
private final Bundle bundle;
|
||||||
|
|
||||||
|
public TabInfo(Class<?> clss, Bundle bunlde) {
|
||||||
|
this.clss = clss;
|
||||||
|
this.bundle = bunlde;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dummy {@link TabContentFactory} that creates an empty view to satisfy the
|
||||||
|
* {@link TabHost} API.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
private static class DummyTabFactory implements TabHost.TabContentFactory {
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
public DummyTabFactory(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View createTabContent(String tag) {
|
||||||
|
View view = new View(context);
|
||||||
|
view.setMinimumWidth(0);
|
||||||
|
view.setMinimumHeight(0);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,11 +76,9 @@ import java.util.Date;
|
|||||||
*/
|
*/
|
||||||
public class TrackDetailActivity extends AbstractTrackActivity implements ChooseActivityTypeCaller, ConfirmDeleteDialogFragment.ConfirmDeleteCaller {
|
public class TrackDetailActivity extends AbstractTrackActivity implements ChooseActivityTypeCaller, ConfirmDeleteDialogFragment.ConfirmDeleteCaller {
|
||||||
|
|
||||||
private static final String TAG = TrackDetailActivity.class.getSimpleName();
|
|
||||||
|
|
||||||
public static final String EXTRA_TRACK_ID = "track_id";
|
public static final String EXTRA_TRACK_ID = "track_id";
|
||||||
public static final String EXTRA_MARKER_ID = "marker_id";
|
public static final String EXTRA_MARKER_ID = "marker_id";
|
||||||
|
private static final String TAG = TrackDetailActivity.class.getSimpleName();
|
||||||
private static final String CURRENT_TAB_TAG_KEY = "current_tab_tag_key";
|
private static final String CURRENT_TAB_TAG_KEY = "current_tab_tag_key";
|
||||||
private static final String PHOTO_URI_KEY = "photo_uri_key";
|
private static final String PHOTO_URI_KEY = "photo_uri_key";
|
||||||
private static final String HAS_PHOTO_KEY = "has_photo_key";
|
private static final String HAS_PHOTO_KEY = "has_photo_key";
|
||||||
@@ -106,14 +104,6 @@ public class TrackDetailActivity extends AbstractTrackActivity implements Choose
|
|||||||
// Preferences
|
// Preferences
|
||||||
private long recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
private long recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
||||||
private boolean recordingTrackPaused = PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT;
|
private boolean recordingTrackPaused = PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT;
|
||||||
|
|
||||||
private MenuItem insertMarkerMenuItem;
|
|
||||||
private MenuItem insertPhotoMenuItem;
|
|
||||||
private MenuItem markerListMenuItem;
|
|
||||||
private MenuItem shareMenuItem;
|
|
||||||
private MenuItem voiceFrequencyMenuItem;
|
|
||||||
private MenuItem splitFrequencyMenuItem;
|
|
||||||
|
|
||||||
private final Runnable bindChangedCallback = new Runnable() {
|
private final Runnable bindChangedCallback = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -135,7 +125,6 @@ public class TrackDetailActivity extends AbstractTrackActivity implements Choose
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that sharedPreferenceChangeListener cannot be an anonymous inner
|
* Note that sharedPreferenceChangeListener cannot be an anonymous inner
|
||||||
* class. Anonymous inner class will get garbage collected.
|
* class. Anonymous inner class will get garbage collected.
|
||||||
@@ -164,7 +153,12 @@ public class TrackDetailActivity extends AbstractTrackActivity implements Choose
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
private MenuItem insertMarkerMenuItem;
|
||||||
|
private MenuItem insertPhotoMenuItem;
|
||||||
|
private MenuItem markerListMenuItem;
|
||||||
|
private MenuItem shareMenuItem;
|
||||||
|
private MenuItem voiceFrequencyMenuItem;
|
||||||
|
private MenuItem splitFrequencyMenuItem;
|
||||||
private final OnClickListener recordListener = new OnClickListener() {
|
private final OnClickListener recordListener = new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
|||||||
@@ -87,7 +87,110 @@ public class TrackListActivity extends AbstractTrackActivity implements FileType
|
|||||||
private static final String[] PROJECTION = new String[]{TracksColumns._ID, TracksColumns.NAME,
|
private static final String[] PROJECTION = new String[]{TracksColumns._ID, TracksColumns.NAME,
|
||||||
TracksColumns.DESCRIPTION, TracksColumns.CATEGORY, TracksColumns.STARTTIME,
|
TracksColumns.DESCRIPTION, TracksColumns.CATEGORY, TracksColumns.STARTTIME,
|
||||||
TracksColumns.TOTALDISTANCE, TracksColumns.TOTALTIME, TracksColumns.ICON};
|
TracksColumns.TOTALDISTANCE, TracksColumns.TOTALTIME, TracksColumns.ICON};
|
||||||
|
// The following are set in onCreate
|
||||||
|
private ContentProviderUtils contentProviderUtils;
|
||||||
|
private SharedPreferences sharedPreferences;
|
||||||
|
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
||||||
|
private TrackController trackController;
|
||||||
|
private ListView listView;
|
||||||
|
private ResourceCursorAdapter resourceCursorAdapter;
|
||||||
|
private final LoaderCallbacks<Cursor> loaderCallbacks = new LoaderCallbacks<Cursor>() {
|
||||||
|
@Override
|
||||||
|
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
||||||
|
return new CursorLoader(TrackListActivity.this, TracksColumns.CONTENT_URI, PROJECTION, null,
|
||||||
|
null, TrackUtils.TRACK_SORT_ORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor cursor) {
|
||||||
|
resourceCursorAdapter.swapCursor(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoaderReset(@NonNull Loader<Cursor> loader) {
|
||||||
|
resourceCursorAdapter.swapCursor(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Preferences
|
||||||
|
private boolean metricUnits = true;
|
||||||
|
private long recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
||||||
|
// Callback when an item is selected in the contextual action mode
|
||||||
|
private final ContextualActionModeCallback
|
||||||
|
contextualActionModeCallback = new ContextualActionModeCallback() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPrepare(Menu menu, int[] positions, long[] ids, boolean showSelectAll) {
|
||||||
|
boolean isRecording = recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
||||||
|
boolean isSingleSelection = ids.length == 1;
|
||||||
|
|
||||||
|
menu.findItem(R.id.list_context_menu_share).setVisible(!isRecording && isSingleSelection);
|
||||||
|
menu.findItem(R.id.list_context_menu_show_on_map).setVisible(false);
|
||||||
|
menu.findItem(R.id.list_context_menu_edit).setVisible(isSingleSelection);
|
||||||
|
menu.findItem(R.id.list_context_menu_select_all).setVisible(showSelectAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onClick(int itemId, int[] positions, long[] ids) {
|
||||||
|
return handleContextItem(itemId, ids);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private boolean recordingTrackPaused = PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT;
|
||||||
|
/*
|
||||||
|
* Note that sharedPreferenceChangeListenr cannot be an anonymous inner class.
|
||||||
|
* Anonymous inner class will get garbage collected.
|
||||||
|
*/
|
||||||
|
private final OnSharedPreferenceChangeListener
|
||||||
|
sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
||||||
|
if (key == null || key.equals(
|
||||||
|
PreferencesUtils.getKey(TrackListActivity.this, R.string.stats_units_key))) {
|
||||||
|
metricUnits = PreferencesUtils.isMetricUnits(TrackListActivity.this);
|
||||||
|
}
|
||||||
|
if (key == null || key.equals(
|
||||||
|
PreferencesUtils.getKey(TrackListActivity.this, R.string.recording_track_id_key))) {
|
||||||
|
recordingTrackId = PreferencesUtils.getLong(
|
||||||
|
TrackListActivity.this, R.string.recording_track_id_key);
|
||||||
|
if (key != null && recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
|
||||||
|
trackRecordingServiceConnection.startAndBind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (key == null || key.equals(PreferencesUtils.getKey(
|
||||||
|
TrackListActivity.this, R.string.recording_track_paused_key))) {
|
||||||
|
recordingTrackPaused = PreferencesUtils.getBoolean(TrackListActivity.this,
|
||||||
|
R.string.recording_track_paused_key,
|
||||||
|
PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT);
|
||||||
|
}
|
||||||
|
if (key != null) {
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
TrackListActivity.this.invalidateOptionsMenu();
|
||||||
|
LoaderManager.getInstance(TrackListActivity.this).restartLoader(0, null, loaderCallbacks);
|
||||||
|
boolean isRecording = recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
||||||
|
trackController.update(isRecording, recordingTrackPaused);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Menu items
|
||||||
|
private MenuItem searchMenuItem;
|
||||||
|
private MenuItem startGpsMenuItem;
|
||||||
|
private MenuItem aggregatedStatisticsMenuItem;
|
||||||
|
private MenuItem exportAllMenuItem;
|
||||||
|
private MenuItem importAllMenuItem;
|
||||||
|
private MenuItem deleteAllMenuItem;
|
||||||
|
private final OnClickListener stopListener = new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
updateMenuItems(false, false);
|
||||||
|
TrackRecordingServiceConnectionUtils.stopRecording(
|
||||||
|
TrackListActivity.this, trackRecordingServiceConnection, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private boolean startGps = false; // true to start gps
|
||||||
|
private boolean startNewRecording = false; // true to start a new recording
|
||||||
// Callback when the trackRecordingServiceConnection binding changes.
|
// Callback when the trackRecordingServiceConnection binding changes.
|
||||||
private final Runnable bindChangedCallback = new Runnable() {
|
private final Runnable bindChangedCallback = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@@ -130,68 +233,6 @@ public class TrackListActivity extends AbstractTrackActivity implements FileType
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Note that sharedPreferenceChangeListenr cannot be an anonymous inner class.
|
|
||||||
* Anonymous inner class will get garbage collected.
|
|
||||||
*/
|
|
||||||
private final OnSharedPreferenceChangeListener
|
|
||||||
sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
|
||||||
if (key == null || key.equals(
|
|
||||||
PreferencesUtils.getKey(TrackListActivity.this, R.string.stats_units_key))) {
|
|
||||||
metricUnits = PreferencesUtils.isMetricUnits(TrackListActivity.this);
|
|
||||||
}
|
|
||||||
if (key == null || key.equals(
|
|
||||||
PreferencesUtils.getKey(TrackListActivity.this, R.string.recording_track_id_key))) {
|
|
||||||
recordingTrackId = PreferencesUtils.getLong(
|
|
||||||
TrackListActivity.this, R.string.recording_track_id_key);
|
|
||||||
if (key != null && recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
|
|
||||||
trackRecordingServiceConnection.startAndBind();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (key == null || key.equals(PreferencesUtils.getKey(
|
|
||||||
TrackListActivity.this, R.string.recording_track_paused_key))) {
|
|
||||||
recordingTrackPaused = PreferencesUtils.getBoolean(TrackListActivity.this,
|
|
||||||
R.string.recording_track_paused_key,
|
|
||||||
PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT);
|
|
||||||
}
|
|
||||||
if (key != null) {
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
TrackListActivity.this.invalidateOptionsMenu();
|
|
||||||
LoaderManager.getInstance(TrackListActivity.this).restartLoader(0, null, loaderCallbacks);
|
|
||||||
boolean isRecording = recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
|
||||||
trackController.update(isRecording, recordingTrackPaused);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Callback when an item is selected in the contextual action mode
|
|
||||||
private final ContextualActionModeCallback
|
|
||||||
contextualActionModeCallback = new ContextualActionModeCallback() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPrepare(Menu menu, int[] positions, long[] ids, boolean showSelectAll) {
|
|
||||||
boolean isRecording = recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
|
||||||
boolean isSingleSelection = ids.length == 1;
|
|
||||||
|
|
||||||
menu.findItem(R.id.list_context_menu_share).setVisible(!isRecording && isSingleSelection);
|
|
||||||
menu.findItem(R.id.list_context_menu_show_on_map).setVisible(false);
|
|
||||||
menu.findItem(R.id.list_context_menu_edit).setVisible(isSingleSelection);
|
|
||||||
menu.findItem(R.id.list_context_menu_select_all).setVisible(showSelectAll);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onClick(int itemId, int[] positions, long[] ids) {
|
|
||||||
return handleContextItem(itemId, ids);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final OnClickListener recordListener = new OnClickListener() {
|
private final OnClickListener recordListener = new OnClickListener() {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (recordingTrackId == PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
|
if (recordingTrackId == PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
|
||||||
@@ -214,57 +255,6 @@ public class TrackListActivity extends AbstractTrackActivity implements FileType
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final OnClickListener stopListener = new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
updateMenuItems(false, false);
|
|
||||||
TrackRecordingServiceConnectionUtils.stopRecording(
|
|
||||||
TrackListActivity.this, trackRecordingServiceConnection, true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final LoaderCallbacks<Cursor> loaderCallbacks = new LoaderCallbacks<Cursor>() {
|
|
||||||
@Override
|
|
||||||
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
|
||||||
return new CursorLoader(TrackListActivity.this, TracksColumns.CONTENT_URI, PROJECTION, null,
|
|
||||||
null, TrackUtils.TRACK_SORT_ORDER);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor cursor) {
|
|
||||||
resourceCursorAdapter.swapCursor(cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoaderReset(@NonNull Loader<Cursor> loader) {
|
|
||||||
resourceCursorAdapter.swapCursor(null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// The following are set in onCreate
|
|
||||||
private ContentProviderUtils contentProviderUtils;
|
|
||||||
private SharedPreferences sharedPreferences;
|
|
||||||
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
|
||||||
private TrackController trackController;
|
|
||||||
private ListView listView;
|
|
||||||
private ResourceCursorAdapter resourceCursorAdapter;
|
|
||||||
|
|
||||||
// Preferences
|
|
||||||
private boolean metricUnits = true;
|
|
||||||
private long recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
|
||||||
private boolean recordingTrackPaused = PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT;
|
|
||||||
|
|
||||||
// Menu items
|
|
||||||
private MenuItem searchMenuItem;
|
|
||||||
private MenuItem startGpsMenuItem;
|
|
||||||
private MenuItem aggregatedStatisticsMenuItem;
|
|
||||||
private MenuItem exportAllMenuItem;
|
|
||||||
private MenuItem importAllMenuItem;
|
|
||||||
private MenuItem deleteAllMenuItem;
|
|
||||||
|
|
||||||
private boolean startGps = false; // true to start gps
|
|
||||||
private boolean startNewRecording = false; // true to start a new recording
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|||||||
@@ -16,14 +16,14 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.content;
|
package com.google.android.apps.mytracks.content;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.location.LocationManager;
|
import android.location.LocationManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -39,6 +39,15 @@ public interface ContentProviderUtils {
|
|||||||
* provider.
|
* provider.
|
||||||
*/
|
*/
|
||||||
String AUTHORITY = "com.google.android.maps.mytracks";
|
String AUTHORITY = "com.google.android.maps.mytracks";
|
||||||
|
/**
|
||||||
|
* The default {@link LocationFactory} which creates a location each time.
|
||||||
|
*/
|
||||||
|
LocationFactory DEFAULT_LOCATION_FACTORY = new LocationFactory() {
|
||||||
|
@Override
|
||||||
|
public Location createLocation() {
|
||||||
|
return new SensorDataSetLocation(LocationManager.GPS_PROVIDER);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears a track. Removes waypoints and trackpoints. Only keeps the track id.
|
* Clears a track. Removes waypoints and trackpoints. Only keeps the track id.
|
||||||
@@ -267,7 +276,6 @@ public interface ContentProviderUtils {
|
|||||||
*/
|
*/
|
||||||
Location getLastValidTrackPoint(long trackId);
|
Location getLastValidTrackPoint(long trackId);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the last valid location.
|
* Gets the last valid location.
|
||||||
*/
|
*/
|
||||||
@@ -344,16 +352,6 @@ public interface ContentProviderUtils {
|
|||||||
Location createLocation();
|
Location createLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The default {@link LocationFactory} which creates a location each time.
|
|
||||||
*/
|
|
||||||
LocationFactory DEFAULT_LOCATION_FACTORY = new LocationFactory() {
|
|
||||||
@Override
|
|
||||||
public Location createLocation() {
|
|
||||||
return new SensorDataSetLocation(LocationManager.GPS_PROVIDER);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A factory which can produce instances of {@link ContentProviderUtils}, and
|
* A factory which can produce instances of {@link ContentProviderUtils}, and
|
||||||
* can be overridden for testing.
|
* can be overridden for testing.
|
||||||
|
|||||||
+9
-9
@@ -1080,6 +1080,15 @@ public class ContentProviderUtilsImpl implements ContentProviderUtils {
|
|||||||
TrackPointsColumns.CONTENT_URI, projection, selection, selectionArgs, sortOrder);
|
TrackPointsColumns.CONTENT_URI, projection, selection, selectionArgs, sortOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the default cursor batch size. For testing purpose.
|
||||||
|
*
|
||||||
|
* @param defaultCursorBatchSize the default cursor batch size
|
||||||
|
*/
|
||||||
|
void setDefaultCursorBatchSize(int defaultCursorBatchSize) {
|
||||||
|
this.defaultCursorBatchSize = defaultCursorBatchSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A cache of track points indexes.
|
* A cache of track points indexes.
|
||||||
*/
|
*/
|
||||||
@@ -1110,13 +1119,4 @@ public class ContentProviderUtilsImpl implements ContentProviderUtils {
|
|||||||
sensorPowerIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_POWER);
|
sensorPowerIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_POWER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the default cursor batch size. For testing purpose.
|
|
||||||
*
|
|
||||||
* @param defaultCursorBatchSize the default cursor batch size
|
|
||||||
*/
|
|
||||||
void setDefaultCursorBatchSize(int defaultCursorBatchSize) {
|
|
||||||
this.defaultCursorBatchSize = defaultCursorBatchSize;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -23,8 +23,6 @@ package com.google.android.apps.mytracks.content;
|
|||||||
*/
|
*/
|
||||||
public class ContentTypeIds {
|
public class ContentTypeIds {
|
||||||
|
|
||||||
private ContentTypeIds() {}
|
|
||||||
|
|
||||||
public static final byte BOOLEAN_TYPE_ID = 0;
|
public static final byte BOOLEAN_TYPE_ID = 0;
|
||||||
public static final byte LONG_TYPE_ID = 1;
|
public static final byte LONG_TYPE_ID = 1;
|
||||||
public static final byte INT_TYPE_ID = 2;
|
public static final byte INT_TYPE_ID = 2;
|
||||||
@@ -32,4 +30,6 @@ public class ContentTypeIds {
|
|||||||
public static final byte DOUBLE_TYPE_ID = 4;
|
public static final byte DOUBLE_TYPE_ID = 4;
|
||||||
public static final byte STRING_TYPE_ID = 5;
|
public static final byte STRING_TYPE_ID = 5;
|
||||||
public static final byte BLOB_TYPE_ID = 6;
|
public static final byte BLOB_TYPE_ID = 6;
|
||||||
|
private ContentTypeIds() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,51 +49,11 @@ import java.io.FileNotFoundException;
|
|||||||
*/
|
*/
|
||||||
public class CustomContentProvider extends ContentProvider {
|
public class CustomContentProvider extends ContentProvider {
|
||||||
|
|
||||||
private static final String TAG = CustomContentProvider.class.getSimpleName();
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final int DATABASE_VERSION = 23;
|
static final int DATABASE_VERSION = 23;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final String DATABASE_NAME = "database.db";
|
static final String DATABASE_NAME = "database.db";
|
||||||
|
private static final String TAG = CustomContentProvider.class.getSimpleName();
|
||||||
/**
|
|
||||||
* Database helper for creating and upgrading the database.
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
static class DatabaseHelper extends SQLiteOpenHelper {
|
|
||||||
|
|
||||||
public DatabaseHelper(Context context) {
|
|
||||||
this(context, DATABASE_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
public DatabaseHelper(Context context, String databaseName) {
|
|
||||||
super(context, databaseName, null, DATABASE_VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(SQLiteDatabase db) {
|
|
||||||
db.execSQL(TrackPointsColumns.CREATE_TABLE);
|
|
||||||
db.execSQL(TracksColumns.CREATE_TABLE);
|
|
||||||
db.execSQL(WaypointsColumns.CREATE_TABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Types of url.
|
|
||||||
*
|
|
||||||
* @author Jimmy Shih
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
enum UrlType {
|
|
||||||
TRACKPOINTS, TRACKPOINTS_ID, TRACKS, TRACKS_ID, WAYPOINTS, WAYPOINTS_ID
|
|
||||||
}
|
|
||||||
|
|
||||||
private final UriMatcher uriMatcher;
|
private final UriMatcher uriMatcher;
|
||||||
private SQLiteDatabase db;
|
private SQLiteDatabase db;
|
||||||
|
|
||||||
@@ -415,4 +375,41 @@ public class CustomContentProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
throw new SQLException("Failed to insert a waypoint " + url);
|
throw new SQLException("Failed to insert a waypoint " + url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types of url.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
enum UrlType {
|
||||||
|
TRACKPOINTS, TRACKPOINTS_ID, TRACKS, TRACKS_ID, WAYPOINTS, WAYPOINTS_ID
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database helper for creating and upgrading the database.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
static class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
|
|
||||||
|
public DatabaseHelper(Context context) {
|
||||||
|
this(context, DATABASE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public DatabaseHelper(Context context, String databaseName) {
|
||||||
|
super(context, databaseName, null, DATABASE_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(SQLiteDatabase db) {
|
||||||
|
db.execSQL(TrackPointsColumns.CREATE_TABLE);
|
||||||
|
db.execSQL(TracksColumns.CREATE_TABLE);
|
||||||
|
db.execSQL(WaypointsColumns.CREATE_TABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.content;
|
package com.google.android.apps.mytracks.content;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
@@ -25,6 +23,8 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
|||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.Constants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data source on the phone.
|
* Data source on the phone.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -35,83 +35,15 @@ import java.util.Set;
|
|||||||
public class DataSourceManager {
|
public class DataSourceManager {
|
||||||
|
|
||||||
private static final String TAG = DataSourceManager.class.getSimpleName();
|
private static final String TAG = DataSourceManager.class.getSimpleName();
|
||||||
|
|
||||||
/**
|
|
||||||
* Observer when the tracks table is updated.
|
|
||||||
*
|
|
||||||
* @author Jimmy Shih
|
|
||||||
*/
|
|
||||||
private class TracksTableObserver extends ContentObserver {
|
|
||||||
|
|
||||||
public TracksTableObserver() {
|
|
||||||
super(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onChange(boolean selfChange) {
|
|
||||||
dataSourceListener.notifyTracksTableUpdated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Observer when the waypoints table is updated.
|
|
||||||
*
|
|
||||||
* @author Jimmy Shih
|
|
||||||
*/
|
|
||||||
private class WaypointsTableObserver extends ContentObserver {
|
|
||||||
|
|
||||||
public WaypointsTableObserver() {
|
|
||||||
super(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onChange(boolean selfChange) {
|
|
||||||
dataSourceListener.notifyWaypointsTableUpdated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Observer when the track points table is updated.
|
|
||||||
*
|
|
||||||
* @author Jimmy Shih
|
|
||||||
*/
|
|
||||||
private class TrackPointsTableObserver extends ContentObserver {
|
|
||||||
|
|
||||||
public TrackPointsTableObserver() {
|
|
||||||
super(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onChange(boolean selfChange) {
|
|
||||||
dataSourceListener.notifyTrackPointsTableUpdated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener for preference changes.
|
|
||||||
*
|
|
||||||
* @author Jimmy Shih
|
|
||||||
*/
|
|
||||||
private class PreferenceListener implements OnSharedPreferenceChangeListener {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
|
||||||
dataSourceListener.notifyPreferenceChanged(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final DataSource dataSource;
|
private final DataSource dataSource;
|
||||||
private final DataSourceListener dataSourceListener;
|
private final DataSourceListener dataSourceListener;
|
||||||
|
|
||||||
// Registered listeners
|
// Registered listeners
|
||||||
private final Set<TrackDataType> registeredListeners = EnumSet.noneOf(TrackDataType.class);
|
private final Set<TrackDataType> registeredListeners = EnumSet.noneOf(TrackDataType.class);
|
||||||
|
|
||||||
private final Handler handler;
|
private final Handler handler;
|
||||||
private final TracksTableObserver tracksTableObserver;
|
private final TracksTableObserver tracksTableObserver;
|
||||||
private final WaypointsTableObserver waypointsTableObserver;
|
private final WaypointsTableObserver waypointsTableObserver;
|
||||||
private final TrackPointsTableObserver trackPointsTableObserver;
|
private final TrackPointsTableObserver trackPointsTableObserver;
|
||||||
private final PreferenceListener preferenceListener;
|
private final PreferenceListener preferenceListener;
|
||||||
|
|
||||||
public DataSourceManager(DataSource dataSource, DataSourceListener dataSourceListener) {
|
public DataSourceManager(DataSource dataSource, DataSourceListener dataSourceListener) {
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
this.dataSourceListener = dataSourceListener;
|
this.dataSourceListener = dataSourceListener;
|
||||||
@@ -228,4 +160,68 @@ public class DataSourceManager {
|
|||||||
unregisterListener(trackDataType);
|
unregisterListener(trackDataType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observer when the tracks table is updated.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
private class TracksTableObserver extends ContentObserver {
|
||||||
|
|
||||||
|
public TracksTableObserver() {
|
||||||
|
super(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChange(boolean selfChange) {
|
||||||
|
dataSourceListener.notifyTracksTableUpdated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observer when the waypoints table is updated.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
private class WaypointsTableObserver extends ContentObserver {
|
||||||
|
|
||||||
|
public WaypointsTableObserver() {
|
||||||
|
super(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChange(boolean selfChange) {
|
||||||
|
dataSourceListener.notifyWaypointsTableUpdated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observer when the track points table is updated.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
private class TrackPointsTableObserver extends ContentObserver {
|
||||||
|
|
||||||
|
public TrackPointsTableObserver() {
|
||||||
|
super(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChange(boolean selfChange) {
|
||||||
|
dataSourceListener.notifyTrackPointsTableUpdated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for preference changes.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
private class PreferenceListener implements OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
|
dataSourceListener.notifyPreferenceChanged(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.google.android.apps.mytracks.content;
|
package com.google.android.apps.mytracks.content;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
|
|||||||
@@ -38,94 +38,69 @@ import java.util.TreeSet;
|
|||||||
*/
|
*/
|
||||||
public class SearchEngine {
|
public class SearchEngine {
|
||||||
|
|
||||||
/** WHERE query to get tracks by name. */
|
/**
|
||||||
|
* WHERE query to get tracks by name.
|
||||||
|
*/
|
||||||
private static final String TRACK_SELECTION_QUERY =
|
private static final String TRACK_SELECTION_QUERY =
|
||||||
TracksColumns.NAME + " LIKE ? OR " +
|
TracksColumns.NAME + " LIKE ? OR " +
|
||||||
TracksColumns.DESCRIPTION + " LIKE ? OR " +
|
TracksColumns.DESCRIPTION + " LIKE ? OR " +
|
||||||
TracksColumns.CATEGORY + " LIKE ?";
|
TracksColumns.CATEGORY + " LIKE ?";
|
||||||
|
|
||||||
/** WHERE query to get waypoints by name. */
|
/**
|
||||||
|
* WHERE query to get waypoints by name.
|
||||||
|
*/
|
||||||
private static final String WAYPOINT_SELECTION_QUERY =
|
private static final String WAYPOINT_SELECTION_QUERY =
|
||||||
WaypointsColumns.NAME + " LIKE ? OR " +
|
WaypointsColumns.NAME + " LIKE ? OR " +
|
||||||
WaypointsColumns.DESCRIPTION + " LIKE ? OR " +
|
WaypointsColumns.DESCRIPTION + " LIKE ? OR " +
|
||||||
WaypointsColumns.CATEGORY + " LIKE ?";
|
WaypointsColumns.CATEGORY + " LIKE ?";
|
||||||
|
|
||||||
/** Order of track results. */
|
/**
|
||||||
|
* Order of track results.
|
||||||
|
*/
|
||||||
private static final String TRACK_SELECTION_ORDER = TracksColumns._ID + " DESC LIMIT 1000";
|
private static final String TRACK_SELECTION_ORDER = TracksColumns._ID + " DESC LIMIT 1000";
|
||||||
|
|
||||||
/** Order of waypoint results. */
|
/**
|
||||||
|
* Order of waypoint results.
|
||||||
|
*/
|
||||||
private static final String WAYPOINT_SELECTION_ORDER = WaypointsColumns._ID + " DESC";
|
private static final String WAYPOINT_SELECTION_ORDER = WaypointsColumns._ID + " DESC";
|
||||||
|
|
||||||
/** How much we promote a match in the track category. */
|
/**
|
||||||
|
* How much we promote a match in the track category.
|
||||||
|
*/
|
||||||
private static final double TRACK_CATEGORY_PROMOTION = 2.0;
|
private static final double TRACK_CATEGORY_PROMOTION = 2.0;
|
||||||
|
|
||||||
/** How much we promote a match in the track description. */
|
/**
|
||||||
|
* How much we promote a match in the track description.
|
||||||
|
*/
|
||||||
private static final double TRACK_DESCRIPTION_PROMOTION = 8.0;
|
private static final double TRACK_DESCRIPTION_PROMOTION = 8.0;
|
||||||
|
|
||||||
/** How much we promote a match in the track name. */
|
/**
|
||||||
|
* How much we promote a match in the track name.
|
||||||
|
*/
|
||||||
private static final double TRACK_NAME_PROMOTION = 16.0;
|
private static final double TRACK_NAME_PROMOTION = 16.0;
|
||||||
|
|
||||||
/** How much we promote a waypoint result if it's in the currently-selected track. */
|
/**
|
||||||
|
* How much we promote a waypoint result if it's in the currently-selected track.
|
||||||
|
*/
|
||||||
private static final double CURRENT_TRACK_WAYPOINT_PROMOTION = 2.0;
|
private static final double CURRENT_TRACK_WAYPOINT_PROMOTION = 2.0;
|
||||||
|
|
||||||
/** How much we promote a track result if it's the currently-selected track. */
|
/**
|
||||||
|
* How much we promote a track result if it's the currently-selected track.
|
||||||
|
*/
|
||||||
private static final double CURRENT_TRACK_DEMOTION = 0.5;
|
private static final double CURRENT_TRACK_DEMOTION = 0.5;
|
||||||
|
|
||||||
/** Maximum number of waypoints which will be retrieved and scored. */
|
/**
|
||||||
|
* Maximum number of waypoints which will be retrieved and scored.
|
||||||
|
*/
|
||||||
private static final int MAX_SCORED_WAYPOINTS = 100;
|
private static final int MAX_SCORED_WAYPOINTS = 100;
|
||||||
|
|
||||||
/** Oldest timestamp for which we rank based on time (2000-01-01 00:00:00.000) */
|
/**
|
||||||
|
* Oldest timestamp for which we rank based on time (2000-01-01 00:00:00.000)
|
||||||
|
*/
|
||||||
private static final long OLDEST_ALLOWED_TIMESTAMP = 946692000000L;
|
private static final long OLDEST_ALLOWED_TIMESTAMP = 946692000000L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description of a search query, along with all contextual data needed to execute it.
|
* Comparador for scored results.
|
||||||
*/
|
*/
|
||||||
public static class SearchQuery {
|
|
||||||
public SearchQuery(String textQuery, Location currentLocation, long currentTrackId,
|
|
||||||
long currentTimestamp) {
|
|
||||||
this.textQuery = textQuery.toLowerCase(Locale.getDefault());
|
|
||||||
this.currentLocation = currentLocation;
|
|
||||||
this.currentTrackId = currentTrackId;
|
|
||||||
this.currentTimestamp = currentTimestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String textQuery;
|
|
||||||
public final Location currentLocation;
|
|
||||||
public final long currentTrackId;
|
|
||||||
public final long currentTimestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description of a search result which has been retrieved and scored.
|
|
||||||
*/
|
|
||||||
public static class ScoredResult {
|
|
||||||
ScoredResult(Track track, double score) {
|
|
||||||
this.track = track;
|
|
||||||
this.waypoint = null;
|
|
||||||
this.score = score;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScoredResult(Waypoint waypoint, double score) {
|
|
||||||
this.track = null;
|
|
||||||
this.waypoint = waypoint;
|
|
||||||
this.score = score;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final Track track;
|
|
||||||
public final Waypoint waypoint;
|
|
||||||
public final double score;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "ScoredResult ["
|
|
||||||
+ (track != null ? ("trackId=" + track.getId() + ", ") : "")
|
|
||||||
+ (waypoint != null ? ("wptId=" + waypoint.getId() + ", ") : "")
|
|
||||||
+ "score=" + score + "]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Comparador for scored results. */
|
|
||||||
private static final Comparator<ScoredResult> SCORED_RESULT_COMPARATOR =
|
private static final Comparator<ScoredResult> SCORED_RESULT_COMPARATOR =
|
||||||
new Comparator<ScoredResult>() {
|
new Comparator<ScoredResult>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -150,13 +125,19 @@ public class SearchEngine {
|
|||||||
return Long.signum(idDiff);
|
return Long.signum(idDiff);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final ContentProviderUtils providerUtils;
|
private final ContentProviderUtils providerUtils;
|
||||||
|
|
||||||
public SearchEngine(ContentProviderUtils providerUtils) {
|
public SearchEngine(ContentProviderUtils providerUtils) {
|
||||||
this.providerUtils = providerUtils;
|
this.providerUtils = providerUtils;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Squashes a number by calculating 1 / log (1 + x).
|
||||||
|
*/
|
||||||
|
private static double squash(double x) {
|
||||||
|
return 1.0 / Math.log1p(x);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes a search query and returns a set of sorted results.
|
* Executes a search query and returns a set of sorted results.
|
||||||
*
|
*
|
||||||
@@ -393,9 +374,47 @@ public class SearchEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Squashes a number by calculating 1 / log (1 + x).
|
* Description of a search query, along with all contextual data needed to execute it.
|
||||||
*/
|
*/
|
||||||
private static double squash(double x) {
|
public static class SearchQuery {
|
||||||
return 1.0 / Math.log1p(x);
|
public final String textQuery;
|
||||||
|
public final Location currentLocation;
|
||||||
|
public final long currentTrackId;
|
||||||
|
public final long currentTimestamp;
|
||||||
|
public SearchQuery(String textQuery, Location currentLocation, long currentTrackId,
|
||||||
|
long currentTimestamp) {
|
||||||
|
this.textQuery = textQuery.toLowerCase(Locale.getDefault());
|
||||||
|
this.currentLocation = currentLocation;
|
||||||
|
this.currentTrackId = currentTrackId;
|
||||||
|
this.currentTimestamp = currentTimestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description of a search result which has been retrieved and scored.
|
||||||
|
*/
|
||||||
|
public static class ScoredResult {
|
||||||
|
public final Track track;
|
||||||
|
public final Waypoint waypoint;
|
||||||
|
public final double score;
|
||||||
|
ScoredResult(Track track, double score) {
|
||||||
|
this.track = track;
|
||||||
|
this.waypoint = null;
|
||||||
|
this.score = score;
|
||||||
|
}
|
||||||
|
ScoredResult(Waypoint waypoint, double score) {
|
||||||
|
this.track = null;
|
||||||
|
this.waypoint = waypoint;
|
||||||
|
this.score = score;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ScoredResult ["
|
||||||
|
+ (track != null ? ("trackId=" + track.getId() + ", ") : "")
|
||||||
|
+ (waypoint != null ? ("wptId=" + waypoint.getId() + ", ") : "")
|
||||||
|
+ "score=" + score + "]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,12 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.content;
|
package com.google.android.apps.mytracks.content;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
|
||||||
|
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,13 +32,23 @@ import java.util.ArrayList;
|
|||||||
*/
|
*/
|
||||||
public class Track implements Parcelable {
|
public class Track implements Parcelable {
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<Track> CREATOR = new Parcelable.Creator<Track>() {
|
||||||
|
@Override
|
||||||
|
public Track createFromParcel(Parcel in) {
|
||||||
|
return new Track(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Track[] newArray(int size) {
|
||||||
|
return new Track[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
private long id = -1L;
|
private long id = -1L;
|
||||||
private String name = "";
|
private String name = "";
|
||||||
private String description = "";
|
private String description = "";
|
||||||
private String category = "";
|
private String category = "";
|
||||||
private long startId = -1L;
|
private long startId = -1L;
|
||||||
private long stopId = -1L;
|
private long stopId = -1L;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The number of location points (present even if the points themselves are
|
* The number of location points (present even if the points themselves are
|
||||||
* not loaded)
|
* not loaded)
|
||||||
@@ -46,13 +56,12 @@ public class Track implements Parcelable {
|
|||||||
private int numberOfPoints = 0;
|
private int numberOfPoints = 0;
|
||||||
private String icon = "";
|
private String icon = "";
|
||||||
private long modifiedTime = -1L;
|
private long modifiedTime = -1L;
|
||||||
|
|
||||||
private TripStatistics tripStatistics = new TripStatistics();
|
private TripStatistics tripStatistics = new TripStatistics();
|
||||||
|
|
||||||
// Location points (which may not have been loaded)
|
// Location points (which may not have been loaded)
|
||||||
private ArrayList<Location> locations = new ArrayList<>();
|
private ArrayList<Location> locations = new ArrayList<>();
|
||||||
|
|
||||||
public Track() {}
|
public Track() {
|
||||||
|
}
|
||||||
|
|
||||||
private Track(Parcel in) {
|
private Track(Parcel in) {
|
||||||
id = in.readLong();
|
id = in.readLong();
|
||||||
@@ -97,18 +106,6 @@ public class Track implements Parcelable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Parcelable.Creator<Track> CREATOR = new Parcelable.Creator<Track>() {
|
|
||||||
@Override
|
|
||||||
public Track createFromParcel(Parcel in) {
|
|
||||||
return new Track(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Track[] newArray(int size) {
|
|
||||||
return new Track[size];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public long getId() {
|
public long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,20 +42,17 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public class TrackDataHub implements DataSourceListener {
|
public class TrackDataHub implements DataSourceListener {
|
||||||
|
|
||||||
private static final String TAG = TrackDataHub.class.getSimpleName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum number of waypoints to displayed.
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
static final int MAX_DISPLAYED_WAYPOINTS = 128;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Target number of track points displayed by the map overlay. We may display
|
* Target number of track points displayed by the map overlay. We may display
|
||||||
* more than this number of points.
|
* more than this number of points.
|
||||||
*/
|
*/
|
||||||
public static final int TARGET_DISPLAYED_TRACK_POINTS = 5000;
|
public static final int TARGET_DISPLAYED_TRACK_POINTS = 5000;
|
||||||
|
/**
|
||||||
|
* Maximum number of waypoints to displayed.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
static final int MAX_DISPLAYED_WAYPOINTS = 128;
|
||||||
|
private static final String TAG = TrackDataHub.class.getSimpleName();
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final TrackDataManager trackDataManager;
|
private final TrackDataManager trackDataManager;
|
||||||
private final ContentProviderUtils contentProviderUtils;
|
private final ContentProviderUtils contentProviderUtils;
|
||||||
@@ -81,14 +78,6 @@ public class TrackDataHub implements DataSourceListener {
|
|||||||
private long firstSeenLocationId;
|
private long firstSeenLocationId;
|
||||||
private long lastSeenLocationId;
|
private long lastSeenLocationId;
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance.
|
|
||||||
*/
|
|
||||||
public synchronized static TrackDataHub newInstance(Context context) {
|
|
||||||
return new TrackDataHub(context, new TrackDataManager(), ContentProviderUtils.Factory.get(
|
|
||||||
context), TARGET_DISPLAYED_TRACK_POINTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
@@ -107,6 +96,14 @@ public class TrackDataHub implements DataSourceListener {
|
|||||||
resetSamplingState();
|
resetSamplingState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance.
|
||||||
|
*/
|
||||||
|
public synchronized static TrackDataHub newInstance(Context context) {
|
||||||
|
return new TrackDataHub(context, new TrackDataManager(), ContentProviderUtils.Factory.get(
|
||||||
|
context), TARGET_DISPLAYED_TRACK_POINTS);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts.
|
* Starts.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -31,10 +31,17 @@ import com.google.android.apps.mytracks.stats.TripStatistics;
|
|||||||
*/
|
*/
|
||||||
public final class Waypoint implements Parcelable {
|
public final class Waypoint implements Parcelable {
|
||||||
|
|
||||||
public enum WaypointType {
|
public static final Parcelable.Creator<Waypoint> CREATOR = new Parcelable.Creator<Waypoint>() {
|
||||||
WAYPOINT, STATISTICS
|
@Override
|
||||||
|
public Waypoint createFromParcel(Parcel in) {
|
||||||
|
return new Waypoint(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Waypoint[] newArray(int size) {
|
||||||
|
return new Waypoint[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
private long id = -1L;
|
private long id = -1L;
|
||||||
private String name = "";
|
private String name = "";
|
||||||
private String description = "";
|
private String description = "";
|
||||||
@@ -50,7 +57,8 @@ public final class Waypoint implements Parcelable {
|
|||||||
private TripStatistics tripStatistics = null;
|
private TripStatistics tripStatistics = null;
|
||||||
private String photoUrl = "";
|
private String photoUrl = "";
|
||||||
|
|
||||||
public Waypoint() {}
|
public Waypoint() {
|
||||||
|
}
|
||||||
|
|
||||||
public Waypoint(String name, String description, String category, String icon, long trackId,
|
public Waypoint(String name, String description, String category, String icon, long trackId,
|
||||||
WaypointType type, double length, long duration, long startId, long stopId, Location location,
|
WaypointType type, double length, long duration, long startId, long stopId, Location location,
|
||||||
@@ -124,18 +132,6 @@ public final class Waypoint implements Parcelable {
|
|||||||
dest.writeString(photoUrl);
|
dest.writeString(photoUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Parcelable.Creator<Waypoint> CREATOR = new Parcelable.Creator<Waypoint>() {
|
|
||||||
@Override
|
|
||||||
public Waypoint createFromParcel(Parcel in) {
|
|
||||||
return new Waypoint(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Waypoint[] newArray(int size) {
|
|
||||||
return new Waypoint[size];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public long getId() {
|
public long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@@ -244,6 +240,10 @@ public final class Waypoint implements Parcelable {
|
|||||||
return photoUrl;
|
return photoUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPhotoUrl(String photoUrl) {
|
||||||
|
this.photoUrl = photoUrl;
|
||||||
|
}
|
||||||
|
|
||||||
public Uri getPhotoURI() {
|
public Uri getPhotoURI() {
|
||||||
return Uri.parse(photoUrl);
|
return Uri.parse(photoUrl);
|
||||||
}
|
}
|
||||||
@@ -252,7 +252,7 @@ public final class Waypoint implements Parcelable {
|
|||||||
return photoUrl != null && !"".equals(photoUrl);
|
return photoUrl != null && !"".equals(photoUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPhotoUrl(String photoUrl) {
|
public enum WaypointType {
|
||||||
this.photoUrl = photoUrl;
|
WAYPOINT, STATISTICS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-30
@@ -15,11 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.content;
|
package com.google.android.apps.mytracks.content;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
|
||||||
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A request for the service to create a waypoint at the current location.
|
* A request for the service to create a waypoint at the current location.
|
||||||
*
|
*
|
||||||
@@ -27,6 +27,13 @@ import android.os.Parcelable;
|
|||||||
*/
|
*/
|
||||||
public class WaypointCreationRequest implements Parcelable {
|
public class WaypointCreationRequest implements Parcelable {
|
||||||
|
|
||||||
|
public final static WaypointCreationRequest DEFAULT_WAYPOINT = new WaypointCreationRequest(
|
||||||
|
WaypointType.WAYPOINT, false);
|
||||||
|
public final static WaypointCreationRequest DEFAULT_STATISTICS = new WaypointCreationRequest(
|
||||||
|
WaypointType.STATISTICS, false);
|
||||||
|
public final static WaypointCreationRequest DEFAULT_START_TRACK = new WaypointCreationRequest(
|
||||||
|
WaypointType.STATISTICS, true);
|
||||||
|
public static final Creator CREATOR = new Creator();
|
||||||
private WaypointType type;
|
private WaypointType type;
|
||||||
// true if this marker contains the track statistics
|
// true if this marker contains the track statistics
|
||||||
private boolean isTrackStatistics;
|
private boolean isTrackStatistics;
|
||||||
@@ -36,13 +43,6 @@ public class WaypointCreationRequest implements Parcelable {
|
|||||||
private String iconUrl;
|
private String iconUrl;
|
||||||
private String photoUrl;
|
private String photoUrl;
|
||||||
|
|
||||||
public final static WaypointCreationRequest DEFAULT_WAYPOINT = new WaypointCreationRequest(
|
|
||||||
WaypointType.WAYPOINT, false);
|
|
||||||
public final static WaypointCreationRequest DEFAULT_STATISTICS = new WaypointCreationRequest(
|
|
||||||
WaypointType.STATISTICS, false);
|
|
||||||
public final static WaypointCreationRequest DEFAULT_START_TRACK = new WaypointCreationRequest(
|
|
||||||
WaypointType.STATISTICS, true);
|
|
||||||
|
|
||||||
private WaypointCreationRequest(WaypointType type, boolean isTrackStatistics) {
|
private WaypointCreationRequest(WaypointType type, boolean isTrackStatistics) {
|
||||||
this(type, isTrackStatistics, null, null, null, null, null);
|
this(type, isTrackStatistics, null, null, null, null, null);
|
||||||
}
|
}
|
||||||
@@ -58,27 +58,6 @@ public class WaypointCreationRequest implements Parcelable {
|
|||||||
this.photoUrl = photoUrl;
|
this.photoUrl = photoUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Creator implements Parcelable.Creator<WaypointCreationRequest> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WaypointCreationRequest createFromParcel(Parcel source) {
|
|
||||||
return new WaypointCreationRequest(
|
|
||||||
WaypointType.values()[source.readInt()],
|
|
||||||
source.readByte() == 1,
|
|
||||||
source.readString(),
|
|
||||||
source.readString(),
|
|
||||||
source.readString(),
|
|
||||||
source.readString(),
|
|
||||||
source.readString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public WaypointCreationRequest[] newArray(int size) {
|
|
||||||
return new WaypointCreationRequest[size];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final Creator CREATOR = new Creator();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -122,4 +101,23 @@ public class WaypointCreationRequest implements Parcelable {
|
|||||||
public String getPhotoUrl() {
|
public String getPhotoUrl() {
|
||||||
return photoUrl;
|
return photoUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Creator implements Parcelable.Creator<WaypointCreationRequest> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WaypointCreationRequest createFromParcel(Parcel source) {
|
||||||
|
return new WaypointCreationRequest(
|
||||||
|
WaypointType.values()[source.readInt()],
|
||||||
|
source.readByte() == 1,
|
||||||
|
source.readString(),
|
||||||
|
source.readString(),
|
||||||
|
source.readString(),
|
||||||
|
source.readString(),
|
||||||
|
source.readString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public WaypointCreationRequest[] newArray(int size) {
|
||||||
|
return new WaypointCreationRequest[size];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -5,16 +5,14 @@ public final class SensorDataSet {
|
|||||||
public static final float DATA_UNAVAILABLE = Integer.MAX_VALUE;
|
public static final float DATA_UNAVAILABLE = Integer.MAX_VALUE;
|
||||||
|
|
||||||
//TODO It might be necessary to consider: sensor if sensor was connected as well.
|
//TODO It might be necessary to consider: sensor if sensor was connected as well.
|
||||||
|
public String sensorName;
|
||||||
|
public String sensorAddress;
|
||||||
private float heartRate;
|
private float heartRate;
|
||||||
private float cadence;
|
private float cadence;
|
||||||
private float power;
|
private float power;
|
||||||
private float batteryLevel;
|
private float batteryLevel;
|
||||||
private long creationTimestamp;
|
private long creationTimestamp;
|
||||||
|
|
||||||
public String sensorName;
|
|
||||||
public String sensorAddress;
|
|
||||||
|
|
||||||
public SensorDataSet(float heartRate, float cadence, float power, float batteryLevel, long creationTimestamp) {
|
public SensorDataSet(float heartRate, float cadence, float power, float batteryLevel, long creationTimestamp) {
|
||||||
this.heartRate = heartRate;
|
this.heartRate = heartRate;
|
||||||
this.cadence = cadence;
|
this.cadence = cadence;
|
||||||
@@ -71,6 +69,7 @@ public final class SensorDataSet {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the data recent considering the current time.
|
* Is the data recent considering the current time.
|
||||||
|
*
|
||||||
* @param maxAge the maximal age in milliseconds.
|
* @param maxAge the maximal age in milliseconds.
|
||||||
*/
|
*/
|
||||||
public boolean isRecent(long maxAge) {
|
public boolean isRecent(long maxAge) {
|
||||||
|
|||||||
+3
-3
@@ -16,16 +16,16 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.fragments;
|
package com.google.android.apps.mytracks.fragments;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.util.DialogUtils;
|
|
||||||
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
|
||||||
/**
|
import com.google.android.apps.mytracks.util.DialogUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
* @author Jimmy Shih
|
* @author Jimmy Shih
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractDialogFragment extends DialogFragment {
|
public abstract class AbstractDialogFragment extends DialogFragment {
|
||||||
|
|||||||
+29
-31
@@ -46,23 +46,8 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class ChooseActivityTypeDialogFragment extends DialogFragment {
|
public class ChooseActivityTypeDialogFragment extends DialogFragment {
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for caller of this dialog fragment.
|
|
||||||
*
|
|
||||||
* @author apoorvn
|
|
||||||
*/
|
|
||||||
public interface ChooseActivityTypeCaller {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when choose activity type is done.
|
|
||||||
*/
|
|
||||||
void onChooseActivityTypeDone(String iconValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String CHOOSE_ACTIVITY_TYPE_DIALOG_TAG = "chooseActivityType";
|
public static final String CHOOSE_ACTIVITY_TYPE_DIALOG_TAG = "chooseActivityType";
|
||||||
|
|
||||||
private static final String KEY_CATEGORY = "category";
|
private static final String KEY_CATEGORY = "category";
|
||||||
|
|
||||||
private ChooseActivityTypeCaller caller;
|
private ChooseActivityTypeCaller caller;
|
||||||
|
|
||||||
public static ChooseActivityTypeDialogFragment newInstance(String category) {
|
public static ChooseActivityTypeDialogFragment newInstance(String category) {
|
||||||
@@ -74,22 +59,6 @@ public class ChooseActivityTypeDialogFragment extends DialogFragment {
|
|||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(Context context) {
|
|
||||||
super.onAttach(context);
|
|
||||||
try {
|
|
||||||
caller = (ChooseActivityTypeCaller) context;
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
throw new ClassCastException(context + " must implement " + ChooseActivityTypeCaller.class.getSimpleName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
return getDialog(getActivity(), getArguments().getString(KEY_CATEGORY), caller);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Dialog getDialog(final Activity activity, final String category, final ChooseActivityTypeCaller caller) {
|
public static Dialog getDialog(final Activity activity, final String category, final ChooseActivityTypeCaller caller) {
|
||||||
View view = activity.getLayoutInflater().inflate(R.layout.choose_activity_type, null);
|
View view = activity.getLayoutInflater().inflate(R.layout.choose_activity_type, null);
|
||||||
GridView gridView = view.findViewById(R.id.choose_activity_type_grid_view);
|
GridView gridView = view.findViewById(R.id.choose_activity_type_grid_view);
|
||||||
@@ -154,4 +123,33 @@ public class ChooseActivityTypeDialogFragment extends DialogFragment {
|
|||||||
boolean showWeight = position == 0 || position == 1 || position == 2;
|
boolean showWeight = position == 0 || position == 1 || position == 2;
|
||||||
weightContainer.setVisibility(showWeight ? View.VISIBLE : View.GONE);
|
weightContainer.setVisibility(showWeight ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
try {
|
||||||
|
caller = (ChooseActivityTypeCaller) context;
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
throw new ClassCastException(context + " must implement " + ChooseActivityTypeCaller.class.getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
return getDialog(getActivity(), getArguments().getString(KEY_CATEGORY), caller);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for caller of this dialog fragment.
|
||||||
|
*
|
||||||
|
* @author apoorvn
|
||||||
|
*/
|
||||||
|
public interface ChooseActivityTypeCaller {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when choose activity type is done.
|
||||||
|
*/
|
||||||
|
void onChooseActivityTypeDone(String iconValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.fragments;
|
package com.google.android.apps.mytracks.fragments;
|
||||||
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -25,6 +23,8 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+17
-18
@@ -31,24 +31,9 @@ import com.google.android.maps.mytracks.R;
|
|||||||
*/
|
*/
|
||||||
public class ConfirmDeleteDialogFragment extends AbstractDialogFragment {
|
public class ConfirmDeleteDialogFragment extends AbstractDialogFragment {
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for caller of this dialog fragment.
|
|
||||||
*
|
|
||||||
* @author Jimmy Shih
|
|
||||||
*/
|
|
||||||
public interface ConfirmDeleteCaller {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when confirm delete is done.
|
|
||||||
*
|
|
||||||
* @param trackIds list of track ids to delete. To delete all, set to size 1
|
|
||||||
* with trackIds[0] == -1L
|
|
||||||
*/
|
|
||||||
void onConfirmDeleteDone(long[] trackIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String CONFIRM_DELETE_DIALOG_TAG = "confirmDeleteDialog";
|
public static final String CONFIRM_DELETE_DIALOG_TAG = "confirmDeleteDialog";
|
||||||
private static final String KEY_TRACK_IDS = "trackIds";
|
private static final String KEY_TRACK_IDS = "trackIds";
|
||||||
|
private ConfirmDeleteCaller caller;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance.
|
* Create a new instance.
|
||||||
@@ -65,8 +50,6 @@ public class ConfirmDeleteDialogFragment extends AbstractDialogFragment {
|
|||||||
return deleteTrackDialogFragment;
|
return deleteTrackDialogFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConfirmDeleteCaller caller;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context) {
|
public void onAttach(Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
@@ -94,4 +77,20 @@ public class ConfirmDeleteDialogFragment extends AbstractDialogFragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for caller of this dialog fragment.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public interface ConfirmDeleteCaller {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when confirm delete is done.
|
||||||
|
*
|
||||||
|
* @param trackIds list of track ids to delete. To delete all, set to size 1
|
||||||
|
* with trackIds[0] == -1L
|
||||||
|
*/
|
||||||
|
void onConfirmDeleteDone(long[] trackIds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+15
-16
@@ -23,8 +23,8 @@ import android.os.Bundle;
|
|||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
||||||
import com.google.android.apps.mytracks.util.DialogUtils;
|
import com.google.android.apps.mytracks.util.DialogUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
@@ -35,21 +35,9 @@ import com.google.android.maps.mytracks.R;
|
|||||||
*/
|
*/
|
||||||
public class DeleteMarkerDialogFragment extends AbstractDialogFragment {
|
public class DeleteMarkerDialogFragment extends AbstractDialogFragment {
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for caller of this dialog fragment.
|
|
||||||
*
|
|
||||||
* @author Jimmy Shih
|
|
||||||
*/
|
|
||||||
public interface DeleteMarkerCaller {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when delete marker is done.
|
|
||||||
*/
|
|
||||||
void onDeleteMarkerDone();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String DELETE_MARKER_DIALOG_TAG = "deleteMarkerDialog";
|
public static final String DELETE_MARKER_DIALOG_TAG = "deleteMarkerDialog";
|
||||||
private static final String KEY_MARKER_IDS = "markerIds";
|
private static final String KEY_MARKER_IDS = "markerIds";
|
||||||
|
private DeleteMarkerCaller caller;
|
||||||
|
|
||||||
public static DeleteMarkerDialogFragment newInstance(long[] markerIds) {
|
public static DeleteMarkerDialogFragment newInstance(long[] markerIds) {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
@@ -60,8 +48,6 @@ public class DeleteMarkerDialogFragment extends AbstractDialogFragment {
|
|||||||
return deleteMarkerDialogFragment;
|
return deleteMarkerDialogFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DeleteMarkerCaller caller;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context) {
|
public void onAttach(Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
@@ -106,4 +92,17 @@ public class DeleteMarkerDialogFragment extends AbstractDialogFragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for caller of this dialog fragment.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public interface DeleteMarkerCaller {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when delete marker is done.
|
||||||
|
*/
|
||||||
|
void onDeleteMarkerDone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+14
-16
@@ -34,24 +34,11 @@ import com.google.android.maps.mytracks.R;
|
|||||||
*/
|
*/
|
||||||
public class FileTypeDialogFragment extends AbstractDialogFragment {
|
public class FileTypeDialogFragment extends AbstractDialogFragment {
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for caller of this dialog fragment.
|
|
||||||
*
|
|
||||||
* @author Jimmy Shih
|
|
||||||
*/
|
|
||||||
public interface FileTypeCaller {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when file type selection is done.
|
|
||||||
*/
|
|
||||||
void onFileTypeDone(int menuId, TrackFileFormat trackFileFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String FILE_TYPE_DIALOG_TAG = "fileType";
|
public static final String FILE_TYPE_DIALOG_TAG = "fileType";
|
||||||
|
|
||||||
private static final String KEY_MENU_ID = "menuId";
|
private static final String KEY_MENU_ID = "menuId";
|
||||||
private static final String KEY_TITLE_ID = "titleId";
|
private static final String KEY_TITLE_ID = "titleId";
|
||||||
private static final String KEY_OPTION_ID = "optionId";
|
private static final String KEY_OPTION_ID = "optionId";
|
||||||
|
private FileTypeCaller caller;
|
||||||
|
|
||||||
public static FileTypeDialogFragment newInstance(int menuId, int titleId, int optionId) {
|
public static FileTypeDialogFragment newInstance(int menuId, int titleId, int optionId) {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
@@ -64,8 +51,6 @@ public class FileTypeDialogFragment extends AbstractDialogFragment {
|
|||||||
return fileTypeDialogFragment;
|
return fileTypeDialogFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
private FileTypeCaller caller;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context) {
|
public void onAttach(Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
@@ -97,4 +82,17 @@ public class FileTypeDialogFragment extends AbstractDialogFragment {
|
|||||||
}
|
}
|
||||||
}).setSingleChoiceItems(choices, 0, null).setTitle(titleId).create();
|
}).setSingleChoiceItems(choices, 0, null).setTitle(titleId).create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for caller of this dialog fragment.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public interface FileTypeCaller {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when file type selection is done.
|
||||||
|
*/
|
||||||
|
void onFileTypeDone(int menuId, TrackFileFormat trackFileFormat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+5
-4
@@ -16,16 +16,17 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.fragments;
|
package com.google.android.apps.mytracks.fragments;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A DialogFragment to configure frequency.
|
* A DialogFragment to configure frequency.
|
||||||
*
|
*
|
||||||
|
|||||||
+14
-14
@@ -57,28 +57,16 @@ import com.google.android.maps.mytracks.R;
|
|||||||
*/
|
*/
|
||||||
public class MarkerDetailFragment extends Fragment {
|
public class MarkerDetailFragment extends Fragment {
|
||||||
|
|
||||||
public static MarkerDetailFragment newInstance(long markerId, String title) {
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.putLong(KEY_MARKER_ID, markerId);
|
|
||||||
bundle.putString(KEY_TITLE, title);
|
|
||||||
|
|
||||||
MarkerDetailFragment fragment = new MarkerDetailFragment();
|
|
||||||
fragment.setArguments(bundle);
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String TAG = MarkerDetailFragment.class.getSimpleName();
|
private static final String TAG = MarkerDetailFragment.class.getSimpleName();
|
||||||
private static final String KEY_MARKER_ID = "markerId";
|
private static final String KEY_MARKER_ID = "markerId";
|
||||||
private static final String KEY_TITLE = "title";
|
private static final String KEY_TITLE = "title";
|
||||||
private static final long HIDE_TEXT_DELAY = 4000L; // 4 seconds
|
private static final long HIDE_TEXT_DELAY = 4000L; // 4 seconds
|
||||||
|
|
||||||
private ContentProviderUtils contentProviderUtils;
|
private ContentProviderUtils contentProviderUtils;
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
private ImageView photo;
|
private ImageView photo;
|
||||||
private ImageView textGradient;
|
private ImageView textGradient;
|
||||||
private LinearLayout waypointInfo;
|
private LinearLayout waypointInfo;
|
||||||
private Waypoint waypoint;
|
private Waypoint waypoint;
|
||||||
|
|
||||||
private Runnable hideText = new Runnable() {
|
private Runnable hideText = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -86,10 +74,12 @@ public class MarkerDetailFragment extends Fragment {
|
|||||||
animation.setAnimationListener(new AnimationListener() {
|
animation.setAnimationListener(new AnimationListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationStart(Animation anim) {}
|
public void onAnimationStart(Animation anim) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationRepeat(Animation anim) {}
|
public void onAnimationRepeat(Animation anim) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationEnd(Animation anim) {
|
public void onAnimationEnd(Animation anim) {
|
||||||
@@ -102,6 +92,16 @@ public class MarkerDetailFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static MarkerDetailFragment newInstance(long markerId, String title) {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putLong(KEY_MARKER_ID, markerId);
|
||||||
|
bundle.putString(KEY_TITLE, title);
|
||||||
|
|
||||||
|
MarkerDetailFragment fragment = new MarkerDetailFragment();
|
||||||
|
fragment.setArguments(bundle);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|||||||
@@ -69,9 +69,6 @@ public class StatsFragment extends Fragment implements TrackDataListener {
|
|||||||
private Location lastLocation = null;
|
private Location lastLocation = null;
|
||||||
private TripStatistics lastTripStatistics = null;
|
private TripStatistics lastTripStatistics = null;
|
||||||
private SensorDataSet sensorDataSet = null;
|
private SensorDataSet sensorDataSet = null;
|
||||||
private String category = "";
|
|
||||||
private int recordingGpsAccuracy = PreferencesUtils.RECORDING_GPS_ACCURACY_DEFAULT;
|
|
||||||
|
|
||||||
private final Runnable updateUIeachSecond = new Runnable() {
|
private final Runnable updateUIeachSecond = new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (isResumed() && isSelectedTrackRecording()) {
|
if (isResumed() && isSelectedTrackRecording()) {
|
||||||
@@ -84,7 +81,8 @@ public class StatsFragment extends Fragment implements TrackDataListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
private String category = "";
|
||||||
|
private int recordingGpsAccuracy = PreferencesUtils.RECORDING_GPS_ACCURACY_DEFAULT;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package com.google.android.apps.mytracks.io.file;
|
package com.google.android.apps.mytracks.io.file;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.io.file.exporter.GpxTrackWriter;
|
import com.google.android.apps.mytracks.io.file.exporter.GpxTrackWriter;
|
||||||
import com.google.android.apps.mytracks.io.file.exporter.KmlTrackWriter;
|
import com.google.android.apps.mytracks.io.file.exporter.KmlTrackWriter;
|
||||||
import com.google.android.apps.mytracks.io.file.exporter.TrackWriter;
|
import com.google.android.apps.mytracks.io.file.exporter.TrackWriter;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Parcel;
|
|
||||||
import android.os.Parcelable;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,16 +28,6 @@ public enum TrackFileFormat implements Parcelable {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
|
||||||
public int describeContents() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeToParcel(final Parcel dest, final int flags) {
|
|
||||||
dest.writeInt(ordinal());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final Creator<TrackFileFormat> CREATOR = new Creator<TrackFileFormat>() {
|
public static final Creator<TrackFileFormat> CREATOR = new Creator<TrackFileFormat>() {
|
||||||
@Override
|
@Override
|
||||||
public TrackFileFormat createFromParcel(final Parcel source) {
|
public TrackFileFormat createFromParcel(final Parcel source) {
|
||||||
@@ -50,6 +40,16 @@ public enum TrackFileFormat implements Parcelable {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(final Parcel dest, final int flags) {
|
||||||
|
dest.writeInt(ordinal());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new track writer for the format.
|
* Creates a new track writer for the format.
|
||||||
*
|
*
|
||||||
|
|||||||
+8
-8
@@ -16,18 +16,18 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.io.file.exporter;
|
package com.google.android.apps.mytracks.io.file.exporter;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
|
||||||
import com.google.android.apps.mytracks.content.SensorDataSetLocation;
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils.LocationIterator;
|
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
|
||||||
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.Constants;
|
||||||
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.ContentProviderUtils.LocationIterator;
|
||||||
|
import com.google.android.apps.mytracks.content.SensorDataSetLocation;
|
||||||
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public class GpxTrackWriter implements TrackWriter {
|
|||||||
|
|
||||||
private static final NumberFormat ELEVATION_FORMAT = NumberFormat.getInstance(Locale.US);
|
private static final NumberFormat ELEVATION_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||||
private static final NumberFormat COORDINATE_FORMAT = NumberFormat.getInstance(Locale.US);
|
private static final NumberFormat COORDINATE_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
/*
|
/*
|
||||||
* GPX readers expect to see fractional numbers with US-style punctuation.
|
* GPX readers expect to see fractional numbers with US-style punctuation.
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ import android.net.Uri;
|
|||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
import com.google.android.apps.mytracks.content.DescriptionGenerator;
|
import com.google.android.apps.mytracks.content.DescriptionGenerator;
|
||||||
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
||||||
import com.google.android.apps.mytracks.content.SensorDataSetLocation;
|
import com.google.android.apps.mytracks.content.SensorDataSetLocation;
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||||
|
|||||||
+6
-6
@@ -16,12 +16,6 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.io.file.exporter;
|
package com.google.android.apps.mytracks.io.file.exporter;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
@@ -29,6 +23,12 @@ import android.graphics.BitmapFactory;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|||||||
@@ -16,12 +16,6 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.io.file.exporter;
|
package com.google.android.apps.mytracks.io.file.exporter;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
|
||||||
import com.google.android.apps.mytracks.util.DialogUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.FileUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.IntentUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
@@ -31,6 +25,12 @@ import android.content.Intent;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
||||||
|
import com.google.android.apps.mytracks.util.DialogUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.FileUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.IntentUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -44,8 +44,6 @@ import java.io.IOException;
|
|||||||
public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||||
|
|
||||||
private static final String TAG = SaveAsyncTask.class.getSimpleName();
|
private static final String TAG = SaveAsyncTask.class.getSimpleName();
|
||||||
|
|
||||||
private SaveActivity saveActivity;
|
|
||||||
private final long[] trackIds;
|
private final long[] trackIds;
|
||||||
private final TrackFileFormat trackFileFormat;
|
private final TrackFileFormat trackFileFormat;
|
||||||
@Deprecated //TODO Seems to be a left over from Google Earth integration and can be removed.
|
@Deprecated //TODO Seems to be a left over from Google Earth integration and can be removed.
|
||||||
@@ -53,7 +51,7 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
|||||||
private final File directory;
|
private final File directory;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final ContentProviderUtils contentProviderUtils;
|
private final ContentProviderUtils contentProviderUtils;
|
||||||
|
private SaveActivity saveActivity;
|
||||||
private WakeLock wakeLock;
|
private WakeLock wakeLock;
|
||||||
|
|
||||||
// true if the AsyncTask has completed
|
// true if the AsyncTask has completed
|
||||||
|
|||||||
@@ -15,11 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.io.file.exporter;
|
package com.google.android.apps.mytracks.io.file.exporter;
|
||||||
|
|
||||||
|
import android.location.Location;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
|
|
||||||
import android.location.Location;
|
|
||||||
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+40
-47
@@ -22,9 +22,9 @@ import android.location.LocationManager;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils.LocationIterator;
|
import com.google.android.apps.mytracks.content.ContentProviderUtils.LocationIterator;
|
||||||
|
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||||
@@ -62,62 +62,17 @@ import javax.xml.parsers.SAXParserFactory;
|
|||||||
*/
|
*/
|
||||||
abstract class AbstractFileTrackImporter extends DefaultHandler implements TrackImporter {
|
abstract class AbstractFileTrackImporter extends DefaultHandler implements TrackImporter {
|
||||||
|
|
||||||
/**
|
|
||||||
* Data for the current track.
|
|
||||||
*
|
|
||||||
* @author Jimmy Shih
|
|
||||||
*/
|
|
||||||
private class TrackData {
|
|
||||||
|
|
||||||
// The current track
|
|
||||||
Track track = new Track();
|
|
||||||
|
|
||||||
// The number of segments processed for the current track
|
|
||||||
int numberOfSegments = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The last location in the current segment. Null if the current segment
|
|
||||||
* doesn't have a last location.
|
|
||||||
*/
|
|
||||||
Location lastLocationInCurrentSegment;
|
|
||||||
|
|
||||||
// The number of locations processed for the current track
|
|
||||||
int numberOfLocations = 0;
|
|
||||||
|
|
||||||
// The trip statistics updater for the current track
|
|
||||||
TripStatisticsUpdater tripStatisticsUpdater;
|
|
||||||
|
|
||||||
// The import time of the track.
|
|
||||||
long importTime = System.currentTimeMillis();
|
|
||||||
|
|
||||||
// The buffered locations
|
|
||||||
Location[] bufferedLocations = new Location[MAX_BUFFERED_LOCATIONS];
|
|
||||||
|
|
||||||
// The number of buffered locations
|
|
||||||
int numBufferedLocations = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String TAG = AbstractFileTrackImporter.class.getSimpleName();
|
private static final String TAG = AbstractFileTrackImporter.class.getSimpleName();
|
||||||
|
|
||||||
// The maximum number of buffered locations for bulk-insertion
|
// The maximum number of buffered locations for bulk-insertion
|
||||||
private static final int MAX_BUFFERED_LOCATIONS = 512;
|
private static final int MAX_BUFFERED_LOCATIONS = 512;
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final long importTrackId;
|
private final long importTrackId;
|
||||||
private final ContentProviderUtils contentProviderUtils;
|
private final ContentProviderUtils contentProviderUtils;
|
||||||
private final int recordingDistanceInterval;
|
private final int recordingDistanceInterval;
|
||||||
private final List<Long> trackIds;
|
private final List<Long> trackIds;
|
||||||
private final List<Waypoint> waypoints;
|
private final List<Waypoint> waypoints;
|
||||||
|
|
||||||
// The current track data
|
|
||||||
private TrackData trackData;
|
|
||||||
|
|
||||||
// The SAX locator to get the current line information
|
|
||||||
private Locator locator;
|
|
||||||
|
|
||||||
// The current element content
|
// The current element content
|
||||||
protected String content;
|
protected String content;
|
||||||
|
|
||||||
protected String name;
|
protected String name;
|
||||||
protected String description;
|
protected String description;
|
||||||
protected String category;
|
protected String category;
|
||||||
@@ -127,7 +82,10 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
protected String time;
|
protected String time;
|
||||||
protected String waypointType;
|
protected String waypointType;
|
||||||
protected String photoUrl;
|
protected String photoUrl;
|
||||||
|
// The current track data
|
||||||
|
private TrackData trackData;
|
||||||
|
// The SAX locator to get the current line information
|
||||||
|
private Locator locator;
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
@@ -616,4 +574,39 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
contentProviderUtils.deleteTrack(context, trackId);
|
contentProviderUtils.deleteTrack(context, trackId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data for the current track.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
private class TrackData {
|
||||||
|
|
||||||
|
// The current track
|
||||||
|
Track track = new Track();
|
||||||
|
|
||||||
|
// The number of segments processed for the current track
|
||||||
|
int numberOfSegments = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The last location in the current segment. Null if the current segment
|
||||||
|
* doesn't have a last location.
|
||||||
|
*/
|
||||||
|
Location lastLocationInCurrentSegment;
|
||||||
|
|
||||||
|
// The number of locations processed for the current track
|
||||||
|
int numberOfLocations = 0;
|
||||||
|
|
||||||
|
// The trip statistics updater for the current track
|
||||||
|
TripStatisticsUpdater tripStatisticsUpdater;
|
||||||
|
|
||||||
|
// The import time of the track.
|
||||||
|
long importTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// The buffered locations
|
||||||
|
Location[] bufferedLocations = new Location[MAX_BUFFERED_LOCATIONS];
|
||||||
|
|
||||||
|
// The number of buffered locations
|
||||||
|
int numBufferedLocations = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.io.file.importer;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
|
|||||||
+7
-8
@@ -16,6 +16,12 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.io.file.importer;
|
package com.google.android.apps.mytracks.io.file.importer;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.PowerManager.WakeLock;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
||||||
@@ -25,12 +31,6 @@ import com.google.android.apps.mytracks.util.PreferencesUtils;
|
|||||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.PowerManager.WakeLock;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
@@ -46,12 +46,11 @@ import java.util.List;
|
|||||||
public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||||
|
|
||||||
private static final String TAG = ImportAsyncTask.class.getSimpleName();
|
private static final String TAG = ImportAsyncTask.class.getSimpleName();
|
||||||
|
|
||||||
private ImportActivity importActivity;
|
|
||||||
private final boolean importAll;
|
private final boolean importAll;
|
||||||
private final TrackFileFormat trackFileFormat;
|
private final TrackFileFormat trackFileFormat;
|
||||||
private final String path;
|
private final String path;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
private ImportActivity importActivity;
|
||||||
private WakeLock wakeLock;
|
private WakeLock wakeLock;
|
||||||
|
|
||||||
// true if the AsyncTask has completed
|
// true if the AsyncTask has completed
|
||||||
|
|||||||
+1
-1
@@ -22,8 +22,8 @@ import android.net.Uri;
|
|||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.SensorDataSetLocation;
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.SensorDataSetLocation;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||||
import com.google.android.apps.mytracks.content.sensor.SensorDataSet;
|
import com.google.android.apps.mytracks.content.sensor.SensorDataSet;
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -16,14 +16,14 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.io.file.importer;
|
package com.google.android.apps.mytracks.io.file.importer;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
|
||||||
import com.google.android.apps.mytracks.io.file.exporter.KmzTrackExporter;
|
|
||||||
import com.google.android.apps.mytracks.util.FileUtils;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.io.file.exporter.KmzTrackExporter;
|
||||||
|
import com.google.android.apps.mytracks.util.FileUtils;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ public interface ITrackRecordingService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts a track point in the current recording track.
|
* Inserts a track point in the current recording track.
|
||||||
*
|
* <p>
|
||||||
* When recording a track, GPS locations are automatically inserted. This is used for
|
* When recording a track, GPS locations are automatically inserted. This is used for
|
||||||
* inserting special track points or for testing.
|
* inserting special track points or for testing.
|
||||||
*
|
*
|
||||||
@@ -99,14 +99,14 @@ public interface ITrackRecordingService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current sensor data. Returns null if there is no data.
|
* Gets the current sensor data. Returns null if there is no data.
|
||||||
|
*
|
||||||
* @return SensorDataSet object.
|
* @return SensorDataSet object.
|
||||||
*/
|
*/
|
||||||
SensorDataSet getSensorData();
|
SensorDataSet getSensorData();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current sensor manager state.
|
* Gets the current sensor manager state.
|
||||||
*
|
* <p>
|
||||||
* return a Sensor.SensorState enum value.
|
* return a Sensor.SensorState enum value.
|
||||||
*/
|
*/
|
||||||
SensorState getSensorState();
|
SensorState getSensorState();
|
||||||
|
|||||||
+13
-20
@@ -44,11 +44,11 @@ import androidx.core.app.TaskStackBuilder;
|
|||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.android.apps.mytracks.TrackDetailActivity;
|
import com.google.android.apps.mytracks.TrackDetailActivity;
|
||||||
import com.google.android.apps.mytracks.TrackListActivity;
|
import com.google.android.apps.mytracks.TrackListActivity;
|
||||||
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
|
||||||
import com.google.android.apps.mytracks.content.SensorDataSetLocation;
|
|
||||||
import com.google.android.apps.mytracks.content.CustomContentProvider;
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils.LocationIterator;
|
import com.google.android.apps.mytracks.content.ContentProviderUtils.LocationIterator;
|
||||||
|
import com.google.android.apps.mytracks.content.CustomContentProvider;
|
||||||
|
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
||||||
|
import com.google.android.apps.mytracks.content.SensorDataSetLocation;
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||||
@@ -95,15 +95,11 @@ public class TrackRecordingService extends Service {
|
|||||||
* Anything faster than that (in meters per second) will be considered moving.
|
* Anything faster than that (in meters per second) will be considered moving.
|
||||||
*/
|
*/
|
||||||
public static final double MAX_NO_MOVEMENT_SPEED = 0.224;
|
public static final double MAX_NO_MOVEMENT_SPEED = 0.224;
|
||||||
|
|
||||||
private static final String TAG = TrackRecordingService.class.getSimpleName();
|
|
||||||
|
|
||||||
// 1 minute in milliseconds
|
|
||||||
private static final long ONE_MINUTE = (long) (UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS);
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final int MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS = 3;
|
static final int MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS = 3;
|
||||||
|
private static final String TAG = TrackRecordingService.class.getSimpleName();
|
||||||
|
// 1 minute in milliseconds
|
||||||
|
private static final long ONE_MINUTE = (long) (UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS);
|
||||||
// The following variables are set in onCreate:
|
// The following variables are set in onCreate:
|
||||||
private ExecutorService executorService;
|
private ExecutorService executorService;
|
||||||
private Context context;
|
private Context context;
|
||||||
@@ -124,15 +120,6 @@ public class TrackRecordingService extends Service {
|
|||||||
|
|
||||||
// The following variables are set when recording:
|
// The following variables are set when recording:
|
||||||
private TripStatisticsUpdater trackTripStatisticsUpdater;
|
private TripStatisticsUpdater trackTripStatisticsUpdater;
|
||||||
private TripStatisticsUpdater markerTripStatisticsUpdater;
|
|
||||||
private WakeLock wakeLock;
|
|
||||||
private SensorManager sensorManager;
|
|
||||||
private Location lastLocation;
|
|
||||||
private boolean currentSegmentHasLocation;
|
|
||||||
private boolean isIdle; // true if idle
|
|
||||||
|
|
||||||
private ServiceBinder binder = new ServiceBinder(this);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that sharedPreferenceChangeListener cannot be an anonymous inner
|
* Note that sharedPreferenceChangeListener cannot be an anonymous inner
|
||||||
* class. Anonymous inner class will get garbage collected.
|
* class. Anonymous inner class will get garbage collected.
|
||||||
@@ -193,7 +180,13 @@ public class TrackRecordingService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
private TripStatisticsUpdater markerTripStatisticsUpdater;
|
||||||
|
private WakeLock wakeLock;
|
||||||
|
private SensorManager sensorManager;
|
||||||
|
private Location lastLocation;
|
||||||
|
private boolean currentSegmentHasLocation;
|
||||||
|
private boolean isIdle; // true if idle
|
||||||
|
private ServiceBinder binder = new ServiceBinder(this);
|
||||||
private LocationListener locationListener = new LocationListener() {
|
private LocationListener locationListener = new LocationListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+6
-9
@@ -16,9 +16,6 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.services;
|
package com.google.android.apps.mytracks.services;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
|
|
||||||
import com.google.android.maps.mytracks.BuildConfig;
|
|
||||||
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -28,6 +25,9 @@ import android.os.IBinder.DeathRecipient;
|
|||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
|
||||||
|
import com.google.android.maps.mytracks.BuildConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for the track recording service. This handles service
|
* Wrapper for the track recording service. This handles service
|
||||||
* start/bind/unbind/stop. The service must be started before it can be bound.
|
* start/bind/unbind/stop. The service must be started before it can be bound.
|
||||||
@@ -38,7 +38,9 @@ import android.util.Log;
|
|||||||
public class TrackRecordingServiceConnection {
|
public class TrackRecordingServiceConnection {
|
||||||
|
|
||||||
private static final String TAG = TrackRecordingServiceConnection.class.getSimpleName();
|
private static final String TAG = TrackRecordingServiceConnection.class.getSimpleName();
|
||||||
|
private final Context context;
|
||||||
|
private final Runnable callback;
|
||||||
|
private ITrackRecordingService trackRecordingService;
|
||||||
private final DeathRecipient deathRecipient = new DeathRecipient() {
|
private final DeathRecipient deathRecipient = new DeathRecipient() {
|
||||||
@Override
|
@Override
|
||||||
public void binderDied() {
|
public void binderDied() {
|
||||||
@@ -46,7 +48,6 @@ public class TrackRecordingServiceConnection {
|
|||||||
setTrackRecordingService(null);
|
setTrackRecordingService(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
||||||
@Override
|
@Override
|
||||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||||
@@ -66,10 +67,6 @@ public class TrackRecordingServiceConnection {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
private final Runnable callback;
|
|
||||||
private ITrackRecordingService trackRecordingService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
|
|||||||
+3
-5
@@ -41,15 +41,13 @@ import java.util.UUID;
|
|||||||
*/
|
*/
|
||||||
public class BluetoothConnectionManager {
|
public class BluetoothConnectionManager {
|
||||||
|
|
||||||
private static final UUID HEART_RATE_SERVICE_UUID = new UUID(0x180D00001000L, 0x800000805f9b34fbL);
|
|
||||||
private static final UUID HEART_RATE_MEASUREMENT_CHAR_UUID = new UUID(0x2A3700001000L, 0x800000805f9b34fbL);
|
|
||||||
private static final UUID CLIENT_CHARACTERISTIC_CONFIG_UUID = new UUID(0x290200001000L, 0x800000805f9b34fbL);
|
|
||||||
|
|
||||||
// Message types sent to handler
|
// Message types sent to handler
|
||||||
public static final int MESSAGE_DEVICE_NAME = 1;
|
public static final int MESSAGE_DEVICE_NAME = 1;
|
||||||
public static final int MESSAGE_READ = 2;
|
public static final int MESSAGE_READ = 2;
|
||||||
public static final String KEY_DEVICE_NAME = "device_name";
|
public static final String KEY_DEVICE_NAME = "device_name";
|
||||||
|
private static final UUID HEART_RATE_SERVICE_UUID = new UUID(0x180D00001000L, 0x800000805f9b34fbL);
|
||||||
|
private static final UUID HEART_RATE_MEASUREMENT_CHAR_UUID = new UUID(0x2A3700001000L, 0x800000805f9b34fbL);
|
||||||
|
private static final UUID CLIENT_CHARACTERISTIC_CONFIG_UUID = new UUID(0x290200001000L, 0x800000805f9b34fbL);
|
||||||
private static final String TAG = BluetoothConnectionManager.class.getSimpleName();
|
private static final String TAG = BluetoothConnectionManager.class.getSimpleName();
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|||||||
+2
-1
@@ -4,7 +4,8 @@ import android.bluetooth.BluetoothGattCharacteristic;
|
|||||||
|
|
||||||
public final class BluetoothLEUtils {
|
public final class BluetoothLEUtils {
|
||||||
|
|
||||||
private BluetoothLEUtils() {}
|
private BluetoothLEUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
public static int parseHeartRate(BluetoothGattCharacteristic characteristic) {
|
public static int parseHeartRate(BluetoothGattCharacteristic characteristic) {
|
||||||
//DOCUMENTATION https://www.bluetooth.com/specifications/gatt/characteristics/
|
//DOCUMENTATION https://www.bluetooth.com/specifications/gatt/characteristics/
|
||||||
|
|||||||
+34
-37
@@ -23,7 +23,6 @@ import android.os.Handler;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.sensor.SensorDataSet;
|
import com.google.android.apps.mytracks.content.sensor.SensorDataSet;
|
||||||
import com.google.android.apps.mytracks.content.sensor.SensorState;
|
import com.google.android.apps.mytracks.content.sensor.SensorState;
|
||||||
@@ -35,15 +34,47 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Bluetooth sensor manager.
|
* Bluetooth sensor manager.
|
||||||
*
|
* <p>
|
||||||
* TODO: Handle a BluetoothGatt.STATE_DISCONNECTED
|
* TODO: Handle a BluetoothGatt.STATE_DISCONNECTED
|
||||||
*
|
*
|
||||||
* @author Sandor Dornbush
|
* @author Sandor Dornbush
|
||||||
*/
|
*/
|
||||||
public class BluetoothSensorManager extends SensorManager {
|
public class BluetoothSensorManager extends SensorManager {
|
||||||
|
|
||||||
private static final BluetoothAdapter bluetoothAdapter = getDefaultBluetoothAdapter();
|
|
||||||
private static final String TAG = BluetoothConnectionManager.class.getSimpleName();
|
private static final String TAG = BluetoothConnectionManager.class.getSimpleName();
|
||||||
|
private static final BluetoothAdapter bluetoothAdapter = getDefaultBluetoothAdapter();
|
||||||
|
private final Context context;
|
||||||
|
private final BluetoothConnectionManager bluetoothConnectionManager;
|
||||||
|
private SensorDataSet sensorDataSet = null;
|
||||||
|
// Handler that gets information back from the bluetoothConnectionManager
|
||||||
|
private final Handler messageHandler = new Handler(Looper.getMainLooper()) {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message message) {
|
||||||
|
switch (message.what) {
|
||||||
|
case BluetoothConnectionManager.MESSAGE_DEVICE_NAME:
|
||||||
|
String deviceName = message.getData().getString(BluetoothConnectionManager.KEY_DEVICE_NAME);
|
||||||
|
break;
|
||||||
|
case BluetoothConnectionManager.MESSAGE_READ:
|
||||||
|
if (!(message.obj instanceof SensorDataSet)) {
|
||||||
|
Log.e(TAG, "Received message did not contain a SensorDataSet.");
|
||||||
|
sensorDataSet = null;
|
||||||
|
} else {
|
||||||
|
sensorDataSet = (SensorDataSet) message.obj;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param context the context
|
||||||
|
*/
|
||||||
|
public BluetoothSensorManager(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
bluetoothConnectionManager = new BluetoothConnectionManager(context, messageHandler);
|
||||||
|
}
|
||||||
|
|
||||||
private static BluetoothAdapter getDefaultBluetoothAdapter() {
|
private static BluetoothAdapter getDefaultBluetoothAdapter() {
|
||||||
// If from the main application thread, return directly
|
// If from the main application thread, return directly
|
||||||
@@ -83,40 +114,6 @@ public class BluetoothSensorManager extends SensorManager {
|
|||||||
return adapters.get(0);
|
return adapters.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
private final BluetoothConnectionManager bluetoothConnectionManager;
|
|
||||||
private SensorDataSet sensorDataSet = null;
|
|
||||||
|
|
||||||
// Handler that gets information back from the bluetoothConnectionManager
|
|
||||||
private final Handler messageHandler = new Handler(Looper.getMainLooper()) {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
switch (message.what) {
|
|
||||||
case BluetoothConnectionManager.MESSAGE_DEVICE_NAME:
|
|
||||||
String deviceName = message.getData().getString(BluetoothConnectionManager.KEY_DEVICE_NAME);
|
|
||||||
break;
|
|
||||||
case BluetoothConnectionManager.MESSAGE_READ:
|
|
||||||
if (!(message.obj instanceof SensorDataSet)) {
|
|
||||||
Log.e(TAG ,"Received message did not contain a SensorDataSet.");
|
|
||||||
sensorDataSet = null;
|
|
||||||
} else {
|
|
||||||
sensorDataSet = (SensorDataSet) message.obj;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param context the context
|
|
||||||
*/
|
|
||||||
public BluetoothSensorManager(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
bluetoothConnectionManager = new BluetoothConnectionManager(context, messageHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabled() {
|
public boolean isEnabled() {
|
||||||
return bluetoothAdapter != null && bluetoothAdapter.isEnabled();
|
return bluetoothAdapter != null && bluetoothAdapter.isEnabled();
|
||||||
|
|||||||
@@ -108,6 +108,13 @@ public abstract class SensorManager {
|
|||||||
tearDownChannel();
|
tearDownChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the sensor state.
|
||||||
|
*/
|
||||||
|
public SensorState getSensorState() {
|
||||||
|
return sensorState;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the sensor state.
|
* Sets the sensor state.
|
||||||
*
|
*
|
||||||
@@ -118,13 +125,6 @@ public abstract class SensorManager {
|
|||||||
this.sensorState = sensorState;
|
this.sensorState = sensorState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the sensor state.
|
|
||||||
*/
|
|
||||||
public SensorState getSensorState() {
|
|
||||||
return sensorState;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the sensor data set is valid.
|
* Returns true if the sensor data set is valid.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+2
-1
@@ -28,7 +28,8 @@ public class SensorManagerFactory {
|
|||||||
private static SensorManager systemSensorManager = null;
|
private static SensorManager systemSensorManager = null;
|
||||||
private static SensorManager sensorManagerTemporary = null;
|
private static SensorManager sensorManagerTemporary = null;
|
||||||
|
|
||||||
private SensorManagerFactory() {}
|
private SensorManagerFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the system sensor manager.
|
* Gets the system sensor manager.
|
||||||
|
|||||||
+2
-9
@@ -50,7 +50,8 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
|
|||||||
static final float TTS_SPEECH_RATE = 0.9f;
|
static final float TTS_SPEECH_RATE = 0.9f;
|
||||||
|
|
||||||
private static final String TAG = AnnouncementPeriodicTask.class.getSimpleName();
|
private static final String TAG = AnnouncementPeriodicTask.class.getSimpleName();
|
||||||
|
private final Context context;
|
||||||
|
private final AudioManager audioManager;
|
||||||
private final UtteranceProgressListener utteranceListener = new UtteranceProgressListener() {
|
private final UtteranceProgressListener utteranceListener = new UtteranceProgressListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onStart(String utteranceId) {
|
public void onStart(String utteranceId) {
|
||||||
@@ -68,21 +69,13 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
|
|||||||
public void onError(String utteranceId) {
|
public void onError(String utteranceId) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final Context context;
|
|
||||||
private TextToSpeech tts;
|
private TextToSpeech tts;
|
||||||
|
|
||||||
// Response from TTS after its initialization
|
// Response from TTS after its initialization
|
||||||
private int initStatus = TextToSpeech.ERROR;
|
private int initStatus = TextToSpeech.ERROR;
|
||||||
|
|
||||||
// True if TTS engine is ready
|
// True if TTS engine is ready
|
||||||
private boolean ready = false;
|
private boolean ready = false;
|
||||||
|
|
||||||
// True if speech is allowed
|
// True if speech is allowed
|
||||||
private boolean speechAllowed;
|
private boolean speechAllowed;
|
||||||
|
|
||||||
private final AudioManager audioManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener which updates {@link #speechAllowed} when the phone state changes.
|
* Listener which updates {@link #speechAllowed} when the phone state changes.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+2
-2
@@ -15,13 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.services.tasks;
|
package com.google.android.apps.mytracks.services.tasks;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.services.TrackRecordingService;
|
import com.google.android.apps.mytracks.services.TrackRecordingService;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a periodic task on a time or distance schedule.
|
* Execute a periodic task on a time or distance schedule.
|
||||||
*
|
*
|
||||||
|
|||||||
+4
-2
@@ -27,7 +27,8 @@ import com.google.android.apps.mytracks.services.TrackRecordingService;
|
|||||||
public class SplitPeriodicTask implements PeriodicTask {
|
public class SplitPeriodicTask implements PeriodicTask {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() {}
|
public void start() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(TrackRecordingService trackRecordingService) {
|
public void run(TrackRecordingService trackRecordingService) {
|
||||||
@@ -35,5 +36,6 @@ public class SplitPeriodicTask implements PeriodicTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void shutdown() {}
|
public void shutdown() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,6 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.settings;
|
package com.google.android.apps.mytracks.settings;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.util.DialogUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
@@ -34,6 +29,11 @@ import android.widget.ArrayAdapter;
|
|||||||
import android.widget.AutoCompleteTextView;
|
import android.widget.AutoCompleteTextView;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.util.DialogUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For entering the default activity type.
|
* For entering the default activity type.
|
||||||
*
|
*
|
||||||
|
|||||||
+5
-7
@@ -16,11 +16,6 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.settings;
|
package com.google.android.apps.mytracks.settings;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
|
||||||
import com.google.android.apps.mytracks.util.DialogUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
@@ -28,14 +23,17 @@ import android.content.Intent;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.CheckBoxPreference;
|
|
||||||
import android.preference.ListPreference;
|
import android.preference.ListPreference;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.Preference.OnPreferenceChangeListener;
|
|
||||||
import android.preference.Preference.OnPreferenceClickListener;
|
import android.preference.Preference.OnPreferenceClickListener;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.Constants;
|
||||||
|
import com.google.android.apps.mytracks.util.DialogUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An activity for advanced settings.
|
* An activity for advanced settings.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -16,13 +16,13 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.settings;
|
package com.google.android.apps.mytracks.settings;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.CheckBoxPreference;
|
import android.preference.CheckBoxPreference;
|
||||||
import android.preference.ListPreference;
|
import android.preference.ListPreference;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An activity for accessing chart settings.
|
* An activity for accessing chart settings.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -16,14 +16,14 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.settings;
|
package com.google.android.apps.mytracks.settings;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.ListPreference;
|
import android.preference.ListPreference;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.Preference.OnPreferenceChangeListener;
|
import android.preference.Preference.OnPreferenceChangeListener;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An activity for accessing stats settings.
|
* An activity for accessing stats settings.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -27,12 +27,10 @@ import androidx.annotation.NonNull;
|
|||||||
*/
|
*/
|
||||||
public class DoubleBuffer {
|
public class DoubleBuffer {
|
||||||
|
|
||||||
// The location that the next write will occur at.
|
|
||||||
private int index;
|
|
||||||
|
|
||||||
// The sliding buffer of doubles.
|
// The sliding buffer of doubles.
|
||||||
private final double[] buffer;
|
private final double[] buffer;
|
||||||
|
// The location that the next write will occur at.
|
||||||
|
private int index;
|
||||||
// True if the buffer is full
|
// True if the buffer is full
|
||||||
private boolean isFull;
|
private boolean isFull;
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,15 @@ public class ExtremityMonitor {
|
|||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the minimum value.
|
||||||
|
*
|
||||||
|
* @param min the minimum value
|
||||||
|
*/
|
||||||
|
public void setMin(double min) {
|
||||||
|
this.min = min;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the maximum value seen.
|
* Gets the maximum value seen.
|
||||||
*/
|
*/
|
||||||
@@ -57,6 +66,15 @@ public class ExtremityMonitor {
|
|||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum value.
|
||||||
|
*
|
||||||
|
* @param max the maximum value
|
||||||
|
*/
|
||||||
|
public void setMax(double max) {
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the min and the max with a new value.
|
* Updates the min and the max with a new value.
|
||||||
*
|
*
|
||||||
@@ -87,24 +105,6 @@ public class ExtremityMonitor {
|
|||||||
this.max = max;
|
this.max = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the minimum value.
|
|
||||||
*
|
|
||||||
* @param min the minimum value
|
|
||||||
*/
|
|
||||||
public void setMin(double min) {
|
|
||||||
this.min = min;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the maximum value.
|
|
||||||
*
|
|
||||||
* @param max the maximum value
|
|
||||||
*/
|
|
||||||
public void setMax(double max) {
|
|
||||||
this.max = max;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if has data.
|
* Returns true if has data.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -31,43 +31,38 @@ import androidx.annotation.NonNull;
|
|||||||
*/
|
*/
|
||||||
public class TripStatistics implements Parcelable {
|
public class TripStatistics implements Parcelable {
|
||||||
|
|
||||||
// The trip start time. This is the system time, might not match the GPs time.
|
/**
|
||||||
private long startTime = -1L;
|
* Creator of {@link TripStatistics} from parcels.
|
||||||
|
*/
|
||||||
// The trip stop time. This is the system time, might not match the GPS time.
|
public static final Creator CREATOR = new Creator();
|
||||||
private long stopTime = -1L;
|
|
||||||
|
|
||||||
// The total trip distance (meters).
|
|
||||||
private double totalDistance;
|
|
||||||
|
|
||||||
// The total time (ms). Updated when new points are received, may be stale.
|
|
||||||
private long totalTime;
|
|
||||||
|
|
||||||
// The total moving time (ms). Based on when we believe the user is traveling.
|
|
||||||
private long movingTime;
|
|
||||||
|
|
||||||
// The min and max latitude seen in this trip.
|
// The min and max latitude seen in this trip.
|
||||||
private final ExtremityMonitor latitudeExtremities = new ExtremityMonitor();
|
private final ExtremityMonitor latitudeExtremities = new ExtremityMonitor();
|
||||||
|
|
||||||
// The min and max longitude seen in this trip.
|
// The min and max longitude seen in this trip.
|
||||||
private final ExtremityMonitor longitudeExtremities = new ExtremityMonitor();
|
private final ExtremityMonitor longitudeExtremities = new ExtremityMonitor();
|
||||||
|
|
||||||
// The maximum speed (meters/second) that we believe is valid.
|
|
||||||
private double maxSpeed;
|
|
||||||
|
|
||||||
// The min and max elevation (meters) seen on this trip.
|
// The min and max elevation (meters) seen on this trip.
|
||||||
private final ExtremityMonitor elevationExtremities = new ExtremityMonitor();
|
private final ExtremityMonitor elevationExtremities = new ExtremityMonitor();
|
||||||
|
|
||||||
// The total elevation gained (meters).
|
|
||||||
private double totalElevationGain;
|
|
||||||
|
|
||||||
// The min and max grade seen on this trip.
|
// The min and max grade seen on this trip.
|
||||||
private final ExtremityMonitor gradeExtremities = new ExtremityMonitor();
|
private final ExtremityMonitor gradeExtremities = new ExtremityMonitor();
|
||||||
|
// The trip start time. This is the system time, might not match the GPs time.
|
||||||
|
private long startTime = -1L;
|
||||||
|
// The trip stop time. This is the system time, might not match the GPS time.
|
||||||
|
private long stopTime = -1L;
|
||||||
|
// The total trip distance (meters).
|
||||||
|
private double totalDistance;
|
||||||
|
// The total time (ms). Updated when new points are received, may be stale.
|
||||||
|
private long totalTime;
|
||||||
|
// The total moving time (ms). Based on when we believe the user is traveling.
|
||||||
|
private long movingTime;
|
||||||
|
// The maximum speed (meters/second) that we believe is valid.
|
||||||
|
private double maxSpeed;
|
||||||
|
// The total elevation gained (meters).
|
||||||
|
private double totalElevationGain;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor.
|
* Default constructor.
|
||||||
*/
|
*/
|
||||||
public TripStatistics() {}
|
public TripStatistics() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy constructor.
|
* Copy constructor.
|
||||||
@@ -446,12 +441,12 @@ public class TripStatistics implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the maximum grade.
|
* Sets the minimum grade.
|
||||||
*
|
*
|
||||||
* @param grade the grade as a fraction (1.0 would mean vertical upwards)
|
* @param grade the grade as a fraction (-1.0 would mean vertical downwards)
|
||||||
*/
|
*/
|
||||||
public void setMaxGrade(double grade) {
|
public void setMinGrade(double grade) {
|
||||||
gradeExtremities.setMax(grade);
|
gradeExtremities.setMin(grade);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -462,12 +457,12 @@ public class TripStatistics implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the minimum grade.
|
* Sets the maximum grade.
|
||||||
*
|
*
|
||||||
* @param grade the grade as a fraction (-1.0 would mean vertical downwards)
|
* @param grade the grade as a fraction (1.0 would mean vertical upwards)
|
||||||
*/
|
*/
|
||||||
public void setMinGrade(double grade) {
|
public void setMaxGrade(double grade) {
|
||||||
gradeExtremities.setMin(grade);
|
gradeExtremities.setMax(grade);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -492,6 +487,30 @@ public class TripStatistics implements Parcelable {
|
|||||||
+ "; Max Grade: " + getMaxGrade() + "}";
|
+ "; Max Grade: " + getMaxGrade() + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeLong(startTime);
|
||||||
|
dest.writeLong(stopTime);
|
||||||
|
dest.writeDouble(totalDistance);
|
||||||
|
dest.writeLong(totalTime);
|
||||||
|
dest.writeLong(movingTime);
|
||||||
|
dest.writeDouble(latitudeExtremities.getMin());
|
||||||
|
dest.writeDouble(latitudeExtremities.getMax());
|
||||||
|
dest.writeDouble(longitudeExtremities.getMin());
|
||||||
|
dest.writeDouble(longitudeExtremities.getMax());
|
||||||
|
dest.writeDouble(maxSpeed);
|
||||||
|
dest.writeDouble(elevationExtremities.getMin());
|
||||||
|
dest.writeDouble(elevationExtremities.getMax());
|
||||||
|
dest.writeDouble(totalElevationGain);
|
||||||
|
dest.writeDouble(gradeExtremities.getMin());
|
||||||
|
dest.writeDouble(gradeExtremities.getMax());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creator of statistics data from parcels.
|
* Creator of statistics data from parcels.
|
||||||
*/
|
*/
|
||||||
@@ -534,33 +553,4 @@ public class TripStatistics implements Parcelable {
|
|||||||
return new TripStatistics[size];
|
return new TripStatistics[size];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creator of {@link TripStatistics} from parcels.
|
|
||||||
*/
|
|
||||||
public static final Creator CREATOR = new Creator();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int describeContents() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
|
||||||
dest.writeLong(startTime);
|
|
||||||
dest.writeLong(stopTime);
|
|
||||||
dest.writeDouble(totalDistance);
|
|
||||||
dest.writeLong(totalTime);
|
|
||||||
dest.writeLong(movingTime);
|
|
||||||
dest.writeDouble(latitudeExtremities.getMin());
|
|
||||||
dest.writeDouble(latitudeExtremities.getMax());
|
|
||||||
dest.writeDouble(longitudeExtremities.getMin());
|
|
||||||
dest.writeDouble(longitudeExtremities.getMax());
|
|
||||||
dest.writeDouble(maxSpeed);
|
|
||||||
dest.writeDouble(elevationExtremities.getMin());
|
|
||||||
dest.writeDouble(elevationExtremities.getMax());
|
|
||||||
dest.writeDouble(totalElevationGain);
|
|
||||||
dest.writeDouble(gradeExtremities.getMin());
|
|
||||||
dest.writeDouble(gradeExtremities.getMax());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -36,8 +36,10 @@ import static com.google.android.apps.mytracks.services.TrackRecordingService.PA
|
|||||||
*/
|
*/
|
||||||
public class TripStatisticsUpdater {
|
public class TripStatisticsUpdater {
|
||||||
|
|
||||||
private static final String TAG = TripStatisticsUpdater.class.getSimpleName();
|
/**
|
||||||
|
* The number of grade readings to smooth to get a somewhat accurate signal.
|
||||||
|
*/
|
||||||
|
public static final int GRADE_SMOOTHING_FACTOR = 5;
|
||||||
/**
|
/**
|
||||||
* The number of elevation readings to smooth to get a somewhat accurate
|
* The number of elevation readings to smooth to get a somewhat accurate
|
||||||
* signal.
|
* signal.
|
||||||
@@ -50,18 +52,12 @@ public class TripStatisticsUpdater {
|
|||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final int RUN_SMOOTHING_FACTOR = 25;
|
static final int RUN_SMOOTHING_FACTOR = 25;
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of grade readings to smooth to get a somewhat accurate signal.
|
|
||||||
*/
|
|
||||||
public static final int GRADE_SMOOTHING_FACTOR = 5;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of speed reading to smooth to get a somewhat accurate signal.
|
* The number of speed reading to smooth to get a somewhat accurate signal.
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final int SPEED_SMOOTHING_FACTOR = 25;
|
static final int SPEED_SMOOTHING_FACTOR = 25;
|
||||||
|
private static final String TAG = TripStatisticsUpdater.class.getSimpleName();
|
||||||
/**
|
/**
|
||||||
* Ignore any acceleration faster than this. Will ignore any speeds that imply
|
* Ignore any acceleration faster than this. Will ignore any speeds that imply
|
||||||
* acceleration greater than 2g's 2g = 19.6 m/s^2 = 0.0002 m/ms^2 = 0.02
|
* acceleration greater than 2g's 2g = 19.6 m/s^2 = 0.0002 m/ms^2 = 0.02
|
||||||
@@ -71,27 +67,20 @@ public class TripStatisticsUpdater {
|
|||||||
|
|
||||||
// The track's trip statistics
|
// The track's trip statistics
|
||||||
private final TripStatistics tripStatistics;
|
private final TripStatistics tripStatistics;
|
||||||
|
|
||||||
// The current segment's trip statistics
|
|
||||||
private TripStatistics currentSegment;
|
|
||||||
|
|
||||||
// Current segment's last location.
|
|
||||||
private Location lastLocation;
|
|
||||||
|
|
||||||
// Current segment's last moving location
|
|
||||||
private Location lastMovingLocation;
|
|
||||||
|
|
||||||
// A buffer of the recent elevation readings (m)
|
// A buffer of the recent elevation readings (m)
|
||||||
private final DoubleBuffer elevationBuffer = new DoubleBuffer(ELEVATION_SMOOTHING_FACTOR);
|
private final DoubleBuffer elevationBuffer = new DoubleBuffer(ELEVATION_SMOOTHING_FACTOR);
|
||||||
|
|
||||||
// A buffer of the recent run readings (m) for calculating grade
|
// A buffer of the recent run readings (m) for calculating grade
|
||||||
private final DoubleBuffer runBuffer = new DoubleBuffer(RUN_SMOOTHING_FACTOR);
|
private final DoubleBuffer runBuffer = new DoubleBuffer(RUN_SMOOTHING_FACTOR);
|
||||||
|
|
||||||
// A buffer of the recent grade calculations (%)
|
// A buffer of the recent grade calculations (%)
|
||||||
private final DoubleBuffer gradeBuffer = new DoubleBuffer(GRADE_SMOOTHING_FACTOR);
|
private final DoubleBuffer gradeBuffer = new DoubleBuffer(GRADE_SMOOTHING_FACTOR);
|
||||||
|
|
||||||
// A buffer of the recent speed readings (m/s) for calculating max speed
|
// A buffer of the recent speed readings (m/s) for calculating max speed
|
||||||
private final DoubleBuffer speedBuffer = new DoubleBuffer(SPEED_SMOOTHING_FACTOR);
|
private final DoubleBuffer speedBuffer = new DoubleBuffer(SPEED_SMOOTHING_FACTOR);
|
||||||
|
// The current segment's trip statistics
|
||||||
|
private TripStatistics currentSegment;
|
||||||
|
// Current segment's last location.
|
||||||
|
private Location lastLocation;
|
||||||
|
// Current segment's last moving location
|
||||||
|
private Location lastMovingLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new trip statistics updater.
|
* Creates a new trip statistics updater.
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public class BluetoothDeviceUtils {
|
public class BluetoothDeviceUtils {
|
||||||
|
|
||||||
private BluetoothDeviceUtils() {}
|
private BluetoothDeviceUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates the device names and the device addresses with all the suitable
|
* Populates the device names and the device addresses with all the suitable
|
||||||
|
|||||||
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.util;
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
@@ -28,6 +26,8 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for creating dialogs.
|
* Utilities for creating dialogs.
|
||||||
*
|
*
|
||||||
@@ -35,7 +35,8 @@ import android.widget.LinearLayout;
|
|||||||
*/
|
*/
|
||||||
public class DialogUtils {
|
public class DialogUtils {
|
||||||
|
|
||||||
private DialogUtils() {}
|
private DialogUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a confirmation dialog.
|
* Creates a confirmation dialog.
|
||||||
|
|||||||
@@ -29,36 +29,32 @@ import java.io.File;
|
|||||||
*/
|
*/
|
||||||
public class FileUtils {
|
public class FileUtils {
|
||||||
|
|
||||||
private FileUtils() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Our external storage directory.
|
|
||||||
*/
|
|
||||||
static final String SDCARD_TOP_DIR = "MyTracks";
|
|
||||||
|
|
||||||
static final String TRACK_PREFIX = "MyTracks";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to transfer picture from the camera.
|
* Used to transfer picture from the camera.
|
||||||
*/
|
*/
|
||||||
public static final String FILEPROVIDER = "com.google.android.apps.mytracks.fileprovider";
|
public static final String FILEPROVIDER = "com.google.android.apps.mytracks.fileprovider";
|
||||||
|
/**
|
||||||
|
* The play tracks directory in the app's cache directory.
|
||||||
|
*/
|
||||||
|
public static final String PLAY_TRACKS_DIR = "temp";
|
||||||
|
/**
|
||||||
|
* Our external storage directory.
|
||||||
|
*/
|
||||||
|
static final String SDCARD_TOP_DIR = "MyTracks";
|
||||||
|
static final String TRACK_PREFIX = "MyTracks";
|
||||||
/**
|
/**
|
||||||
* The maximum FAT32 path length. See the FAT32 spec at
|
* The maximum FAT32 path length. See the FAT32 spec at
|
||||||
* http://msdn.microsoft.com/en-us/windows/hardware/gg463080
|
* http://msdn.microsoft.com/en-us/windows/hardware/gg463080
|
||||||
*/
|
*/
|
||||||
static final int MAX_FAT32_PATH_LENGTH = 260;
|
static final int MAX_FAT32_PATH_LENGTH = 260;
|
||||||
|
|
||||||
/**
|
|
||||||
* The play tracks directory in the app's cache directory.
|
|
||||||
*/
|
|
||||||
public static final String PLAY_TRACKS_DIR = "temp";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The pictures directory under the app's external storage directory.
|
* The pictures directory under the app's external storage directory.
|
||||||
*/
|
*/
|
||||||
private static final String PICTURES_DIR = "pictures";
|
private static final String PICTURES_DIR = "pictures";
|
||||||
|
|
||||||
|
private FileUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the external storage is available.
|
* Returns true if the external storage is available.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
||||||
@@ -38,7 +38,8 @@ public class IntentUtils {
|
|||||||
|
|
||||||
public static final String TEXT_PLAIN_TYPE = "text/plain";
|
public static final String TEXT_PLAIN_TYPE = "text/plain";
|
||||||
|
|
||||||
private IntentUtils() {}
|
private IntentUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an intent with {@link Intent#FLAG_ACTIVITY_CLEAR_TOP} and
|
* Creates an intent with {@link Intent#FLAG_ACTIVITY_CLEAR_TOP} and
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ public class ListItemUtils {
|
|||||||
|
|
||||||
private static final int LIST_PREFERRED_ITEM_HEIGHT_DEFAULT = 128;
|
private static final int LIST_PREFERRED_ITEM_HEIGHT_DEFAULT = 128;
|
||||||
|
|
||||||
private ListItemUtils() {}
|
private ListItemUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a list item.
|
* Sets a list item.
|
||||||
|
|||||||
@@ -15,11 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.util;
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
|
||||||
|
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
@@ -36,7 +36,8 @@ public class LocationUtils {
|
|||||||
private static final long MAX_LOCATION_AGE_MS = (long) (UnitConversions.MIN_TO_S
|
private static final long MAX_LOCATION_AGE_MS = (long) (UnitConversions.MIN_TO_S
|
||||||
* UnitConversions.S_TO_MS);
|
* UnitConversions.S_TO_MS);
|
||||||
|
|
||||||
private LocationUtils() {}
|
private LocationUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the distance on the two sphere between the point c0 and the line
|
* Computes the distance on the two sphere between the point c0 and the line
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package com.google.android.apps.mytracks.util;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.SharedPreferences.Editor;
|
import android.content.SharedPreferences.Editor;
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
@@ -92,7 +91,8 @@ public class PreferencesUtils {
|
|||||||
public static final int TRACK_WIDGET_ITEM4_DEFAULT = 2; // average speed
|
public static final int TRACK_WIDGET_ITEM4_DEFAULT = 2; // average speed
|
||||||
public static final int VOICE_FREQUENCY_DEFAULT = 0;
|
public static final int VOICE_FREQUENCY_DEFAULT = 0;
|
||||||
|
|
||||||
private PreferencesUtils() {}
|
private PreferencesUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a preference key
|
* Gets a preference key
|
||||||
|
|||||||
@@ -40,7 +40,8 @@ public class StatsUtils {
|
|||||||
private static final String GRADE_PERCENTAGE = "%";
|
private static final String GRADE_PERCENTAGE = "%";
|
||||||
private static final String GRADE_FORMAT = "%1$d";
|
private static final String GRADE_FORMAT = "%1$d";
|
||||||
|
|
||||||
private StatsUtils() {}
|
private StatsUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the location values.
|
* Sets the location values.
|
||||||
|
|||||||
@@ -47,12 +47,14 @@ public class StringUtils {
|
|||||||
"yyyy-MM-dd'T'HH:mm:ss", Locale.US);
|
"yyyy-MM-dd'T'HH:mm:ss", Locale.US);
|
||||||
private static final Pattern ISO_8601_EXTRAS = Pattern.compile(
|
private static final Pattern ISO_8601_EXTRAS = Pattern.compile(
|
||||||
"^(\\.\\d+)?(?:Z|([+-])(\\d{2}):(\\d{2}))?$");
|
"^(\\.\\d+)?(?:Z|([+-])(\\d{2}):(\\d{2}))?$");
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ISO_8601_DATE_TIME_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
|
ISO_8601_DATE_TIME_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
ISO_8601_BASE.setTimeZone(TimeZone.getTimeZone("UTC"));
|
ISO_8601_BASE.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private StringUtils() {}
|
private StringUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats the date and time based on user's phone date/time preferences.
|
* Formats the date and time based on user's phone date/time preferences.
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ public class SystemUtils {
|
|||||||
|
|
||||||
private static final String TAG = SystemUtils.class.getSimpleName();
|
private static final String TAG = SystemUtils.class.getSimpleName();
|
||||||
|
|
||||||
private SystemUtils() {}
|
private SystemUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the app version from the manifest.
|
* Get the app version from the manifest.
|
||||||
|
|||||||
@@ -92,7 +92,8 @@ public class TrackIconUtils {
|
|||||||
MAP.put(BOAT, new Pair<>(R.string.activity_type_boat, R.drawable.ic_track_boat));
|
MAP.put(BOAT, new Pair<>(R.string.activity_type_boat, R.drawable.ic_track_boat));
|
||||||
}
|
}
|
||||||
|
|
||||||
private TrackIconUtils() {}
|
private TrackIconUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the icon drawable.
|
* Gets the icon drawable.
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import android.content.Context;
|
|||||||
import android.location.Address;
|
import android.location.Address;
|
||||||
import android.location.Geocoder;
|
import android.location.Geocoder;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|||||||
+2
-1
@@ -42,7 +42,8 @@ public class TrackRecordingServiceConnectionUtils {
|
|||||||
|
|
||||||
private static final String TAG = TrackRecordingServiceConnectionUtils.class.getSimpleName();
|
private static final String TAG = TrackRecordingServiceConnectionUtils.class.getSimpleName();
|
||||||
|
|
||||||
private TrackRecordingServiceConnectionUtils() {}
|
private TrackRecordingServiceConnectionUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the recording service is running.
|
* Returns true if the recording service is running.
|
||||||
|
|||||||
@@ -16,12 +16,12 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.util;
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for updating track.
|
* Utilities for updating track.
|
||||||
*
|
*
|
||||||
@@ -29,10 +29,11 @@ import android.content.Context;
|
|||||||
*/
|
*/
|
||||||
public class TrackUtils {
|
public class TrackUtils {
|
||||||
|
|
||||||
private TrackUtils() {}
|
|
||||||
|
|
||||||
public static String TRACK_SORT_ORDER = TracksColumns.STARTTIME + " DESC";
|
public static String TRACK_SORT_ORDER = TracksColumns.STARTTIME + " DESC";
|
||||||
|
|
||||||
|
private TrackUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
public static void updateTrack(Context context, Track track, String name, String category, String description, ContentProviderUtils contentProviderUtils) {
|
public static void updateTrack(Context context, Track track, String name, String category, String description, ContentProviderUtils contentProviderUtils) {
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
track.setName(name);
|
track.setName(name);
|
||||||
|
|||||||
@@ -22,58 +22,44 @@ package com.google.android.apps.mytracks.util;
|
|||||||
*/
|
*/
|
||||||
public class UnitConversions {
|
public class UnitConversions {
|
||||||
|
|
||||||
private UnitConversions() {}
|
// multiplication factor to convert seconds to milliseconds
|
||||||
|
public static final double S_TO_MS = 1000.0;
|
||||||
// Time
|
// Time
|
||||||
// 1 second in milliseconds
|
// 1 second in milliseconds
|
||||||
public static final long ONE_SECOND = (long) UnitConversions.S_TO_MS;
|
public static final long ONE_SECOND = (long) UnitConversions.S_TO_MS;
|
||||||
|
|
||||||
// multiplication factor to convert seconds to milliseconds
|
|
||||||
public static final double S_TO_MS = 1000.0;
|
|
||||||
|
|
||||||
// multiplication factor to convert milliseconds to seconds
|
// multiplication factor to convert milliseconds to seconds
|
||||||
public static final double MS_TO_S = 1 / S_TO_MS;
|
public static final double MS_TO_S = 1 / S_TO_MS;
|
||||||
|
|
||||||
// multiplication factor to convert minutes to seconds
|
// multiplication factor to convert minutes to seconds
|
||||||
public static final double MIN_TO_S = 60.0;
|
public static final double MIN_TO_S = 60.0;
|
||||||
|
|
||||||
// multiplication factor to convert seconds to minutes
|
// multiplication factor to convert seconds to minutes
|
||||||
public static final double S_TO_MIN = 1 / MIN_TO_S;
|
public static final double S_TO_MIN = 1 / MIN_TO_S;
|
||||||
|
|
||||||
// multiplication factor to convert hours to minutes
|
// multiplication factor to convert hours to minutes
|
||||||
public static final double HR_TO_MIN = 60.0;
|
public static final double HR_TO_MIN = 60.0;
|
||||||
|
|
||||||
// multiplication factor to convert minutes to hours
|
// multiplication factor to convert minutes to hours
|
||||||
public static final double MIN_TO_HR = 1 / HR_TO_MIN;
|
public static final double MIN_TO_HR = 1 / HR_TO_MIN;
|
||||||
|
|
||||||
// Distance
|
|
||||||
|
|
||||||
// multiplication factor to convert kilometers to miles
|
// multiplication factor to convert kilometers to miles
|
||||||
public static final double KM_TO_MI = 0.621371192;
|
public static final double KM_TO_MI = 0.621371192;
|
||||||
|
|
||||||
|
// Distance
|
||||||
// multiplication factor to convert miles to feet
|
// multiplication factor to convert miles to feet
|
||||||
public static final double MI_TO_FT = 5280.0;
|
public static final double MI_TO_FT = 5280.0;
|
||||||
|
|
||||||
// multiplication factor to convert feet to miles
|
// multiplication factor to convert feet to miles
|
||||||
public static final double FT_TO_MI = 1 / MI_TO_FT;
|
public static final double FT_TO_MI = 1 / MI_TO_FT;
|
||||||
|
|
||||||
// multiplication factor to covert kilometers to meters
|
// multiplication factor to covert kilometers to meters
|
||||||
public static final double KM_TO_M = 1000.0;
|
public static final double KM_TO_M = 1000.0;
|
||||||
|
|
||||||
// multiplication factor to convert meters to kilometers
|
// multiplication factor to convert meters to kilometers
|
||||||
public static final double M_TO_KM = 1 / KM_TO_M;
|
public static final double M_TO_KM = 1 / KM_TO_M;
|
||||||
|
|
||||||
// multiplication factor to convert meters to miles
|
// multiplication factor to convert meters to miles
|
||||||
public static final double M_TO_MI = M_TO_KM * KM_TO_MI;
|
public static final double M_TO_MI = M_TO_KM * KM_TO_MI;
|
||||||
|
|
||||||
// multiplication factor to convert meters to feet
|
// multiplication factor to convert meters to feet
|
||||||
public static final double M_TO_FT = M_TO_MI * MI_TO_FT;
|
public static final double M_TO_FT = M_TO_MI * MI_TO_FT;
|
||||||
|
|
||||||
// Others
|
|
||||||
|
|
||||||
// multiplication factor to convert meters per second to kilometers per hour
|
// multiplication factor to convert meters per second to kilometers per hour
|
||||||
public static final double MS_TO_KMH = M_TO_KM / (S_TO_MIN * MIN_TO_HR);
|
public static final double MS_TO_KMH = M_TO_KM / (S_TO_MIN * MIN_TO_HR);
|
||||||
|
|
||||||
|
// Others
|
||||||
// multiplication factor to convert degrees to radians
|
// multiplication factor to convert degrees to radians
|
||||||
public static final double DEG_TO_RAD = Math.PI / 180.0;
|
public static final double DEG_TO_RAD = Math.PI / 180.0;
|
||||||
|
|
||||||
|
private UnitConversions() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -16,9 +16,6 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.widgets;
|
package com.google.android.apps.mytracks.widgets;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.appwidget.AppWidgetManager;
|
import android.appwidget.AppWidgetManager;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -27,6 +24,9 @@ import android.view.View;
|
|||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|||||||
@@ -16,17 +16,6 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.widgets;
|
package com.google.android.apps.mytracks.widgets;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.TrackDetailActivity;
|
|
||||||
import com.google.android.apps.mytracks.TrackListActivity;
|
|
||||||
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
|
||||||
import com.google.android.apps.mytracks.services.ControlRecordingService;
|
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
|
||||||
import com.google.android.apps.mytracks.util.IntentUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.appwidget.AppWidgetManager;
|
import android.appwidget.AppWidgetManager;
|
||||||
@@ -37,10 +26,22 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import androidx.core.app.TaskStackBuilder;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
|
|
||||||
|
import androidx.core.app.TaskStackBuilder;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.TrackDetailActivity;
|
||||||
|
import com.google.android.apps.mytracks.TrackListActivity;
|
||||||
|
import com.google.android.apps.mytracks.content.ContentProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
|
import com.google.android.apps.mytracks.services.ControlRecordingService;
|
||||||
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
|
import com.google.android.apps.mytracks.util.IntentUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A track widget to start/stop/pause/resume recording, launch the main activity, and
|
* A track widget to start/stop/pause/resume recording, launch the main activity, and
|
||||||
* display track statistics (total distance, total time, average speed, and
|
* display track statistics (total distance, total time, average speed, and
|
||||||
@@ -72,70 +73,6 @@ public class TrackWidgetProvider extends AppWidgetProvider {
|
|||||||
R.id.track_widget_item4_value, R.id.track_widget_item4_unit,
|
R.id.track_widget_item4_value, R.id.track_widget_item4_unit,
|
||||||
R.id.track_widget_item4_chronometer};
|
R.id.track_widget_item4_chronometer};
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
super.onReceive(context, intent);
|
|
||||||
String action = intent.getAction();
|
|
||||||
if (context.getString(R.string.track_paused_broadcast_action).equals(action)
|
|
||||||
|| context.getString(R.string.track_resumed_broadcast_action).equals(action)
|
|
||||||
|| context.getString(R.string.track_started_broadcast_action).equals(action)
|
|
||||||
|| context.getString(R.string.track_stopped_broadcast_action).equals(action)
|
|
||||||
|| context.getString(R.string.track_update_broadcast_action).equals(action)) {
|
|
||||||
long trackId = intent.getLongExtra(context.getString(R.string.track_id_broadcast_extra), -1L);
|
|
||||||
updateAllAppWidgets(context, trackId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnabled(Context context) {
|
|
||||||
super.onEnabled(context);
|
|
||||||
// Need to update all app widgets after phone reboot
|
|
||||||
updateAllAppWidgets(context, -1L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
|
||||||
super.onUpdate(context, appWidgetManager, appWidgetIds);
|
|
||||||
// Need to update all app widgets after software update
|
|
||||||
updateAllAppWidgets(context, -1L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(16)
|
|
||||||
@Override
|
|
||||||
public void onAppWidgetOptionsChanged(
|
|
||||||
Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
|
|
||||||
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
|
|
||||||
if (newOptions != null) {
|
|
||||||
int newSize;
|
|
||||||
if (newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1)
|
|
||||||
== AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) {
|
|
||||||
newSize = 1;
|
|
||||||
} else {
|
|
||||||
int height = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
|
|
||||||
if (height == 0) {
|
|
||||||
newSize = 2;
|
|
||||||
} else if (height >= FOUR_CELLS) {
|
|
||||||
newSize = 4;
|
|
||||||
} else if (height >= THREE_CELLS) {
|
|
||||||
newSize = 3;
|
|
||||||
} else if (height >= TWO_CELLS) {
|
|
||||||
newSize = 2;
|
|
||||||
} else {
|
|
||||||
newSize = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int size = getAppWidgetSize(appWidgetManager, appWidgetId);
|
|
||||||
|
|
||||||
if (size != newSize) {
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.putInt(APP_WIDGET_SIZE_KEY, size);
|
|
||||||
appWidgetManager.updateAppWidgetOptions(appWidgetId, bundle);
|
|
||||||
|
|
||||||
updateAppWidget(context, appWidgetManager, appWidgetId, -1L);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates an app widget.
|
* Updates an app widget.
|
||||||
*
|
*
|
||||||
@@ -507,4 +444,68 @@ public class TrackWidgetProvider extends AppWidgetProvider {
|
|||||||
R.id.track_widget_record_status, context.getResources().getColor(colorId));
|
R.id.track_widget_record_status, context.getResources().getColor(colorId));
|
||||||
remoteViews.setTextViewText(R.id.track_widget_record_status, status);
|
remoteViews.setTextViewText(R.id.track_widget_record_status, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
super.onReceive(context, intent);
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (context.getString(R.string.track_paused_broadcast_action).equals(action)
|
||||||
|
|| context.getString(R.string.track_resumed_broadcast_action).equals(action)
|
||||||
|
|| context.getString(R.string.track_started_broadcast_action).equals(action)
|
||||||
|
|| context.getString(R.string.track_stopped_broadcast_action).equals(action)
|
||||||
|
|| context.getString(R.string.track_update_broadcast_action).equals(action)) {
|
||||||
|
long trackId = intent.getLongExtra(context.getString(R.string.track_id_broadcast_extra), -1L);
|
||||||
|
updateAllAppWidgets(context, trackId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnabled(Context context) {
|
||||||
|
super.onEnabled(context);
|
||||||
|
// Need to update all app widgets after phone reboot
|
||||||
|
updateAllAppWidgets(context, -1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||||
|
super.onUpdate(context, appWidgetManager, appWidgetIds);
|
||||||
|
// Need to update all app widgets after software update
|
||||||
|
updateAllAppWidgets(context, -1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(16)
|
||||||
|
@Override
|
||||||
|
public void onAppWidgetOptionsChanged(
|
||||||
|
Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
|
||||||
|
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
|
||||||
|
if (newOptions != null) {
|
||||||
|
int newSize;
|
||||||
|
if (newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1)
|
||||||
|
== AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) {
|
||||||
|
newSize = 1;
|
||||||
|
} else {
|
||||||
|
int height = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
|
||||||
|
if (height == 0) {
|
||||||
|
newSize = 2;
|
||||||
|
} else if (height >= FOUR_CELLS) {
|
||||||
|
newSize = 4;
|
||||||
|
} else if (height >= THREE_CELLS) {
|
||||||
|
newSize = 3;
|
||||||
|
} else if (height >= TWO_CELLS) {
|
||||||
|
newSize = 2;
|
||||||
|
} else {
|
||||||
|
newSize = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int size = getAppWidgetSize(appWidgetManager, appWidgetId);
|
||||||
|
|
||||||
|
if (size != newSize) {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putInt(APP_WIDGET_SIZE_KEY, size);
|
||||||
|
appWidgetManager.updateAppWidgetOptions(appWidgetId, bundle);
|
||||||
|
|
||||||
|
updateAppWidget(context, appWidgetManager, appWidgetId, -1L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user