merge heads

This commit is contained in:
Jimmy Shih
2011-09-29 18:14:44 -07:00
12 changed files with 99 additions and 48 deletions
+1
View File
@@ -21,6 +21,7 @@ limitations under the License.
android:versionName="1.1.9"> android:versionName="1.1.9">
<application android:icon="@drawable/arrow_icon" <application android:icon="@drawable/arrow_icon"
android:label="@string/app_name" android:label="@string/app_name"
android:name="com.google.android.apps.mytracks.MyTracksApplication"
android:backupAgent="com.google.android.apps.mytracks.io.backup.MyTracksBackupAgent"> android:backupAgent="com.google.android.apps.mytracks.io.backup.MyTracksBackupAgent">
<uses-library android:name="com.google.android.maps" /> <uses-library android:name="com.google.android.maps" />
@@ -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.ChartView.Mode;
import com.google.android.apps.mytracks.content.MyTracksLocation; import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.Sensor; 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.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.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.content.Waypoint;
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory; import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.stats.DoubleBuffer; import com.google.android.apps.mytracks.stats.DoubleBuffer;
@@ -148,7 +148,7 @@ public class ChartActivity extends Activity implements TrackDataListener {
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
dataHub = TrackDataHub.getStartedInstance(); dataHub = ((MyTracksApplication) getApplication()).getTrackDataHub();
dataHub.registerTrackDataListener(this, EnumSet.of( dataHub.registerTrackDataListener(this, EnumSet.of(
ListenerDataType.SELECTED_TRACK_CHANGED, ListenerDataType.SELECTED_TRACK_CHANGED,
ListenerDataType.TRACK_UPDATES, ListenerDataType.TRACK_UPDATES,
@@ -185,7 +185,7 @@ public class MapActivity extends com.google.android.maps.MapActivity
Log.d(TAG, "MapActivity.onResume"); Log.d(TAG, "MapActivity.onResume");
super.onResume(); super.onResume();
dataHub = TrackDataHub.getStartedInstance(); dataHub = ((MyTracksApplication) getApplication()).getTrackDataHub();
dataHub.registerTrackDataListener(this, EnumSet.of( dataHub.registerTrackDataListener(this, EnumSet.of(
ListenerDataType.SELECTED_TRACK_CHANGED, ListenerDataType.SELECTED_TRACK_CHANGED,
ListenerDataType.POINT_UPDATES, ListenerDataType.POINT_UPDATES,
@@ -146,7 +146,7 @@ public class MyTracks extends TabActivity implements OnTouchListener {
providerUtils = MyTracksProviderUtils.Factory.get(this); providerUtils = MyTracksProviderUtils.Factory.get(this);
preferences = getSharedPreferences(Constants.SETTINGS_NAME, 0); preferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
dataHub = TrackDataHub.newInstance(this); dataHub = ((MyTracksApplication) getApplication()).getTrackDataHub();
menuManager = new MenuManager(this); menuManager = new MenuManager(this);
serviceConnection = new TrackRecordingServiceConnection(this, serviceBindCallback); serviceConnection = new TrackRecordingServiceConnection(this, serviceBindCallback);
@@ -249,7 +249,6 @@ public class MyTracks extends TabActivity implements OnTouchListener {
protected void onDestroy() { protected void onDestroy() {
Log.d(TAG, "MyTracks.onDestroy"); Log.d(TAG, "MyTracks.onDestroy");
serviceConnection.unbind(); serviceConnection.unbind();
super.onDestroy(); super.onDestroy();
} }
@@ -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;
}
}
@@ -137,7 +137,7 @@ public class StatsActivity extends Activity implements TrackDataListener {
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
dataHub = TrackDataHub.getStartedInstance(); dataHub = ((MyTracksApplication) getApplication()).getTrackDataHub();
dataHub.registerTrackDataListener(this, EnumSet.of( dataHub.registerTrackDataListener(this, EnumSet.of(
ListenerDataType.SELECTED_TRACK_CHANGED, ListenerDataType.SELECTED_TRACK_CHANGED,
ListenerDataType.TRACK_UPDATES, ListenerDataType.TRACK_UPDATES,
@@ -195,15 +195,12 @@ public class TrackDataHub {
private int lastSamplingFrequency; private int lastSamplingFrequency;
private DoubleBufferedLocationFactory locationFactory; private DoubleBufferedLocationFactory locationFactory;
private static TrackDataHub startedInstance; private boolean started = false;
/** /**
* Builds a new {@link TrackDataHub} instance. * Builds a new {@link TrackDataHub} instance.
*/ */
public synchronized static TrackDataHub newInstance(Context context) { 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); SharedPreferences preferences = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(context); MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(context);
return new TrackDataHub(context, return new TrackDataHub(context,
@@ -240,11 +237,11 @@ public class TrackDataHub {
*/ */
public void start() { public void start() {
Log.i(TAG, "TrackDataHub.start"); Log.i(TAG, "TrackDataHub.start");
if (startedInstance != null) { if (isStarted()) {
Log.w(TAG, "Already started, ignoring"); Log.w(TAG, "Already started, ignoring");
return; return;
} }
startedInstance = this; started = true;
listenerHandlerThread = new HandlerThread("trackDataContentThread"); listenerHandlerThread = new HandlerThread("trackDataContentThread");
listenerHandlerThread.start(); listenerHandlerThread.start();
@@ -266,20 +263,6 @@ public class TrackDataHub {
return new DataSourcesWrapperImpl(context, preferences); 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 * Stops listening to data sources and reporting the data to external
* listeners. * listeners.
@@ -295,7 +278,7 @@ public class TrackDataHub {
dataSourceManager.unregisterAllListeners(); dataSourceManager.unregisterAllListeners();
listenerHandlerThread.getLooper().quit(); listenerHandlerThread.getLooper().quit();
startedInstance = null; started = false;
dataSources = null; dataSources = null;
dataSourceManager = null; dataSourceManager = null;
@@ -304,7 +287,7 @@ public class TrackDataHub {
} }
private boolean isStarted() { private boolean isStarted() {
return startedInstance != null; return started;
} }
@Override @Override
@@ -71,6 +71,11 @@ class WriteProgressController {
this.onCompletionListener = onCompletionListener; this.onCompletionListener = onCompletionListener;
} }
// For testing purpose
OnCompletionListener getOnCompletionListener() {
return onCompletionListener;
}
public ProgressDialog createProgressDialog() { public ProgressDialog createProgressDialog() {
dialog = new ProgressDialog(activity); dialog = new ProgressDialog(activity);
dialog.setIcon(android.R.drawable.ic_dialog_info); dialog.setIcon(android.R.drawable.ic_dialog_info);
@@ -49,7 +49,6 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
protected void tearDown() throws Exception { protected void tearDown() throws Exception {
clearSelectedAndRecordingTracks(); clearSelectedAndRecordingTracks();
waitForIdle(); waitForIdle();
super.tearDown(); super.tearDown();
} }
@@ -85,7 +84,7 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
// Simulate start with ACTION_VIEW intent. // Simulate start with ACTION_VIEW intent.
Intent startIntent = new Intent(); Intent startIntent = new Intent();
startIntent.setAction(Intent.ACTION_VIEW); 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. // TODO: Add a valid GPX.
@@ -108,7 +107,7 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
// Simulate start with ACTION_VIEW intent. // Simulate start with ACTION_VIEW intent.
Intent startIntent = new Intent(); Intent startIntent = new Intent();
startIntent.setAction(Intent.ACTION_VIEW); 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); startIntent.setData(uri);
setActivityIntent(startIntent); setActivityIntent(startIntent);
@@ -168,8 +167,13 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
// properly saved. // properly saved.
// Simulate a click on Save button. // Simulate a click on Save button.
Button save = (Button) activity.findViewById(R.id.trackdetails_save); final Button save = (Button) activity.findViewById(R.id.trackdetails_save);
save.performClick(); getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
save.performClick();
}
});
// Check the remaining properties. // Check the remaining properties.
recordingTrackId = awaitRecordingStatus(5000, false); recordingTrackId = awaitRecordingStatus(5000, false);
@@ -28,6 +28,8 @@ import android.test.mock.MockContext;
import android.test.mock.MockResources; import android.test.mock.MockResources;
import java.io.IOException; import java.io.IOException;
import java.text.DateFormat;
import java.util.Date;
import junit.framework.TestCase; import junit.framework.TestCase;
@@ -55,13 +57,13 @@ public class DocsHelper_AddTrackRowTest extends TestCase {
StringWritingDocsHelper docsHelper = new StringWritingDocsHelper(); StringWritingDocsHelper docsHelper = new StringWritingDocsHelper();
addTrackRow(docsHelper, false); addTrackRow(docsHelper, false);
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
String expectedData = String expectedData =
"<entry xmlns='http://www.w3.org/2005/Atom' " "<entry xmlns='http://www.w3.org/2005/Atom' "
+ "xmlns:gsx='http://schemas.google.com/spreadsheets/2006/extended'>" + "xmlns:gsx='http://schemas.google.com/spreadsheets/2006/extended'>"
+ "<gsx:name><![CDATA[trackName]]></gsx:name>" + "<gsx:name><![CDATA[trackName]]></gsx:name>"
+ "<gsx:description><![CDATA[trackDescription]]></gsx:description>" + "<gsx:description><![CDATA[trackDescription]]></gsx:description>"
// We format the date here because we can't guarantee/force the timezone + "<gsx:date><![CDATA[" + dateFormat.format(new Date(TIME)) + "]]></gsx:date>"
+ "<gsx:date><![CDATA[" + String.format("%tc", TIME) + "]]></gsx:date>"
+ "<gsx:totaltime><![CDATA[0:00:05]]></gsx:totaltime>" + "<gsx:totaltime><![CDATA[0:00:05]]></gsx:totaltime>"
+ "<gsx:movingtime><![CDATA[0:00:04]]></gsx:movingtime>" + "<gsx:movingtime><![CDATA[0:00:04]]></gsx:movingtime>"
+ "<gsx:distance><![CDATA[12.43]]></gsx:distance>" + "<gsx:distance><![CDATA[12.43]]></gsx:distance>"
@@ -76,12 +78,12 @@ public class DocsHelper_AddTrackRowTest extends TestCase {
+ "<gsx:maxelevation><![CDATA[1,804]]></gsx:maxelevation>" + "<gsx:maxelevation><![CDATA[1,804]]></gsx:maxelevation>"
+ "<gsx:elevationunit><![CDATA[feet]]></gsx:elevationunit>" + "<gsx:elevationunit><![CDATA[feet]]></gsx:elevationunit>"
+ "<gsx:map>" + "<gsx:map>"
+ "<![CDATA[http://maps.google.com/maps/ms?msa=0&msid=trackMapId]]>" + "<![CDATA[https://maps.google.com/maps/ms?msa=0&msid=trackMapId]]>"
+ "</gsx:map>" + "</gsx:map>"
+ "</entry>"; + "</entry>";
assertEquals( assertEquals(
"http://spreadsheets.google.com/feeds/list/ssid/wsid/private/full", "https://spreadsheets.google.com/feeds/list/ssid/wsid/private/full",
docsHelper.writtenSheetUri); docsHelper.writtenSheetUri);
assertEquals(expectedData, docsHelper.writtenData); assertEquals(expectedData, docsHelper.writtenData);
} }
@@ -53,7 +53,7 @@ public class WriteProgressControllerTest extends ActivityInstrumentationTestCase
} }
}; };
WriteProgressController controller = new WriteProgressController( final WriteProgressController controller = new WriteProgressController(
getActivity(), mockWriter, SaveActivity.PROGRESS_DIALOG); getActivity(), mockWriter, SaveActivity.PROGRESS_DIALOG);
controller.setOnCompletionListener(new WriteProgressController.OnCompletionListener() { controller.setOnCompletionListener(new WriteProgressController.OnCompletionListener() {
@Override @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()); dialogRef.set(controller.createProgressDialog());
controller.startWrite(); controller.startWrite();
@@ -69,7 +85,6 @@ public class WriteProgressControllerTest extends ActivityInstrumentationTestCase
// wait for the writer to finish // wait for the writer to finish
writerDone.acquire(); writerDone.acquire();
assertFalse(dialogRef.get().isShowing());
assertTrue(controllerDoneRef.get()); assertTrue(controllerDoneRef.get());
} }
} }
@@ -26,9 +26,9 @@ public class ZephyrMessageParserTest extends TestCase {
public void testParseBuffer() { public void testParseBuffer() {
byte[] buf = new byte[60]; byte[] buf = new byte[60];
// Heartrate (-1 =^ 255 unsigned byte) // Heart Rate (-1 =^ 255 unsigned byte)
buf[12] = -1; buf[12] = -1;
// Power // Battery Level
buf[11] = 51; buf[11] = 51;
// Cadence (=^ 255*16 strides/min) // Cadence (=^ 255*16 strides/min)
buf[56] = -1; buf[56] = -1;
@@ -37,9 +37,9 @@ public class ZephyrMessageParserTest extends TestCase {
assertTrue(sds.hasHeartRate()); assertTrue(sds.hasHeartRate());
assertTrue(sds.getHeartRate().getState() == Sensor.SensorState.SENDING); assertTrue(sds.getHeartRate().getState() == Sensor.SensorState.SENDING);
assertEquals(255, sds.getHeartRate().getValue()); assertEquals(255, sds.getHeartRate().getValue());
assertTrue(sds.hasPower()); assertTrue(sds.hasBatteryLevel());
assertTrue(sds.getPower().getState() == Sensor.SensorState.SENDING); assertTrue(sds.getBatteryLevel().getState() == Sensor.SensorState.SENDING);
assertEquals(51, sds.getPower().getValue()); assertEquals(51, sds.getBatteryLevel().getValue());
assertTrue(sds.hasCadence()); assertTrue(sds.hasCadence());
assertTrue(sds.getCadence().getState() == Sensor.SensorState.SENDING); assertTrue(sds.getCadence().getState() == Sensor.SensorState.SENDING);
assertEquals(255, sds.getCadence().getValue()); assertEquals(255, sds.getCadence().getValue());