diff --git a/MyTracks/AndroidManifest.xml b/MyTracks/AndroidManifest.xml index d085d37e9..f4dc05e85 100755 --- a/MyTracks/AndroidManifest.xml +++ b/MyTracks/AndroidManifest.xml @@ -21,6 +21,7 @@ limitations under the License. android:versionName="1.1.9"> diff --git a/MyTracks/src/com/google/android/apps/mytracks/ChartActivity.java b/MyTracks/src/com/google/android/apps/mytracks/ChartActivity.java index ca4ac742f..194912471 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/ChartActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/ChartActivity.java @@ -20,11 +20,11 @@ import static com.google.android.apps.mytracks.Constants.TAG; import com.google.android.apps.mytracks.ChartView.Mode; import com.google.android.apps.mytracks.content.MyTracksLocation; import com.google.android.apps.mytracks.content.Sensor; -import com.google.android.apps.mytracks.content.TrackDataHub; -import com.google.android.apps.mytracks.content.TrackDataListener; import com.google.android.apps.mytracks.content.Sensor.SensorDataSet; -import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType; import com.google.android.apps.mytracks.content.Track; +import com.google.android.apps.mytracks.content.TrackDataHub; +import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType; +import com.google.android.apps.mytracks.content.TrackDataListener; import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory; import com.google.android.apps.mytracks.stats.DoubleBuffer; @@ -148,7 +148,7 @@ public class ChartActivity extends Activity implements TrackDataListener { protected void onResume() { super.onResume(); - dataHub = TrackDataHub.getStartedInstance(); + dataHub = ((MyTracksApplication) getApplication()).getTrackDataHub(); dataHub.registerTrackDataListener(this, EnumSet.of( ListenerDataType.SELECTED_TRACK_CHANGED, ListenerDataType.TRACK_UPDATES, diff --git a/MyTracks/src/com/google/android/apps/mytracks/MapActivity.java b/MyTracks/src/com/google/android/apps/mytracks/MapActivity.java index f168b3bc7..d7f5b8ce8 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/MapActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/MapActivity.java @@ -185,7 +185,7 @@ public class MapActivity extends com.google.android.maps.MapActivity Log.d(TAG, "MapActivity.onResume"); super.onResume(); - dataHub = TrackDataHub.getStartedInstance(); + dataHub = ((MyTracksApplication) getApplication()).getTrackDataHub(); dataHub.registerTrackDataListener(this, EnumSet.of( ListenerDataType.SELECTED_TRACK_CHANGED, ListenerDataType.POINT_UPDATES, diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java index 8a9555a8e..2071bf948 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java +++ b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java @@ -146,7 +146,7 @@ public class MyTracks extends TabActivity implements OnTouchListener { providerUtils = MyTracksProviderUtils.Factory.get(this); preferences = getSharedPreferences(Constants.SETTINGS_NAME, 0); - dataHub = TrackDataHub.newInstance(this); + dataHub = ((MyTracksApplication) getApplication()).getTrackDataHub(); menuManager = new MenuManager(this); serviceConnection = new TrackRecordingServiceConnection(this, serviceBindCallback); @@ -249,7 +249,6 @@ public class MyTracks extends TabActivity implements OnTouchListener { protected void onDestroy() { Log.d(TAG, "MyTracks.onDestroy"); serviceConnection.unbind(); - super.onDestroy(); } diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksApplication.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracksApplication.java new file mode 100644 index 000000000..27cf04efb --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/MyTracksApplication.java @@ -0,0 +1,42 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.android.apps.mytracks; + +import com.google.android.apps.mytracks.content.TrackDataHub; + +import android.app.Application; + +/** + * MyTracksApplication for keeping global state. + * + * @author jshih@google.com (Jimmy Shih) + */ +public class MyTracksApplication extends Application { + + private TrackDataHub trackDataHub; + + /** + * Gets the application's TrackDataHub. + * + * Note: use synchronized to make sure only one instance is created per application. + */ + public synchronized TrackDataHub getTrackDataHub() { + if (trackDataHub == null) { + trackDataHub = TrackDataHub.newInstance(getApplicationContext()); + } + return trackDataHub; + } +} diff --git a/MyTracks/src/com/google/android/apps/mytracks/StatsActivity.java b/MyTracks/src/com/google/android/apps/mytracks/StatsActivity.java index 5ed8b12b9..ba85fac47 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/StatsActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/StatsActivity.java @@ -137,7 +137,7 @@ public class StatsActivity extends Activity implements TrackDataListener { protected void onResume() { super.onResume(); - dataHub = TrackDataHub.getStartedInstance(); + dataHub = ((MyTracksApplication) getApplication()).getTrackDataHub(); dataHub.registerTrackDataListener(this, EnumSet.of( ListenerDataType.SELECTED_TRACK_CHANGED, ListenerDataType.TRACK_UPDATES, diff --git a/MyTracks/src/com/google/android/apps/mytracks/content/TrackDataHub.java b/MyTracks/src/com/google/android/apps/mytracks/content/TrackDataHub.java index d5e53c109..3bdd31b0c 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/content/TrackDataHub.java +++ b/MyTracks/src/com/google/android/apps/mytracks/content/TrackDataHub.java @@ -195,15 +195,12 @@ public class TrackDataHub { private int lastSamplingFrequency; private DoubleBufferedLocationFactory locationFactory; - private static TrackDataHub startedInstance; - + private boolean started = false; + /** * Builds a new {@link TrackDataHub} instance. */ public synchronized static TrackDataHub newInstance(Context context) { - // Ensure our singleton is never bound to an activity, to avoid memory leaks. - context = context.getApplicationContext(); - SharedPreferences preferences = context.getSharedPreferences(Constants.SETTINGS_NAME, 0); MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(context); return new TrackDataHub(context, @@ -240,11 +237,11 @@ public class TrackDataHub { */ public void start() { Log.i(TAG, "TrackDataHub.start"); - if (startedInstance != null) { + if (isStarted()) { Log.w(TAG, "Already started, ignoring"); return; } - startedInstance = this; + started = true; listenerHandlerThread = new HandlerThread("trackDataContentThread"); listenerHandlerThread.start(); @@ -266,20 +263,6 @@ public class TrackDataHub { return new DataSourcesWrapperImpl(context, preferences); } - /** - * If there's an instance for which {@link start} has been called, returns it. - * - * @return the started instance - * @throws IllegalStateException if there isn't a started instance - */ - public static TrackDataHub getStartedInstance() { - if (startedInstance == null) { - throw new IllegalStateException("Data hub not started"); - } - - return startedInstance; - } - /** * Stops listening to data sources and reporting the data to external * listeners. @@ -290,12 +273,12 @@ public class TrackDataHub { Log.w(TAG, "Not started, ignoring"); return; } - + // Unregister internal listeners even if there are external listeners registered. dataSourceManager.unregisterAllListeners(); listenerHandlerThread.getLooper().quit(); - startedInstance = null; + started = false; dataSources = null; dataSourceManager = null; @@ -304,7 +287,7 @@ public class TrackDataHub { } private boolean isStarted() { - return startedInstance != null; + return started; } @Override diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/WriteProgressController.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/WriteProgressController.java index f41930fd8..c759e24d9 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/WriteProgressController.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/WriteProgressController.java @@ -70,6 +70,11 @@ class WriteProgressController { public void setOnCompletionListener(OnCompletionListener onCompletionListener) { this.onCompletionListener = onCompletionListener; } + + // For testing purpose + OnCompletionListener getOnCompletionListener() { + return onCompletionListener; + } public ProgressDialog createProgressDialog() { dialog = new ProgressDialog(activity); diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/MyTracksTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/MyTracksTest.java index a5581edc7..a82c4aa12 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/MyTracksTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/MyTracksTest.java @@ -49,7 +49,6 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2{ protected void tearDown() throws Exception { clearSelectedAndRecordingTracks(); waitForIdle(); - super.tearDown(); } @@ -85,7 +84,7 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2{ // Simulate start with ACTION_VIEW intent. Intent startIntent = new Intent(); startIntent.setAction(Intent.ACTION_VIEW); - Uri uri = Uri.fromFile(File.createTempFile("valid", ".gpx")); + Uri uri = Uri.fromFile(File.createTempFile("valid", ".gpx", getActivity().getFilesDir())); // TODO: Add a valid GPX. @@ -108,7 +107,7 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2{ // Simulate start with ACTION_VIEW intent. Intent startIntent = new Intent(); startIntent.setAction(Intent.ACTION_VIEW); - Uri uri = Uri.fromFile(File.createTempFile("invalid", ".gpx")); + Uri uri = Uri.fromFile(File.createTempFile("invalid", ".gpx", getActivity().getFilesDir())); startIntent.setData(uri); setActivityIntent(startIntent); @@ -168,8 +167,13 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2{ // properly saved. // Simulate a click on Save button. - Button save = (Button) activity.findViewById(R.id.trackdetails_save); - save.performClick(); + final Button save = (Button) activity.findViewById(R.id.trackdetails_save); + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + save.performClick(); + } + }); // Check the remaining properties. recordingTrackId = awaitRecordingStatus(5000, false); diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/docs/DocsHelper_AddTrackRowTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/docs/DocsHelper_AddTrackRowTest.java index 89c0cfa3a..7400bcf11 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/docs/DocsHelper_AddTrackRowTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/docs/DocsHelper_AddTrackRowTest.java @@ -28,6 +28,8 @@ import android.test.mock.MockContext; import android.test.mock.MockResources; import java.io.IOException; +import java.text.DateFormat; +import java.util.Date; import junit.framework.TestCase; @@ -55,13 +57,13 @@ public class DocsHelper_AddTrackRowTest extends TestCase { StringWritingDocsHelper docsHelper = new StringWritingDocsHelper(); addTrackRow(docsHelper, false); + DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); String expectedData = "" + "" + "" - // We format the date here because we can't guarantee/force the timezone - + "" + + "" + "" + "" + "" @@ -76,12 +78,12 @@ public class DocsHelper_AddTrackRowTest extends TestCase { + "" + "" + "" - + "" + + "" + "" + ""; assertEquals( - "http://spreadsheets.google.com/feeds/list/ssid/wsid/private/full", + "https://spreadsheets.google.com/feeds/list/ssid/wsid/private/full", docsHelper.writtenSheetUri); assertEquals(expectedData, docsHelper.writtenData); } diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/WriteProgressControllerTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/WriteProgressControllerTest.java index 7810af87d..c6028c325 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/WriteProgressControllerTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/WriteProgressControllerTest.java @@ -53,7 +53,7 @@ public class WriteProgressControllerTest extends ActivityInstrumentationTestCase } }; - WriteProgressController controller = new WriteProgressController( + final WriteProgressController controller = new WriteProgressController( getActivity(), mockWriter, SaveActivity.PROGRESS_DIALOG); controller.setOnCompletionListener(new WriteProgressController.OnCompletionListener() { @Override @@ -62,6 +62,22 @@ public class WriteProgressControllerTest extends ActivityInstrumentationTestCase } }); + /* + * The WriteProgressController constructor calls the mockWriter's + * setOnCompletionListener method with a listener that dismisses the + * progress dialog. However, this unit test only tests the + * WriteProgressController and doesn't actually show any progress dialog. + * Thus after the WriteProgressController is setup, we need to call the + * mockWriter's setOnCompletionListener method again with an listener that + * doesn't dismiss dialog. + */ + mockWriter.setOnCompletionListener(new TrackWriter.OnCompletionListener() { + @Override + public void onComplete() { + controller.getOnCompletionListener().onComplete(); + } + }); + dialogRef.set(controller.createProgressDialog()); controller.startWrite(); @@ -69,7 +85,6 @@ public class WriteProgressControllerTest extends ActivityInstrumentationTestCase // wait for the writer to finish writerDone.acquire(); - assertFalse(dialogRef.get().isShowing()); assertTrue(controllerDoneRef.get()); } } diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/services/sensors/ZephyrMessageParserTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/services/sensors/ZephyrMessageParserTest.java index 910b1ca98..61d99167a 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/services/sensors/ZephyrMessageParserTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/services/sensors/ZephyrMessageParserTest.java @@ -26,9 +26,9 @@ public class ZephyrMessageParserTest extends TestCase { public void testParseBuffer() { byte[] buf = new byte[60]; - // Heartrate (-1 =^ 255 unsigned byte) + // Heart Rate (-1 =^ 255 unsigned byte) buf[12] = -1; - // Power + // Battery Level buf[11] = 51; // Cadence (=^ 255*16 strides/min) buf[56] = -1; @@ -37,9 +37,9 @@ public class ZephyrMessageParserTest extends TestCase { assertTrue(sds.hasHeartRate()); assertTrue(sds.getHeartRate().getState() == Sensor.SensorState.SENDING); assertEquals(255, sds.getHeartRate().getValue()); - assertTrue(sds.hasPower()); - assertTrue(sds.getPower().getState() == Sensor.SensorState.SENDING); - assertEquals(51, sds.getPower().getValue()); + assertTrue(sds.hasBatteryLevel()); + assertTrue(sds.getBatteryLevel().getState() == Sensor.SensorState.SENDING); + assertEquals(51, sds.getBatteryLevel().getValue()); assertTrue(sds.hasCadence()); assertTrue(sds.getCadence().getState() == Sensor.SensorState.SENDING); assertEquals(255, sds.getCadence().getValue());