forked from upstream-mirrors/OpenTracks
Merge heads
This commit is contained in:
@@ -214,7 +214,7 @@ limitations under the License.
|
||||
<activity android:name="com.google.android.apps.mytracks.io.backup.RestoreActivity" />
|
||||
<activity android:name="com.google.android.apps.mytracks.io.backup.RestoreChooserActivity" />
|
||||
<activity android:name="com.google.android.apps.mytracks.io.drive.SendDriveActivity" />
|
||||
<activity android:name="com.google.android.apps.mytracks.io.file.SaveActivity" />
|
||||
<activity android:name="com.google.android.apps.mytracks.io.file.export.SaveActivity" />
|
||||
<activity android:name="com.google.android.apps.mytracks.io.fusiontables.SendFusionTablesActivity" />
|
||||
<activity android:name="com.google.android.apps.mytracks.io.maps.SendMapsActivity" />
|
||||
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity" />
|
||||
|
||||
@@ -30,8 +30,8 @@ import com.google.android.apps.mytracks.fragments.InstallEarthDialogFragment;
|
||||
import com.google.android.apps.mytracks.fragments.ShareTrackDialogFragment;
|
||||
import com.google.android.apps.mytracks.fragments.ShareTrackDialogFragment.ShareTrackCaller;
|
||||
import com.google.android.apps.mytracks.io.drive.SendDriveActivity;
|
||||
import com.google.android.apps.mytracks.io.file.SaveActivity;
|
||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
||||
import com.google.android.apps.mytracks.io.file.export.SaveActivity;
|
||||
import com.google.android.apps.mytracks.io.fusiontables.SendFusionTablesActivity;
|
||||
import com.google.android.apps.mytracks.io.gdata.maps.MapsConstants;
|
||||
import com.google.android.apps.mytracks.io.maps.SendMapsActivity;
|
||||
|
||||
@@ -30,8 +30,8 @@ import com.google.android.apps.mytracks.fragments.ExportDialogFragment.ExportTyp
|
||||
import com.google.android.apps.mytracks.fragments.FrequencyDialogFragment;
|
||||
import com.google.android.apps.mytracks.fragments.MyTracksMapFragment;
|
||||
import com.google.android.apps.mytracks.fragments.StatsFragment;
|
||||
import com.google.android.apps.mytracks.io.file.SaveActivity;
|
||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
||||
import com.google.android.apps.mytracks.io.file.export.SaveActivity;
|
||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
|
||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||
import com.google.android.apps.mytracks.settings.SettingsActivity;
|
||||
|
||||
@@ -27,8 +27,8 @@ import com.google.android.apps.mytracks.fragments.EulaDialogFragment.EulaCaller;
|
||||
import com.google.android.apps.mytracks.fragments.FileTypeDialogFragment;
|
||||
import com.google.android.apps.mytracks.fragments.FileTypeDialogFragment.FileTypeCaller;
|
||||
import com.google.android.apps.mytracks.io.file.ImportActivity;
|
||||
import com.google.android.apps.mytracks.io.file.SaveActivity;
|
||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
||||
import com.google.android.apps.mytracks.io.file.export.SaveActivity;
|
||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
|
||||
import com.google.android.apps.mytracks.io.sync.SyncUtils;
|
||||
import com.google.android.apps.mytracks.services.ITrackRecordingService;
|
||||
|
||||
@@ -117,8 +117,10 @@ public class TrackDataHub implements DataSourceListener {
|
||||
runInHanderThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
dataSourceManager.updateListeners(trackDataManager.getRegisteredTrackDataTypes());
|
||||
loadDataForAll();
|
||||
if (dataSourceManager != null) {
|
||||
dataSourceManager.updateListeners(trackDataManager.getRegisteredTrackDataTypes());
|
||||
loadDataForAll();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -173,9 +175,11 @@ public class TrackDataHub implements DataSourceListener {
|
||||
runInHanderThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
trackDataManager.registerListener(trackDataListener, trackDataTypes);
|
||||
dataSourceManager.updateListeners(trackDataManager.getRegisteredTrackDataTypes());
|
||||
loadDataForListener(trackDataListener);
|
||||
if (dataSourceManager != null) {
|
||||
trackDataManager.registerListener(trackDataListener, trackDataTypes);
|
||||
dataSourceManager.updateListeners(trackDataManager.getRegisteredTrackDataTypes());
|
||||
loadDataForListener(trackDataListener);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -189,8 +193,10 @@ public class TrackDataHub implements DataSourceListener {
|
||||
runInHanderThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
trackDataManager.unregisterListener(trackDataListener);
|
||||
dataSourceManager.updateListeners(trackDataManager.getRegisteredTrackDataTypes());
|
||||
if (dataSourceManager != null) {
|
||||
trackDataManager.unregisterListener(trackDataListener);
|
||||
dataSourceManager.updateListeners(trackDataManager.getRegisteredTrackDataTypes());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.google.common.annotations.VisibleForTesting;
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -172,7 +173,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
tripStatisticsUpdater = startTime != -1L ? new TripStatisticsUpdater(startTime) : null;
|
||||
pendingPoints.clear();
|
||||
chartView.reset();
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isResumed()) {
|
||||
@@ -211,7 +212,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
if (isResumed()) {
|
||||
chartView.addDataPoints(pendingPoints);
|
||||
pendingPoints.clear();
|
||||
getActivity().runOnUiThread(updateChart);
|
||||
runOnUiThread(updateChart);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +233,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
@Override
|
||||
public void onNewWaypointsDone() {
|
||||
if (isResumed()) {
|
||||
getActivity().runOnUiThread(updateChart);
|
||||
runOnUiThread(updateChart);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +245,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
}
|
||||
metricUnits = metric;
|
||||
chartView.setMetricUnits(metricUnits);
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isResumed()) {
|
||||
@@ -269,7 +270,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
getActivity(), R.string.chart_show_speed_key, PreferencesUtils.CHART_SHOW_SPEED_DEFAULT);
|
||||
setSeriesEnabled(ChartView.SPEED_SERIES, chartShowSpeed && reportSpeed);
|
||||
setSeriesEnabled(ChartView.PACE_SERIES, chartShowSpeed && !reportSpeed);
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isResumed()) {
|
||||
@@ -414,6 +415,18 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
zoomControls.setIsZoomOutEnabled(chartView.canZoomOut());
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a runnable on the UI thread if possible.
|
||||
*
|
||||
* @param runnable the runnable
|
||||
*/
|
||||
private void runOnUiThread(Runnable runnable) {
|
||||
FragmentActivity fragmentActivity = getActivity();
|
||||
if (fragmentActivity != null) {
|
||||
fragmentActivity.runOnUiThread(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a location, fill in a data point, an array of double[]. <br>
|
||||
* data[0] = time/distance <br>
|
||||
|
||||
+8
-1
@@ -98,7 +98,14 @@ public class CheckPermissionFragment extends Fragment {
|
||||
SendToGoogleUtils.getGoogleAccountCredential(getActivity(), accountName, scope);
|
||||
finish(scope, true, null);
|
||||
} catch (UserRecoverableAuthException e) {
|
||||
finish(scope, false, e.getIntent());
|
||||
Intent intent = null;
|
||||
try {
|
||||
// HACK: UserRecoverableAuthException.getIntent can throw a null pointer exception.
|
||||
intent = e.getIntent();
|
||||
} catch (Exception e1) {
|
||||
Log.e(TAG, "Exception in getIntent", e1);
|
||||
}
|
||||
finish(scope, false, intent);
|
||||
} catch (GoogleAuthException e) {
|
||||
Log.e(TAG, "GoogleAuthException", e);
|
||||
finish(scope, false, null);
|
||||
|
||||
@@ -28,7 +28,6 @@ import com.google.android.apps.mytracks.util.StatsUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
@@ -66,7 +65,6 @@ public class MarkerDetailFragment extends Fragment {
|
||||
|
||||
private MyTracksProviderUtils myTracksProviderUtils;
|
||||
private Waypoint waypoint;
|
||||
private Bitmap bitmap;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@@ -97,13 +95,6 @@ public class MarkerDetailFragment extends Fragment {
|
||||
update();
|
||||
}
|
||||
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
if (bitmap != null) {
|
||||
bitmap.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.marker_detail, menu);
|
||||
@@ -180,8 +171,7 @@ public class MarkerDetailFragment extends Fragment {
|
||||
int displayWidth = defaultDisplay.getWidth();
|
||||
@SuppressWarnings("deprecation")
|
||||
int displayHeight = defaultDisplay.getHeight();
|
||||
bitmap = PhotoUtils.setImageVew(
|
||||
imageView, Uri.parse(photoUrl), displayWidth, displayHeight);
|
||||
PhotoUtils.setImageVew(imageView, Uri.parse(photoUrl), displayWidth, displayHeight);
|
||||
}
|
||||
|
||||
TextView name = (TextView) getView().findViewById(R.id.marker_detail_waypoint_name);
|
||||
|
||||
+5
-5
@@ -54,12 +54,12 @@ import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
/**
|
||||
* Abstract class for various importers like {@link GpxImporter} and
|
||||
* {@link KmlImporter}.
|
||||
* Abstract class for various file track importers like {@link GpxFileTrackImporter} and
|
||||
* {@link KmlFileTrackImporter}.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
abstract class AbstractImporter extends DefaultHandler {
|
||||
abstract class AbstractFileTrackImporter extends DefaultHandler implements TrackImporter {
|
||||
|
||||
/**
|
||||
* Data for the current track.
|
||||
@@ -131,12 +131,12 @@ abstract class AbstractImporter extends DefaultHandler {
|
||||
* @param importTrackId the track id to import to. -1L to import to a new
|
||||
* track.
|
||||
*/
|
||||
protected AbstractImporter(Context context, long importTrackId) {
|
||||
protected AbstractFileTrackImporter(Context context, long importTrackId) {
|
||||
this(context, importTrackId, MyTracksProviderUtils.Factory.get(context));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected AbstractImporter(
|
||||
protected AbstractFileTrackImporter(
|
||||
Context context, long importTrackId, MyTracksProviderUtils myTracksProviderUtils) {
|
||||
this.context = context;
|
||||
this.importTrackId = importTrackId;
|
||||
+3
-3
@@ -31,7 +31,7 @@ import org.xml.sax.SAXException;
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class GpxImporter extends AbstractImporter {
|
||||
public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
||||
|
||||
private static final String TAG_DESCRIPTION = "desc";
|
||||
private static final String TAG_COMMENT = "cmt";
|
||||
@@ -54,12 +54,12 @@ public class GpxImporter extends AbstractImporter {
|
||||
* @param context the context
|
||||
* @param importTrackId track id to import to. -1L to import to a new track.
|
||||
*/
|
||||
public GpxImporter(Context context, long importTrackId) {
|
||||
public GpxFileTrackImporter(Context context, long importTrackId) {
|
||||
super(context, importTrackId);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public GpxImporter(Context context, MyTracksProviderUtils myTracksProviderUtils) {
|
||||
public GpxFileTrackImporter(Context context, MyTracksProviderUtils myTracksProviderUtils) {
|
||||
super(context, -1L, myTracksProviderUtils);
|
||||
}
|
||||
|
||||
@@ -158,10 +158,10 @@ public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
*/
|
||||
private boolean importFile(final File file) {
|
||||
try {
|
||||
AbstractImporter importer = trackFileFormat == TrackFileFormat.KML ? new KmlImporter(
|
||||
TrackImporter trackImporter = trackFileFormat == TrackFileFormat.KML ? new KmlFileTrackImporter(
|
||||
context, -1L)
|
||||
: new GpxImporter(context, -1L);
|
||||
long trackIds[] = importer.importFile(new FileInputStream(file));
|
||||
: new GpxFileTrackImporter(context, -1L);
|
||||
long trackIds[] = trackImporter.importFile(new FileInputStream(file));
|
||||
int length = trackIds.length;
|
||||
if (length > 0) {
|
||||
trackId = trackIds[length - 1];
|
||||
|
||||
+8
-3
@@ -36,7 +36,7 @@ import org.xml.sax.SAXException;
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class KmlImporter extends AbstractImporter {
|
||||
public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||
|
||||
private static final String CADENCE = "cadence";
|
||||
private static final String HEART_RATE = "heart_rate";
|
||||
@@ -61,6 +61,7 @@ public class KmlImporter extends AbstractImporter {
|
||||
|
||||
private static final String ATTRIBUTE_NAME = "name";
|
||||
|
||||
private boolean trackStarted = false;
|
||||
private String sensorName;
|
||||
private ArrayList<Location> locationList;
|
||||
private ArrayList<Integer> cadenceList;
|
||||
@@ -73,12 +74,12 @@ public class KmlImporter extends AbstractImporter {
|
||||
* @param context the context
|
||||
* @param importTrackId track id to import to. -1L to import to a new track.
|
||||
*/
|
||||
public KmlImporter(Context context, long importTrackId) {
|
||||
public KmlFileTrackImporter(Context context, long importTrackId) {
|
||||
super(context, importTrackId);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public KmlImporter(Context context, MyTracksProviderUtils myTracksProviderUtils) {
|
||||
public KmlFileTrackImporter(Context context, MyTracksProviderUtils myTracksProviderUtils) {
|
||||
super(context, -1L, myTracksProviderUtils);
|
||||
}
|
||||
|
||||
@@ -88,8 +89,12 @@ public class KmlImporter extends AbstractImporter {
|
||||
if (tag.equals(TAG_PLACEMARK)) {
|
||||
onWaypointStart();
|
||||
} else if (tag.equals(TAG_GX_MULTI_TRACK)) {
|
||||
trackStarted = true;
|
||||
onTrackStart();
|
||||
} else if (tag.equals(TAG_GX_TRACK)) {
|
||||
if (!trackStarted) {
|
||||
throw new SAXException("No " + TAG_GX_MULTI_TRACK);
|
||||
}
|
||||
onTrackSegmentStart();
|
||||
} else if (tag.equals(TAG_GX_SIMPLE_ARRAY_DATA)) {
|
||||
onSensorDataStart(attributes);
|
||||
@@ -1,5 +1,11 @@
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import com.google.android.apps.mytracks.io.file.export.CsvTrackWriter;
|
||||
import com.google.android.apps.mytracks.io.file.export.GpxTrackWriter;
|
||||
import com.google.android.apps.mytracks.io.file.export.KmlTrackWriter;
|
||||
import com.google.android.apps.mytracks.io.file.export.TcxTrackWriter;
|
||||
import com.google.android.apps.mytracks.io.file.export.TrackWriter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
@@ -12,25 +18,25 @@ import java.util.Locale;
|
||||
public enum TrackFileFormat implements Parcelable {
|
||||
KML {
|
||||
@Override
|
||||
TrackFormatWriter newFormatWriter(Context context) {
|
||||
return new KmlTrackWriter(context);
|
||||
public TrackWriter newTrackWriter(Context context, boolean inZip) {
|
||||
return new KmlTrackWriter(context, inZip);
|
||||
}
|
||||
},
|
||||
GPX {
|
||||
@Override
|
||||
TrackFormatWriter newFormatWriter(Context context) {
|
||||
public TrackWriter newTrackWriter(Context context, boolean inZip) {
|
||||
return new GpxTrackWriter(context);
|
||||
}
|
||||
},
|
||||
CSV {
|
||||
@Override
|
||||
public TrackFormatWriter newFormatWriter(Context context) {
|
||||
public TrackWriter newTrackWriter(Context context, boolean inZip) {
|
||||
return new CsvTrackWriter(context);
|
||||
}
|
||||
},
|
||||
TCX {
|
||||
@Override
|
||||
public TrackFormatWriter newFormatWriter(Context context) {
|
||||
public TrackWriter newTrackWriter(Context context, boolean inZip) {
|
||||
return new TcxTrackWriter(context);
|
||||
}
|
||||
};
|
||||
@@ -58,9 +64,9 @@ public enum TrackFileFormat implements Parcelable {
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates and returns a new format writer for each format.
|
||||
* Creates a new track writer for the format.
|
||||
*/
|
||||
abstract TrackFormatWriter newFormatWriter(Context context);
|
||||
public abstract TrackWriter newTrackWriter(Context context, boolean inZip);
|
||||
|
||||
/**
|
||||
* Returns the mime type for each format.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2013 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.io.file;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Interface for a track importer.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public interface TrackImporter {
|
||||
|
||||
public long[] importFile(InputStream inputStream)
|
||||
throws SAXException, IOException, ParserConfigurationException;
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2013 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.io.file.export;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Abstract class for {@link TrackExporter}.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
abstract class AbstractTrackExporter implements TrackExporter {
|
||||
|
||||
private static final String TAG = AbstractTrackExporter.class.getSimpleName();
|
||||
|
||||
private Thread writeThread;
|
||||
private boolean success = false;
|
||||
|
||||
@Override
|
||||
public void writeTrack(final OutputStream outputStream) {
|
||||
writeThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
performWrite(outputStream);
|
||||
success = true;
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Unable to perform write", e);
|
||||
success = false;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to perform write", e);
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
writeThread.start();
|
||||
try {
|
||||
writeThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Interrupted while waiting for write thread to finish", e);
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
abstract void performWrite(OutputStream outputStream) throws InterruptedException, IOException;
|
||||
}
|
||||
+3
-7
@@ -13,7 +13,7 @@
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
package com.google.android.apps.mytracks.io.file.export;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
@@ -21,6 +21,7 @@ import com.google.android.apps.mytracks.content.Sensor.SensorData;
|
||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
@@ -48,7 +49,7 @@ import java.text.NumberFormat;
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class CsvTrackWriter implements TrackFormatWriter {
|
||||
public class CsvTrackWriter implements TrackWriter {
|
||||
|
||||
private static final NumberFormat SHORT_FORMAT = NumberFormat.getInstance();
|
||||
|
||||
@@ -77,11 +78,6 @@ public class CsvTrackWriter implements TrackFormatWriter {
|
||||
pointIndex = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
printWriter.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeHeader(Track track) {
|
||||
writeCommaSeparatedLine(context.getString(R.string.generic_name),
|
||||
+50
-111
@@ -14,7 +14,7 @@
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
package com.google.android.apps.mytracks.io.file.export;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
@@ -22,13 +22,13 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.location.Location;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
@@ -38,32 +38,12 @@ import java.io.OutputStream;
|
||||
* @author Sandor Dornbush
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class TrackWriter {
|
||||
|
||||
/**
|
||||
* Listener for when a track location is written.
|
||||
*/
|
||||
public interface OnWriteListener {
|
||||
|
||||
/**
|
||||
* When a track location is written.
|
||||
*
|
||||
* @param number the location number
|
||||
* @param max the maximum number of locations in a track, for calculation of completion
|
||||
* percentage
|
||||
*/
|
||||
public void onWrite(int number, int max);
|
||||
}
|
||||
|
||||
private final static String TAG = TrackWriter.class.getSimpleName();
|
||||
public class FileTrackExporter extends AbstractTrackExporter {
|
||||
|
||||
private final MyTracksProviderUtils myTracksProviderUtils;
|
||||
private final Track[] tracks;
|
||||
private final TrackFormatWriter trackFormatWriter;
|
||||
private final OnWriteListener onWriteListener;
|
||||
|
||||
private Thread writeThread;
|
||||
private boolean success = false;
|
||||
private final TrackWriter trackWriter;
|
||||
private final TrackExporterListener trackExporterListener;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -72,86 +52,41 @@ public class TrackWriter {
|
||||
* @param myTracksProviderUtils the my tracks provider utils
|
||||
* @param tracks the tracks
|
||||
* @param trackFileFormat the track file format
|
||||
* @param onWriteListener the on write listener
|
||||
* @param trackExporterListener the track export listener
|
||||
*/
|
||||
public TrackWriter(Context context, MyTracksProviderUtils myTracksProviderUtils, Track[] tracks,
|
||||
TrackFileFormat trackFileFormat, OnWriteListener onWriteListener) {
|
||||
this(myTracksProviderUtils, tracks, trackFileFormat.newFormatWriter(context), onWriteListener);
|
||||
public FileTrackExporter(MyTracksProviderUtils myTracksProviderUtils,
|
||||
Track[] tracks, TrackFileFormat trackFileFormat, Context context, boolean inZip,
|
||||
TrackExporterListener trackExporterListener) {
|
||||
this(myTracksProviderUtils, tracks, trackFileFormat.newTrackWriter(context, inZip),
|
||||
trackExporterListener);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public TrackWriter(MyTracksProviderUtils myTracksProviderUtils, Track[] tracks,
|
||||
TrackFormatWriter trackFormatWriter, OnWriteListener onWriteListener) {
|
||||
public FileTrackExporter(MyTracksProviderUtils myTracksProviderUtils, Track[] tracks,
|
||||
TrackWriter trackWriter, TrackExporterListener trackExporterListener) {
|
||||
this.myTracksProviderUtils = myTracksProviderUtils;
|
||||
this.tracks = tracks;
|
||||
this.trackFormatWriter = trackFormatWriter;
|
||||
this.onWriteListener = onWriteListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the write completed successfully.
|
||||
*/
|
||||
public boolean wasSuccess() {
|
||||
return success;
|
||||
this.trackWriter = trackWriter;
|
||||
this.trackExporterListener = trackExporterListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given track to the output stream.
|
||||
*
|
||||
* @param outputStream the output stream.
|
||||
*/
|
||||
public void writeTrack(final OutputStream outputStream) {
|
||||
writeThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
trackFormatWriter.prepare(outputStream);
|
||||
trackFormatWriter.writeHeader(tracks[0]);
|
||||
long startTime = tracks[0].getTripStatistics().getStartTime();
|
||||
for (int i = 0; i < tracks.length; i++) {
|
||||
writeWaypoints(tracks[i]);
|
||||
long offset = tracks[i].getTripStatistics().getStartTime() - startTime;
|
||||
writeLocations(tracks[i], offset);
|
||||
}
|
||||
trackFormatWriter.writeFooter();
|
||||
trackFormatWriter.close();
|
||||
success = true;
|
||||
} catch (InterruptedException e) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
writeThread.start();
|
||||
try {
|
||||
writeThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Interrupted while waiting for write to complete", e);
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops any in-progress writes.
|
||||
*/
|
||||
public void stopWriteTrack() {
|
||||
if (writeThread != null && writeThread.isAlive()) {
|
||||
Log.i(TAG, "Attempting to stop track write");
|
||||
writeThread.interrupt();
|
||||
|
||||
try {
|
||||
writeThread.join();
|
||||
Log.i(TAG, "Track write stopped");
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Interrupted while waiting for writer to stop", e);
|
||||
success = false;
|
||||
}
|
||||
@Override
|
||||
void performWrite(OutputStream outputStream) throws InterruptedException {
|
||||
trackWriter.prepare(outputStream);
|
||||
trackWriter.writeHeader(tracks[0]);
|
||||
long startTime = tracks[0].getTripStatistics().getStartTime();
|
||||
for (int i = 0; i < tracks.length; i++) {
|
||||
writeWaypoints(tracks[i]);
|
||||
long offset = tracks[i].getTripStatistics().getStartTime() - startTime;
|
||||
writeLocations(tracks[i], offset);
|
||||
}
|
||||
trackWriter.writeFooter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the waypoints.
|
||||
*/
|
||||
private void writeWaypoints(Track track) {
|
||||
private void writeWaypoints(Track track) throws InterruptedException {
|
||||
/*
|
||||
* TODO: Stream through the waypoints in chunks. I am leaving the number of
|
||||
* waypoints very high which should not be a problem because we don't try to
|
||||
@@ -168,12 +103,15 @@ public class TrackWriter {
|
||||
* first waypoint holds the stats for the track.
|
||||
*/
|
||||
while (cursor.moveToNext()) {
|
||||
if (Thread.interrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
if (!hasWaypoints) {
|
||||
trackFormatWriter.writeBeginWaypoints();
|
||||
trackWriter.writeBeginWaypoints();
|
||||
hasWaypoints = true;
|
||||
}
|
||||
Waypoint waypoint = myTracksProviderUtils.createWaypoint(cursor);
|
||||
trackFormatWriter.writeWaypoint(waypoint);
|
||||
trackWriter.writeWaypoint(waypoint);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@@ -182,7 +120,7 @@ public class TrackWriter {
|
||||
}
|
||||
}
|
||||
if (hasWaypoints) {
|
||||
trackFormatWriter.writeEndWaypoints();
|
||||
trackWriter.writeEndWaypoints();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,62 +134,63 @@ public class TrackWriter {
|
||||
TrackWriterLocationFactory locationFactory = new TrackWriterLocationFactory();
|
||||
LocationIterator iterator = myTracksProviderUtils.getTrackPointLocationIterator(
|
||||
track.getId(), -1L, false, locationFactory);
|
||||
|
||||
|
||||
try {
|
||||
int locationNumber = 0;
|
||||
while (iterator.hasNext()) {
|
||||
Location location = iterator.next();
|
||||
setLocationTime(location, offset);
|
||||
if (Thread.interrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
Location location = iterator.next();
|
||||
|
||||
setLocationTime(location, offset);
|
||||
locationNumber++;
|
||||
|
||||
boolean isLocationValid = LocationUtils.isValidLocation(location);
|
||||
boolean isSegmentValid = isLocationValid && isLastLocationValid;
|
||||
if (!wroteTrack && isSegmentValid) {
|
||||
// Found the first two consecutive locations that are valid
|
||||
trackFormatWriter.writeBeginTrack(track, locationFactory.lastLocation);
|
||||
// Found the first two consecutive locations that are valid
|
||||
trackWriter.writeBeginTrack(track, locationFactory.lastLocation);
|
||||
wroteTrack = true;
|
||||
}
|
||||
|
||||
if (isSegmentValid) {
|
||||
if (!wroteSegment) {
|
||||
// Start a segment
|
||||
trackFormatWriter.writeOpenSegment();
|
||||
trackWriter.writeOpenSegment();
|
||||
wroteSegment = true;
|
||||
|
||||
// Write the previous location, which we had previously skipped
|
||||
trackFormatWriter.writeLocation(locationFactory.lastLocation);
|
||||
trackWriter.writeLocation(locationFactory.lastLocation);
|
||||
}
|
||||
|
||||
// Write the current location
|
||||
trackFormatWriter.writeLocation(location);
|
||||
if (onWriteListener != null) {
|
||||
onWriteListener.onWrite(locationNumber, track.getNumberOfPoints());
|
||||
trackWriter.writeLocation(location);
|
||||
if (trackExporterListener != null) {
|
||||
trackExporterListener.onProgressUpdate(locationNumber, track.getNumberOfPoints());
|
||||
}
|
||||
} else {
|
||||
if (wroteSegment) {
|
||||
trackFormatWriter.writeCloseSegment();
|
||||
trackWriter.writeCloseSegment();
|
||||
wroteSegment = false;
|
||||
}
|
||||
}
|
||||
locationFactory.swapLocations();
|
||||
isLastLocationValid = isLocationValid;
|
||||
}
|
||||
|
||||
|
||||
if (wroteSegment) {
|
||||
trackFormatWriter.writeCloseSegment();
|
||||
trackWriter.writeCloseSegment();
|
||||
wroteSegment = false;
|
||||
}
|
||||
if (wroteTrack) {
|
||||
Location lastValidTrackPoint = myTracksProviderUtils.getLastValidTrackPoint(track.getId());
|
||||
setLocationTime(lastValidTrackPoint, offset);
|
||||
trackFormatWriter.writeEndTrack(track, lastValidTrackPoint);
|
||||
trackWriter.writeEndTrack(track, lastValidTrackPoint);
|
||||
} else {
|
||||
// Write an empty track
|
||||
trackFormatWriter.writeBeginTrack(track, null);
|
||||
trackFormatWriter.writeEndTrack(track, null);
|
||||
trackWriter.writeBeginTrack(track, null);
|
||||
trackWriter.writeEndTrack(track, null);
|
||||
}
|
||||
} finally {
|
||||
iterator.close();
|
||||
@@ -269,7 +208,7 @@ public class TrackWriter {
|
||||
location.setTime(location.getTime() - offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Track writer location factory. Keeping the last two locations.
|
||||
*
|
||||
+3
-10
@@ -14,10 +14,11 @@
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
package com.google.android.apps.mytracks.io.file.export;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
@@ -34,7 +35,7 @@ import java.util.Locale;
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class GpxTrackWriter implements TrackFormatWriter {
|
||||
public class GpxTrackWriter implements TrackWriter {
|
||||
|
||||
private static final NumberFormat ELEVATION_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||
private static final NumberFormat COORDINATE_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||
@@ -68,14 +69,6 @@ public class GpxTrackWriter implements TrackFormatWriter {
|
||||
this.printWriter = new PrintWriter(outputStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (printWriter != null) {
|
||||
printWriter.close();
|
||||
printWriter = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeHeader(Track track) {
|
||||
if (printWriter != null) {
|
||||
+23
-17
@@ -13,7 +13,7 @@
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
package com.google.android.apps.mytracks.io.file.export;
|
||||
|
||||
import com.google.android.apps.mytracks.content.DescriptionGenerator;
|
||||
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
||||
@@ -25,6 +25,7 @@ import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
||||
import com.google.android.apps.mytracks.util.GoogleEarthUtils;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
@@ -35,6 +36,7 @@ import android.database.Cursor;
|
||||
import android.location.Location;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
@@ -44,7 +46,7 @@ import java.util.ArrayList;
|
||||
*
|
||||
* @author Leif Hendrik Wilden
|
||||
*/
|
||||
public class KmlTrackWriter implements TrackFormatWriter {
|
||||
public class KmlTrackWriter implements TrackWriter {
|
||||
|
||||
private static final String WAYPOINT_STYLE = "waypoint";
|
||||
private static final String STATISTICS_STYLE = "statistics";
|
||||
@@ -68,8 +70,10 @@ public class KmlTrackWriter implements TrackFormatWriter {
|
||||
TRACK_ICON = "http://earth.google.com/images/kml-icons/track-directional/track-0.png";
|
||||
|
||||
private final Context context;
|
||||
private final boolean inKmz;
|
||||
private final DescriptionGenerator descriptionGenerator;
|
||||
private final MyTracksProviderUtils myTracksProviderUtils;
|
||||
|
||||
private PrintWriter printWriter;
|
||||
private ArrayList<Integer> powerList = new ArrayList<Integer>();
|
||||
private ArrayList<Integer> cadenceList = new ArrayList<Integer>();
|
||||
@@ -78,13 +82,14 @@ public class KmlTrackWriter implements TrackFormatWriter {
|
||||
private boolean hasCadence;
|
||||
private boolean hasHeartRate;
|
||||
|
||||
public KmlTrackWriter(Context context) {
|
||||
this(context, new DescriptionGeneratorImpl(context));
|
||||
public KmlTrackWriter(Context context, boolean inKmz) {
|
||||
this(context, inKmz, new DescriptionGeneratorImpl(context));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
KmlTrackWriter(Context context, DescriptionGenerator descriptionGenerator) {
|
||||
KmlTrackWriter(Context context, boolean inKmz, DescriptionGenerator descriptionGenerator) {
|
||||
this.context = context;
|
||||
this.inKmz = inKmz;
|
||||
this.descriptionGenerator = descriptionGenerator;
|
||||
this.myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
|
||||
}
|
||||
@@ -99,14 +104,6 @@ public class KmlTrackWriter implements TrackFormatWriter {
|
||||
this.printWriter = new PrintWriter(outputStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (printWriter != null) {
|
||||
printWriter.close();
|
||||
printWriter = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeHeader(Track track) {
|
||||
if (printWriter != null) {
|
||||
@@ -335,9 +332,8 @@ public class KmlTrackWriter implements TrackFormatWriter {
|
||||
if (location != null) {
|
||||
printWriter.println("<PhotoOverlay>");
|
||||
printWriter.println("<name>" + StringUtils.formatCData(name) + "</name>");
|
||||
printWriter.println("<description>"
|
||||
+ StringUtils.formatCData(StringUtils.getCategoryDescription(category, description))
|
||||
+ "</description>");
|
||||
printWriter.println(
|
||||
"<description>" + StringUtils.formatCData(description) + "</description>");
|
||||
printWriter.print("<Camera>");
|
||||
printWriter.print("<longitude>" + location.getLongitude() + "</longitude>");
|
||||
printWriter.print("<latitude>" + location.getLatitude() + "</latitude>");
|
||||
@@ -345,8 +341,18 @@ public class KmlTrackWriter implements TrackFormatWriter {
|
||||
printWriter.print("<heading>" + heading + "</heading>");
|
||||
printWriter.print("<tilt>90</tilt>");
|
||||
printWriter.println("</Camera>");
|
||||
printWriter.println("<TimeStamp><when>"
|
||||
+ StringUtils.formatDateTimeIso8601(location.getTime()) + "</when></TimeStamp>");
|
||||
printWriter.println("<styleUrl>#" + styleName + "</styleUrl>");
|
||||
printWriter.println("<Icon><href>" + Uri.decode(photoUrl) + "</href></Icon>");
|
||||
writeCategory(category);
|
||||
if (inKmz) {
|
||||
Uri uri = Uri.parse(photoUrl);
|
||||
printWriter.println("<Icon><href>" + KmzTrackExporter.KMZ_IMAGES_DIR + File.separatorChar
|
||||
+ uri.getLastPathSegment() + "</href></Icon>");
|
||||
} else {
|
||||
printWriter.println("<Icon><href>" + Uri.decode(photoUrl) + "</href></Icon>");
|
||||
}
|
||||
|
||||
printWriter.print("<ViewVolume>");
|
||||
printWriter.print("<near>10</near>");
|
||||
printWriter.print("<leftFov>-60</leftFov>");
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2013 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.io.file.export;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* KMZ track exporter.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class KmzTrackExporter extends AbstractTrackExporter {
|
||||
|
||||
public static final String KMZ_IMAGES_DIR = "images";
|
||||
public static final String KMZ_EXTENSION = "kmz";
|
||||
public static final int BUFFER_SIZE = 4096;
|
||||
public static final String KML_FILE_NAME = "doc.kml";
|
||||
|
||||
private final MyTracksProviderUtils myTracksProviderUtils;
|
||||
private final FileTrackExporter fileTrackExporter;
|
||||
private final Track[] tracks;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param myTracksProviderUtils the my tracks provider utils
|
||||
* @param fileTrackExporter the file track exporter
|
||||
* @param tracks the tracks to export
|
||||
*/
|
||||
public KmzTrackExporter(MyTracksProviderUtils myTracksProviderUtils,
|
||||
FileTrackExporter fileTrackExporter, Track[] tracks) {
|
||||
this.myTracksProviderUtils = myTracksProviderUtils;
|
||||
this.fileTrackExporter = fileTrackExporter;
|
||||
this.tracks = tracks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuccess() {
|
||||
return fileTrackExporter.isSuccess() && super.isSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
void performWrite(OutputStream outputStream) throws InterruptedException, IOException {
|
||||
ZipOutputStream zipOutputStream = null;
|
||||
try {
|
||||
zipOutputStream = new ZipOutputStream(outputStream);
|
||||
|
||||
// Add kml file
|
||||
ZipEntry zipEntry = new ZipEntry(KML_FILE_NAME);
|
||||
zipOutputStream.putNextEntry(zipEntry);
|
||||
|
||||
fileTrackExporter.writeTrack(zipOutputStream);
|
||||
zipOutputStream.closeEntry();
|
||||
if (!fileTrackExporter.isSuccess()) {
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
// Add photos
|
||||
addImages(zipOutputStream);
|
||||
} finally {
|
||||
if (zipOutputStream != null) {
|
||||
zipOutputStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addImages(ZipOutputStream zipOutputStream) throws InterruptedException, IOException {
|
||||
for (Track track : tracks) {
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = myTracksProviderUtils.getWaypointCursor(track.getId(), -1L, -1);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
/*
|
||||
* Yes, this will skip the first waypoint and that is intentional as
|
||||
* the first waypoint holds the stats for the track.
|
||||
*/
|
||||
while (cursor.moveToNext()) {
|
||||
if (Thread.interrupted()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
Waypoint waypoint = myTracksProviderUtils.createWaypoint(cursor);
|
||||
String photoUrl = waypoint.getPhotoUrl();
|
||||
if (photoUrl != null && !photoUrl.equals("")) {
|
||||
addImage(zipOutputStream, photoUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addImage(ZipOutputStream zipOutputStream, String photoUrl) throws IOException {
|
||||
Uri uri = Uri.parse(photoUrl);
|
||||
ZipEntry zipEntry = new ZipEntry(
|
||||
KMZ_IMAGES_DIR + File.separatorChar + uri.getLastPathSegment());
|
||||
zipOutputStream.putNextEntry(zipEntry);
|
||||
|
||||
FileInputStream fileInputStream = null;
|
||||
try {
|
||||
fileInputStream = new FileInputStream(new File(uri.getPath()));
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
int byteCount = 0;
|
||||
while ((byteCount = fileInputStream.read(buffer)) != -1) {
|
||||
zipOutputStream.write(buffer, 0, byteCount);
|
||||
}
|
||||
} finally {
|
||||
if (fileInputStream != null) {
|
||||
fileInputStream.close();
|
||||
}
|
||||
}
|
||||
zipOutputStream.closeEntry();
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -14,8 +14,9 @@
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
package com.google.android.apps.mytracks.io.file.export;
|
||||
|
||||
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.GoogleEarthUtils;
|
||||
@@ -99,7 +100,7 @@ public class SaveActivity extends Activity {
|
||||
saveAsyncTask = (SaveAsyncTask) retained;
|
||||
saveAsyncTask.setActivity(this);
|
||||
} else {
|
||||
saveAsyncTask = new SaveAsyncTask(this, trackFileFormat, trackIds, directory);
|
||||
saveAsyncTask = new SaveAsyncTask(this, trackFileFormat, trackIds, directory, playTrack);
|
||||
saveAsyncTask.execute();
|
||||
}
|
||||
}
|
||||
@@ -121,7 +122,6 @@ public class SaveActivity extends Activity {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
saveAsyncTask.cancel(true);
|
||||
dialog.dismiss();
|
||||
finish();
|
||||
}
|
||||
}, directoryDisplayName);
|
||||
return progressDialog;
|
||||
+47
-27
@@ -14,11 +14,12 @@
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
package com.google.android.apps.mytracks.io.file.export;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
||||
import com.google.android.apps.mytracks.util.FileUtils;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||
@@ -33,7 +34,7 @@ import android.util.Log;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Async Task to save tracks to the external storage.
|
||||
@@ -48,11 +49,12 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
private final TrackFileFormat trackFileFormat;
|
||||
private final long[] trackIds;
|
||||
private final File directory;
|
||||
private final boolean playTrack;
|
||||
private final Context context;
|
||||
private final MyTracksProviderUtils myTracksProviderUtils;
|
||||
|
||||
private WakeLock wakeLock;
|
||||
private TrackWriter trackWriter;
|
||||
private TrackExporter trackExporter;
|
||||
|
||||
// true if the AsyncTask has completed
|
||||
private boolean completed;
|
||||
@@ -74,13 +76,15 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
* @param trackIds the track ids to save. To save all, set to size 1 with
|
||||
* trackIds[0] == -1L
|
||||
* @param directory the directory to save to
|
||||
* @param playTrack true to play track
|
||||
*/
|
||||
public SaveAsyncTask(
|
||||
SaveActivity saveActivity, TrackFileFormat trackFileFormat, long[] trackIds, File directory) {
|
||||
public SaveAsyncTask(SaveActivity saveActivity, TrackFileFormat trackFileFormat, long[] trackIds,
|
||||
File directory, boolean playTrack) {
|
||||
this.saveActivity = saveActivity;
|
||||
this.trackFileFormat = trackFileFormat;
|
||||
this.trackIds = trackIds;
|
||||
this.directory = directory;
|
||||
this.playTrack = playTrack;
|
||||
context = saveActivity.getApplicationContext();
|
||||
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
|
||||
|
||||
@@ -163,8 +167,9 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
|
||||
@Override
|
||||
protected void onCancelled() {
|
||||
if (trackWriter != null) {
|
||||
trackWriter.stopWriteTrack();
|
||||
completed = true;
|
||||
if (saveActivity != null) {
|
||||
saveActivity.onAsyncTaskCompleted(successCount, totalCount, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,18 +183,21 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
return false;
|
||||
}
|
||||
Track track = tracks[0];
|
||||
boolean useKmz = !playTrack && trackFileFormat == TrackFileFormat.KML;
|
||||
String extension = useKmz ? KmzTrackExporter.KMZ_EXTENSION : trackFileFormat.getExtension();
|
||||
|
||||
// Make sure the file doesn't exist yet (possibly by changing the filename)
|
||||
String fileName = FileUtils.buildUniqueFileName(
|
||||
directory, track.getName(), trackFileFormat.getExtension());
|
||||
String fileName = FileUtils.buildUniqueFileName(directory, track.getName(), extension);
|
||||
if (fileName == null) {
|
||||
Log.d(TAG, "Unable to get a unique filename for " + track.getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
trackWriter = new TrackWriter(
|
||||
context, myTracksProviderUtils, tracks, trackFileFormat, new TrackWriter.OnWriteListener() {
|
||||
FileTrackExporter fileTrackExporter = new FileTrackExporter(myTracksProviderUtils, tracks,
|
||||
trackFileFormat, context, useKmz, new TrackExporterListener() {
|
||||
|
||||
@Override
|
||||
public void onWrite(int number, int max) {
|
||||
public void onProgressUpdate(int number, int max) {
|
||||
/*
|
||||
* If only saving one track, update the progress dialog once every
|
||||
* 500 points
|
||||
@@ -200,24 +208,36 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
}
|
||||
});
|
||||
|
||||
File file = null;
|
||||
try {
|
||||
file = new File(directory, fileName);
|
||||
OutputStream outputStream = new FileOutputStream(file);
|
||||
trackWriter.writeTrack(outputStream);
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.d(TAG, "File not found " + fileName, e);
|
||||
return false;
|
||||
}
|
||||
trackExporter = useKmz ? new KmzTrackExporter(myTracksProviderUtils, fileTrackExporter, tracks)
|
||||
: fileTrackExporter;
|
||||
|
||||
if (trackWriter.wasSuccess()) {
|
||||
savedPath = file.getAbsolutePath();
|
||||
} else {
|
||||
if (!file.delete()) {
|
||||
Log.w(TAG, "Failed to delete file " + file.getAbsolutePath());
|
||||
File file = new File(directory, fileName);
|
||||
FileOutputStream fileOutputStream = null;
|
||||
try {
|
||||
fileOutputStream = new FileOutputStream(file);
|
||||
trackExporter.writeTrack(fileOutputStream);
|
||||
|
||||
if (trackExporter.isSuccess()) {
|
||||
savedPath = file.getAbsolutePath();
|
||||
return true;
|
||||
} else {
|
||||
if (!file.delete()) {
|
||||
Log.w(TAG, "Failed to delete file " + file.getAbsolutePath());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(TAG, "Unable to open file " + file.getName(), e);
|
||||
return false;
|
||||
} finally {
|
||||
if (fileOutputStream != null) {
|
||||
try {
|
||||
fileOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to close file output stream", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return trackWriter.wasSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
+3
-10
@@ -13,13 +13,14 @@
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
package com.google.android.apps.mytracks.io.file.export;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
@@ -40,7 +41,7 @@ import java.util.Locale;
|
||||
* @author Sandor Dornbush
|
||||
* @author Dominik Rttsches
|
||||
*/
|
||||
public class TcxTrackWriter implements TrackFormatWriter {
|
||||
public class TcxTrackWriter implements TrackWriter {
|
||||
|
||||
/**
|
||||
* TCX sport type. See the TCX spec.
|
||||
@@ -96,14 +97,6 @@ public class TcxTrackWriter implements TrackFormatWriter {
|
||||
this.printWriter = new PrintWriter(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (printWriter != null) {
|
||||
printWriter.close();
|
||||
printWriter = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtension() {
|
||||
return TrackFileFormat.TCX.getExtension();
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2011 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.io.file.export;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Track exporting for exporting track to an {@link OutputStream}.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public interface TrackExporter {
|
||||
|
||||
/**
|
||||
* Write track to an output stream
|
||||
*
|
||||
* @param outputStream the output stream
|
||||
*/
|
||||
void writeTrack(OutputStream outputStream);
|
||||
|
||||
/**
|
||||
* Returns true if {@link #writeTrack(OutputStream)} completed successfully.
|
||||
*/
|
||||
boolean isSuccess();
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2010 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.io.file.export;
|
||||
|
||||
/**
|
||||
* Listener for {@link TrackExporter} progress.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public interface TrackExporterListener {
|
||||
|
||||
/**
|
||||
* Called to update progress.
|
||||
*
|
||||
* @param number the number of locations written
|
||||
* @param max the maximum number of locations in a track, for calculation of
|
||||
* completion percentage
|
||||
*/
|
||||
public void onProgressUpdate(int number, int max);
|
||||
}
|
||||
+2
-7
@@ -13,7 +13,7 @@
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
package com.google.android.apps.mytracks.io.file.export;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
@@ -50,7 +50,7 @@ import java.io.OutputStream;
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public interface TrackFormatWriter {
|
||||
public interface TrackWriter {
|
||||
|
||||
/**
|
||||
* Gets the file extension (i.e. gpx, kml, ...)
|
||||
@@ -64,11 +64,6 @@ public interface TrackFormatWriter {
|
||||
*/
|
||||
public void prepare(OutputStream outputStream);
|
||||
|
||||
/**
|
||||
* Closes the underlying file handler.
|
||||
*/
|
||||
public void close();
|
||||
|
||||
/**
|
||||
* Writes the header for a file
|
||||
*
|
||||
@@ -18,7 +18,7 @@ package com.google.android.apps.mytracks.io.sync;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.io.file.KmlImporter;
|
||||
import com.google.android.apps.mytracks.io.file.KmlFileTrackImporter;
|
||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendToGoogleUtils;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.gms.auth.GoogleAuthException;
|
||||
@@ -348,9 +348,9 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
if (driveFile != null) {
|
||||
InputStream inputStream = downloadDriveFile(driveFile, true);
|
||||
if (inputStream != null) {
|
||||
KmlImporter kmlImporter = new KmlImporter(context, -1L);
|
||||
KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter(context, -1L);
|
||||
try {
|
||||
long[] trackIds = kmlImporter.importFile(inputStream);
|
||||
long[] trackIds = kmlFileTrackImporter.importFile(inputStream);
|
||||
if (trackIds.length == 1) {
|
||||
Track track = myTracksProviderUtils.getTrack(trackIds[0]);
|
||||
if (track == null) {
|
||||
@@ -494,9 +494,9 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
Log.e(TAG, "Unable to update track. Input stream is null for track " + track.getName());
|
||||
return false;
|
||||
}
|
||||
KmlImporter kmlImporter = new KmlImporter(context, track.getId());
|
||||
KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter(context, track.getId());
|
||||
try {
|
||||
long[] trackIds = kmlImporter.importFile(inputStream);
|
||||
long[] trackIds = kmlFileTrackImporter.importFile(inputStream);
|
||||
if (trackIds.length == 1) {
|
||||
Track newTrack = myTracksProviderUtils.getTrack(trackIds[0]);
|
||||
if (newTrack == null) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
||||
import com.google.android.apps.mytracks.io.file.TrackWriter;
|
||||
import com.google.android.apps.mytracks.io.file.export.FileTrackExporter;
|
||||
import com.google.android.apps.mytracks.util.FileUtils;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
@@ -441,15 +441,31 @@ public class SyncUtils {
|
||||
|
||||
java.io.File file = new java.io.File(directory,
|
||||
FileUtils.buildUniqueFileName(directory, track.getName(), trackFileFormat.getExtension()));
|
||||
TrackWriter trackWriter = new TrackWriter(
|
||||
context, myTracksProviderUtils, new Track[] {track}, trackFileFormat, null);
|
||||
FileTrackExporter fileTrackExporter = new FileTrackExporter(
|
||||
myTracksProviderUtils, new Track[] { track }, trackFileFormat, context, false, null);
|
||||
|
||||
trackWriter.writeTrack(new FileOutputStream(file));
|
||||
if (trackWriter.wasSuccess()) {
|
||||
return file;
|
||||
}
|
||||
Log.d(TAG, "Unable to get file for track " + track.getName());
|
||||
return null;
|
||||
FileOutputStream fileOutputStream = null;
|
||||
try {
|
||||
fileOutputStream = new FileOutputStream(file);
|
||||
fileTrackExporter.writeTrack(fileOutputStream);
|
||||
if (fileTrackExporter.isSuccess()) {
|
||||
return file;
|
||||
} else {
|
||||
if (!file.delete()) {
|
||||
Log.d(TAG, "Unable to delete file for track " + track.getName());
|
||||
}
|
||||
Log.d(TAG, "Unable to get file for track " + track.getName());
|
||||
return null;
|
||||
}
|
||||
} finally {
|
||||
if (fileOutputStream != null) {
|
||||
try {
|
||||
fileOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to close file output stream", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 2013 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.services.tasks;
|
||||
|
||||
import com.google.android.apps.mytracks.util.PhotoUtils;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Matrix;
|
||||
import android.media.ExifInterface;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* A bitmap loader.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class BitmapLoader extends AsyncTask<Void, Void, Bitmap> {
|
||||
private static final String TAG = BitmapLoader.class.getSimpleName();
|
||||
|
||||
private final WeakReference<ImageView> imageViewReference;
|
||||
private final Uri uri;
|
||||
private final int displayWidth;
|
||||
private final int displayHeight;
|
||||
|
||||
public BitmapLoader(ImageView imageView, Uri uri, int displayWidth, int displayHeight) {
|
||||
|
||||
// Use a WeakReference to ensure the ImageView can be garbage collected
|
||||
imageViewReference = new WeakReference<ImageView>(imageView);
|
||||
this.uri = uri;
|
||||
this.displayWidth = displayWidth;
|
||||
this.displayHeight = displayHeight;
|
||||
}
|
||||
|
||||
public Uri getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Bitmap doInBackground(Void... params) {
|
||||
|
||||
// Get the image dimensions
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(uri.getPath(), options);
|
||||
|
||||
// Set targetWidth and targetHeight
|
||||
int targetWidth = displayWidth;
|
||||
int targetHeight = displayHeight;
|
||||
if (targetHeight == 0) {
|
||||
targetHeight = (int) (targetWidth * ((float) options.outHeight / (float) options.outWidth));
|
||||
}
|
||||
|
||||
// Set imageWidth and imageHeight based on image rotation
|
||||
int rotation = getRotation();
|
||||
int imageWidth;
|
||||
int imageHeight;
|
||||
|
||||
if (rotation == 0 || rotation == 180) {
|
||||
imageWidth = options.outWidth;
|
||||
imageHeight = options.outHeight;
|
||||
} else {
|
||||
imageWidth = options.outHeight;
|
||||
imageHeight = options.outWidth;
|
||||
}
|
||||
|
||||
// Get a scaled down version of the image
|
||||
options.inJustDecodeBounds = false;
|
||||
options.inSampleSize = getInSampleSize(imageWidth, imageHeight, targetWidth, targetHeight);
|
||||
options.inPurgeable = true;
|
||||
|
||||
Bitmap scaledBitmap = BitmapFactory.decodeFile(uri.getPath(), options);
|
||||
|
||||
// Get the final bitmap after rotating the scaled down image
|
||||
Bitmap bitmap;
|
||||
if (rotation == 0) {
|
||||
bitmap = scaledBitmap;
|
||||
} else {
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.postRotate(rotation);
|
||||
bitmap = Bitmap.createBitmap(
|
||||
scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
|
||||
scaledBitmap.recycle();
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Bitmap bitmap) {
|
||||
if (isCancelled()) {
|
||||
bitmap = null;
|
||||
}
|
||||
// If imageView is still around, set bitmap
|
||||
if (imageViewReference != null && bitmap != null) {
|
||||
ImageView imageView = imageViewReference.get();
|
||||
if (imageView != null) {
|
||||
BitmapLoader bitmapLoader = PhotoUtils.getBitmapLoader(imageView);
|
||||
if (this == bitmapLoader) {
|
||||
imageView.setImageBitmap(bitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getRotation() {
|
||||
try {
|
||||
ExifInterface exifInterface = new ExifInterface(uri.getPath());
|
||||
switch (exifInterface.getAttributeInt(
|
||||
ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)) {
|
||||
case ExifInterface.ORIENTATION_ROTATE_90:
|
||||
return 90;
|
||||
case ExifInterface.ORIENTATION_ROTATE_180:
|
||||
return 180;
|
||||
case ExifInterface.ORIENTATION_ROTATE_270:
|
||||
return 270;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to get photo orientation", e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the in sample size.
|
||||
*
|
||||
* @param imageWidth the image width
|
||||
* @param imageHeight the image height
|
||||
* @param targetWidth the target width
|
||||
* @param targetHeight the target height
|
||||
*/
|
||||
private int getInSampleSize(int imageWidth, int imageHeight, int targetWidth, int targetHeight) {
|
||||
float widthRatio = 1;
|
||||
if (imageWidth > targetWidth) {
|
||||
widthRatio = (float) imageWidth / (float) targetWidth;
|
||||
}
|
||||
|
||||
float heightRatio = 1;
|
||||
if (imageHeight > targetHeight) {
|
||||
heightRatio = (float) imageHeight / (float) targetHeight;
|
||||
}
|
||||
|
||||
/*
|
||||
* To fit within the target area, return the larger sample ratio so the
|
||||
* image will not be larger than the target dimensions. Use Math.floor to
|
||||
* not under sample.
|
||||
*/
|
||||
return (int) Math.floor(Math.max(widthRatio, heightRatio));
|
||||
}
|
||||
}
|
||||
@@ -16,15 +16,12 @@
|
||||
|
||||
package com.google.android.apps.mytracks.util;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Matrix;
|
||||
import android.media.ExifInterface;
|
||||
import com.google.android.apps.mytracks.services.tasks.BitmapLoader;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* Utilities for photos.
|
||||
@@ -33,8 +30,6 @@ import java.io.IOException;
|
||||
*/
|
||||
public class PhotoUtils {
|
||||
|
||||
private static final String TAG = PhotoUtils.class.getSimpleName();
|
||||
|
||||
private PhotoUtils() {}
|
||||
|
||||
/**
|
||||
@@ -45,108 +40,55 @@ public class PhotoUtils {
|
||||
* @param displayWidth the display width
|
||||
* @param displayHeight the display height
|
||||
*/
|
||||
public static Bitmap setImageVew(
|
||||
public static void setImageVew(
|
||||
ImageView imageView, Uri uri, int displayWidth, int displayHeight) {
|
||||
|
||||
// Get the image dimensions
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(uri.getPath(), options);
|
||||
|
||||
// Set targetWidth and targetHeight
|
||||
int targetWidth = displayWidth;
|
||||
int targetHeight = displayHeight;
|
||||
if (targetHeight == 0) {
|
||||
targetHeight = (int) (targetWidth * ((float) options.outHeight / (float) options.outWidth));
|
||||
if (cancelBitmapLoader(imageView, uri)) {
|
||||
BitmapLoader bitmapLoader = new BitmapLoader(imageView, uri, displayWidth, displayHeight);
|
||||
WeakReference<BitmapLoader> bitmapLoaderReference = new WeakReference<BitmapLoader>(
|
||||
bitmapLoader);
|
||||
imageView.setTag(bitmapLoaderReference);
|
||||
bitmapLoader.execute();
|
||||
}
|
||||
|
||||
// Set imageWidth and imageHeight based on image rotation
|
||||
int rotation = getRotation(uri);
|
||||
int imageWidth;
|
||||
int imageHeight;
|
||||
|
||||
if (rotation == 0 || rotation == 180) {
|
||||
imageWidth = options.outWidth;
|
||||
imageHeight = options.outHeight;
|
||||
} else {
|
||||
imageWidth = options.outHeight;
|
||||
imageHeight = options.outWidth;
|
||||
}
|
||||
|
||||
// Get a scaled down version of the image
|
||||
options.inJustDecodeBounds = false;
|
||||
options.inSampleSize = getInSampleSize(imageWidth, imageHeight, targetWidth, targetHeight);
|
||||
options.inPurgeable = true;
|
||||
|
||||
Bitmap scaledBitmap = BitmapFactory.decodeFile(uri.getPath(), options);
|
||||
|
||||
// Get the final bitmap after rotating the scaled down image
|
||||
Bitmap bitmap;
|
||||
if (rotation == 0) {
|
||||
bitmap = scaledBitmap;
|
||||
} else {
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.postRotate(rotation);
|
||||
bitmap = Bitmap.createBitmap(
|
||||
scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
|
||||
scaledBitmap.recycle();
|
||||
}
|
||||
|
||||
imageView.setImageBitmap(bitmap);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the image rotation
|
||||
* Gets the image view bitmap loader.
|
||||
*
|
||||
* @param uri the image uri
|
||||
* @param imageView the image view
|
||||
*/
|
||||
private static int getRotation(Uri uri) {
|
||||
try {
|
||||
ExifInterface exifInterface = new ExifInterface(uri.getPath());
|
||||
switch (exifInterface.getAttributeInt(
|
||||
ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)) {
|
||||
case ExifInterface.ORIENTATION_ROTATE_90:
|
||||
return 90;
|
||||
case ExifInterface.ORIENTATION_ROTATE_180:
|
||||
return 180;
|
||||
case ExifInterface.ORIENTATION_ROTATE_270:
|
||||
return 270;
|
||||
default:
|
||||
return 0;
|
||||
public static BitmapLoader getBitmapLoader(ImageView imageView) {
|
||||
if (imageView != null) {
|
||||
Object object = imageView.getTag();
|
||||
if (object instanceof WeakReference<?>) {
|
||||
@SuppressWarnings("unchecked")
|
||||
WeakReference<BitmapLoader> bitmapLoaderReference = (WeakReference<BitmapLoader>) object;
|
||||
return bitmapLoaderReference.get();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to get photo orientation", e);
|
||||
return 0;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the in sample size.
|
||||
* Cancels the image view bitmap loader.
|
||||
*
|
||||
* @param imageWidth the image width
|
||||
* @param imageHeight the image height
|
||||
* @param targetWidth the target width
|
||||
* @param targetHeight the target height
|
||||
* @param imageView the image view
|
||||
* @param uri the uri
|
||||
* @return false if the bitmap loader shouldn't be canceled. True if there is
|
||||
* no bitmap loader or the bitmap loader is cancelled.
|
||||
*/
|
||||
private static int getInSampleSize(
|
||||
int imageWidth, int imageHeight, int targetWidth, int targetHeight) {
|
||||
float widthRatio = 1;
|
||||
if (imageWidth > targetWidth) {
|
||||
widthRatio = (float) imageWidth / (float) targetWidth;
|
||||
}
|
||||
private static boolean cancelBitmapLoader(ImageView imageView, Uri uri) {
|
||||
BitmapLoader bitmapLoaderAsyncTask = getBitmapLoader(imageView);
|
||||
|
||||
float heightRatio = 1;
|
||||
if (imageHeight > targetHeight) {
|
||||
heightRatio = (float) imageHeight / (float) targetHeight;
|
||||
if (bitmapLoaderAsyncTask != null) {
|
||||
if (bitmapLoaderAsyncTask.getUri().equals(uri)) {
|
||||
// same bitmap loader is already in progress, don't cancel
|
||||
return false;
|
||||
} else {
|
||||
// cancel previous bitmap loader
|
||||
bitmapLoaderAsyncTask.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* To fit within the target area, return the larger sample ratio so the
|
||||
* image will not be larger than the target dimensions. Use Math.floor to
|
||||
* not under sample.
|
||||
*/
|
||||
return (int) Math.floor(Math.max(widthRatio, heightRatio));
|
||||
// imageview has no bitmap loader, or an existing bitmap loader is cancelled
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -42,11 +42,11 @@ import java.util.SimpleTimeZone;
|
||||
import org.easymock.Capture;
|
||||
|
||||
/**
|
||||
* Abstract class for testing importer.
|
||||
* Abstract class for testing file track importers.
|
||||
*
|
||||
* @author Jimmy Shih.
|
||||
*/
|
||||
public class AbstractTestImporter extends AndroidTestCase {
|
||||
public class AbstractTestFileTrackImporter extends AndroidTestCase {
|
||||
|
||||
protected static final String TRACK_NAME_0 = "blablub";
|
||||
protected static final String TRACK_DESCRIPTION_0 = "s'Laebe isch koi Schlotzer";
|
||||
+17
-12
@@ -31,11 +31,11 @@ import org.easymock.Capture;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Tests for {@link GpxImporter}.
|
||||
* Tests for {@link GpxFileTrackImporter}.
|
||||
*
|
||||
* @author Steffen Horlacher
|
||||
*/
|
||||
public class GpxImporterTest extends AbstractTestImporter {
|
||||
public class GpxFileTrackImporterTest extends AbstractTestFileTrackImporter {
|
||||
|
||||
private static String getNameAndDescription(String name, String description) {
|
||||
return "<name><![CDATA[" + name + "]]></name>" + "<desc><![CDATA[" + description + "]]></desc>";
|
||||
@@ -107,8 +107,9 @@ public class GpxImporterTest extends AbstractTestImporter {
|
||||
AndroidMock.replay(myTracksProviderUtils);
|
||||
|
||||
InputStream inputStream = new ByteArrayInputStream(VALID_ONE_TRACK_ONE_SEGMENT_GPX.getBytes());
|
||||
GpxImporter gpxImporter = new GpxImporter(getContext(), myTracksProviderUtils);
|
||||
long[] trackIds = gpxImporter.importFile(inputStream);
|
||||
GpxFileTrackImporter gpxFileTrackImporter = new GpxFileTrackImporter(
|
||||
getContext(), myTracksProviderUtils);
|
||||
long[] trackIds = gpxFileTrackImporter.importFile(inputStream);
|
||||
assertEquals(1, trackIds.length);
|
||||
assertEquals(TRACK_ID_0, trackIds[0]);
|
||||
|
||||
@@ -140,8 +141,9 @@ public class GpxImporterTest extends AbstractTestImporter {
|
||||
AndroidMock.replay(myTracksProviderUtils);
|
||||
|
||||
InputStream inputStream = new ByteArrayInputStream(VALID_ONE_TRACK_TWO_SEGMENTS_GPX.getBytes());
|
||||
GpxImporter gpxImporter = new GpxImporter(getContext(), myTracksProviderUtils);
|
||||
long[] trackIds = gpxImporter.importFile(inputStream);
|
||||
GpxFileTrackImporter gpxFileTrackImporter = new GpxFileTrackImporter(
|
||||
getContext(), myTracksProviderUtils);
|
||||
long[] trackIds = gpxFileTrackImporter.importFile(inputStream);
|
||||
assertEquals(1, trackIds.length);
|
||||
assertEquals(TRACK_ID_0, trackIds[0]);
|
||||
|
||||
@@ -177,8 +179,9 @@ public class GpxImporterTest extends AbstractTestImporter {
|
||||
|
||||
InputStream inputStream = new ByteArrayInputStream(
|
||||
VALID_ONE_TRACK_TWO_SEGMENTS_NO_TIME_GPX.getBytes());
|
||||
GpxImporter gpxImporter = new GpxImporter(getContext(), myTracksProviderUtils);
|
||||
long[] trackIds = gpxImporter.importFile(inputStream);
|
||||
GpxFileTrackImporter gpxFileTrackImporter = new GpxFileTrackImporter(
|
||||
getContext(), myTracksProviderUtils);
|
||||
long[] trackIds = gpxFileTrackImporter.importFile(inputStream);
|
||||
|
||||
assertEquals(1, trackIds.length);
|
||||
assertEquals(TRACK_ID_0, trackIds[0]);
|
||||
@@ -212,8 +215,9 @@ public class GpxImporterTest extends AbstractTestImporter {
|
||||
AndroidMock.replay(myTracksProviderUtils);
|
||||
|
||||
InputStream inputStream = new ByteArrayInputStream(VALID_TWO_TRACKS_GPX.getBytes());
|
||||
GpxImporter gpxImporter = new GpxImporter(getContext(), myTracksProviderUtils);
|
||||
long[] trackIds = gpxImporter.importFile(inputStream);
|
||||
GpxFileTrackImporter gpxFileTrackImporter = new GpxFileTrackImporter(
|
||||
getContext(), myTracksProviderUtils);
|
||||
long[] trackIds = gpxFileTrackImporter.importFile(inputStream);
|
||||
assertEquals(2, trackIds.length);
|
||||
assertEquals(TRACK_ID_0, trackIds[0]);
|
||||
assertEquals(TRACK_ID_1, trackIds[1]);
|
||||
@@ -279,8 +283,9 @@ public class GpxImporterTest extends AbstractTestImporter {
|
||||
|
||||
InputStream inputStream = new ByteArrayInputStream(xml.getBytes());
|
||||
try {
|
||||
GpxImporter gpxImporter = new GpxImporter(getContext(), myTracksProviderUtils);
|
||||
gpxImporter.importFile(inputStream);
|
||||
GpxFileTrackImporter gpxFileTrackImporter = new GpxFileTrackImporter(
|
||||
getContext(), myTracksProviderUtils);
|
||||
gpxFileTrackImporter.importFile(inputStream);
|
||||
} catch (SAXException e) {
|
||||
// expected
|
||||
}
|
||||
+8
-6
@@ -30,11 +30,11 @@ import java.io.InputStream;
|
||||
import org.easymock.Capture;
|
||||
|
||||
/**
|
||||
* Tests for {@link KmlImporter}.
|
||||
* Tests for {@link KmlFileTrackImporter}.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class KmlImporterTest extends AbstractTestImporter {
|
||||
public class KmlFileTrackImporterTest extends AbstractTestFileTrackImporter {
|
||||
|
||||
private static String getNameAndDescription(String name, String description) {
|
||||
return "<name><![CDATA[" + name + "]]></name><description><![CDATA[" + description
|
||||
@@ -85,8 +85,9 @@ public class KmlImporterTest extends AbstractTestImporter {
|
||||
AndroidMock.replay(myTracksProviderUtils);
|
||||
|
||||
InputStream inputStream = new ByteArrayInputStream(VALID_ONE_TRACK_ONE_SEGMENT_GPX.getBytes());
|
||||
KmlImporter kmlImporter = new KmlImporter(getContext(), myTracksProviderUtils);
|
||||
long[] trackIds = kmlImporter.importFile(inputStream);
|
||||
KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter(
|
||||
getContext(), myTracksProviderUtils);
|
||||
long[] trackIds = kmlFileTrackImporter.importFile(inputStream);
|
||||
assertEquals(1, trackIds.length);
|
||||
assertEquals(TRACK_ID_0, trackIds[0]);
|
||||
|
||||
@@ -118,8 +119,9 @@ public class KmlImporterTest extends AbstractTestImporter {
|
||||
AndroidMock.replay(myTracksProviderUtils);
|
||||
|
||||
InputStream inputStream = new ByteArrayInputStream(VALID_ONE_TRACK_TWO_SEGMENTS_GPX.getBytes());
|
||||
KmlImporter kmlImporter = new KmlImporter(getContext(), myTracksProviderUtils);
|
||||
long[] trackIds = kmlImporter.importFile(inputStream);
|
||||
KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter(
|
||||
getContext(), myTracksProviderUtils);
|
||||
long[] trackIds = kmlFileTrackImporter.importFile(inputStream);
|
||||
assertEquals(1, trackIds.length);
|
||||
assertEquals(TRACK_ID_0, trackIds[0]);
|
||||
|
||||
+6
-4
@@ -13,7 +13,9 @@
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
package com.google.android.apps.mytracks.io.file.export;
|
||||
|
||||
import com.google.android.apps.mytracks.io.file.export.CsvTrackWriter;
|
||||
|
||||
|
||||
/**
|
||||
@@ -21,7 +23,7 @@ package com.google.android.apps.mytracks.io.file;
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class CsvTrackWriterTest extends TrackFormatWriterTest {
|
||||
public class CsvTrackWriterTest extends TrackWriterTest {
|
||||
|
||||
private static final String BEGIN_TAG = "\"";
|
||||
private static final String END_TAG = "\"\n";
|
||||
@@ -62,8 +64,8 @@ public class CsvTrackWriterTest extends TrackFormatWriterTest {
|
||||
+ expectedMarkerHeader + expectedMarker1 + expectedMarker2 + "\n"
|
||||
+ expectedPointHeader + expectedPoint1 + expectedPoint2 + expectedPoint3 + expectedPoint4;
|
||||
|
||||
CsvTrackWriter writer = new CsvTrackWriter(getContext());
|
||||
assertEquals(expected, writeTrack(writer));
|
||||
CsvTrackWriter csvTrackWriter = new CsvTrackWriter(getContext());
|
||||
assertEquals(expected, writeTrack(csvTrackWriter));
|
||||
}
|
||||
|
||||
/**
|
||||
+49
-49
@@ -1,13 +1,15 @@
|
||||
// Copyright 2010 Google Inc. All Rights Reserved.
|
||||
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
package com.google.android.apps.mytracks.io.file.export;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProvider;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.io.file.TrackWriter.OnWriteListener;
|
||||
import com.google.android.apps.mytracks.io.file.export.FileTrackExporter;
|
||||
import com.google.android.apps.mytracks.io.file.export.TrackExporterListener;
|
||||
import com.google.android.apps.mytracks.io.file.export.TrackWriter;
|
||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext;
|
||||
import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory;
|
||||
|
||||
@@ -25,11 +27,11 @@ import org.easymock.IArgumentMatcher;
|
||||
import org.easymock.IMocksControl;
|
||||
|
||||
/**
|
||||
* Tests for {@link TrackWriter}.
|
||||
* Tests for {@link FileTrackExporter}.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class TrackWriterTest extends AndroidTestCase {
|
||||
public class FileTrackExporterTest extends AndroidTestCase {
|
||||
|
||||
private static final long TRACK_ID = 1234567L;
|
||||
private static final String TRACK_NAME = "Swimming across the pacific";
|
||||
@@ -39,10 +41,10 @@ public class TrackWriterTest extends AndroidTestCase {
|
||||
|
||||
private IMocksControl mocksControl;
|
||||
|
||||
private TrackFormatWriter trackFormatWriter;
|
||||
private TrackWriter trackWriter;
|
||||
private Track track;
|
||||
private OutputStream outputStream;
|
||||
private TrackWriter trackWriter;
|
||||
private FileTrackExporter fileTrackExporter;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
@@ -61,22 +63,23 @@ public class TrackWriterTest extends AndroidTestCase {
|
||||
myTracksProviderUtils);
|
||||
|
||||
mocksControl = EasyMock.createStrictControl();
|
||||
trackFormatWriter = mocksControl.createMock(TrackFormatWriter.class);
|
||||
trackWriter = mocksControl.createMock(TrackWriter.class);
|
||||
|
||||
track = new Track();
|
||||
track.setName(TRACK_NAME);
|
||||
track.setId(TRACK_ID);
|
||||
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
OnWriteListener onWriteListener = new OnWriteListener() {
|
||||
|
||||
TrackExporterListener trackExporterListener = new TrackExporterListener() {
|
||||
|
||||
@Override
|
||||
public void onWrite(int number, int max) {
|
||||
public void onProgressUpdate(int number, int max) {
|
||||
// Safe to ignore
|
||||
|
||||
}
|
||||
};
|
||||
trackWriter = new TrackWriter(myTracksProviderUtils, new Track[] {track}, trackFormatWriter, onWriteListener);
|
||||
fileTrackExporter = new FileTrackExporter(
|
||||
myTracksProviderUtils, new Track[] { track }, trackWriter, trackExporterListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -91,17 +94,16 @@ public class TrackWriterTest extends AndroidTestCase {
|
||||
public void testWriteTrack_emptyTrack() throws Exception {
|
||||
|
||||
// Set expected mock behavior
|
||||
trackFormatWriter.prepare(outputStream);
|
||||
trackFormatWriter.writeHeader(track);
|
||||
trackFormatWriter.writeBeginTrack(track, null);
|
||||
trackFormatWriter.writeEndTrack(track, null);
|
||||
trackFormatWriter.writeFooter();
|
||||
trackFormatWriter.close();
|
||||
|
||||
trackWriter.prepare(outputStream);
|
||||
trackWriter.writeHeader(track);
|
||||
trackWriter.writeBeginTrack(track, null);
|
||||
trackWriter.writeEndTrack(track, null);
|
||||
trackWriter.writeFooter();
|
||||
|
||||
mocksControl.replay();
|
||||
trackWriter.writeTrack(outputStream);
|
||||
fileTrackExporter.writeTrack(outputStream);
|
||||
|
||||
assertTrue(trackWriter.wasSuccess());
|
||||
assertTrue(fileTrackExporter.isSuccess());
|
||||
mocksControl.verify();
|
||||
}
|
||||
|
||||
@@ -123,17 +125,16 @@ public class TrackWriterTest extends AndroidTestCase {
|
||||
myTracksProviderUtils.bulkInsertTrackPoint(locations, locations.length, TRACK_ID));
|
||||
|
||||
// Set expected mock behavior
|
||||
trackFormatWriter.prepare(outputStream);
|
||||
trackFormatWriter.writeHeader(track);
|
||||
trackFormatWriter.writeBeginTrack(track, null);
|
||||
trackFormatWriter.writeEndTrack(track, null);
|
||||
trackFormatWriter.writeFooter();
|
||||
trackFormatWriter.close();
|
||||
trackWriter.prepare(outputStream);
|
||||
trackWriter.writeHeader(track);
|
||||
trackWriter.writeBeginTrack(track, null);
|
||||
trackWriter.writeEndTrack(track, null);
|
||||
trackWriter.writeFooter();
|
||||
|
||||
mocksControl.replay();
|
||||
trackWriter.writeTrack(outputStream);
|
||||
fileTrackExporter.writeTrack(outputStream);
|
||||
|
||||
assertTrue(trackWriter.wasSuccess());
|
||||
assertTrue(fileTrackExporter.isSuccess());
|
||||
mocksControl.verify();
|
||||
}
|
||||
|
||||
@@ -162,43 +163,42 @@ public class TrackWriterTest extends AndroidTestCase {
|
||||
waypoint.setId(i + 1);
|
||||
}
|
||||
|
||||
trackFormatWriter.prepare(outputStream);
|
||||
trackFormatWriter.writeHeader(track);
|
||||
trackWriter.prepare(outputStream);
|
||||
trackWriter.writeHeader(track);
|
||||
|
||||
// Expect reading/writing of the waypoints (except the first)
|
||||
trackFormatWriter.writeBeginWaypoints();
|
||||
trackFormatWriter.writeWaypoint(waypointEq(waypoints[1]));
|
||||
trackFormatWriter.writeWaypoint(waypointEq(waypoints[2]));
|
||||
trackFormatWriter.writeEndWaypoints();
|
||||
trackWriter.writeBeginWaypoints();
|
||||
trackWriter.writeWaypoint(waypointEq(waypoints[1]));
|
||||
trackWriter.writeWaypoint(waypointEq(waypoints[2]));
|
||||
trackWriter.writeEndWaypoints();
|
||||
|
||||
// Begin the track
|
||||
trackFormatWriter.writeBeginTrack(trackEq(track), locationEq(locations[0]));
|
||||
trackWriter.writeBeginTrack(trackEq(track), locationEq(locations[0]));
|
||||
|
||||
// Write locations 1-2
|
||||
trackFormatWriter.writeOpenSegment();
|
||||
trackFormatWriter.writeLocation(locationEq(locations[0]));
|
||||
trackFormatWriter.writeLocation(locationEq(locations[1]));
|
||||
trackFormatWriter.writeCloseSegment();
|
||||
trackWriter.writeOpenSegment();
|
||||
trackWriter.writeLocation(locationEq(locations[0]));
|
||||
trackWriter.writeLocation(locationEq(locations[1]));
|
||||
trackWriter.writeCloseSegment();
|
||||
|
||||
// Location 3 is not written - it's invalid
|
||||
|
||||
// Write locations 4-6
|
||||
trackFormatWriter.writeOpenSegment();
|
||||
trackFormatWriter.writeLocation(locationEq(locations[3]));
|
||||
trackFormatWriter.writeLocation(locationEq(locations[4]));
|
||||
trackFormatWriter.writeLocation(locationEq(locations[5]));
|
||||
trackFormatWriter.writeCloseSegment();
|
||||
trackWriter.writeOpenSegment();
|
||||
trackWriter.writeLocation(locationEq(locations[3]));
|
||||
trackWriter.writeLocation(locationEq(locations[4]));
|
||||
trackWriter.writeLocation(locationEq(locations[5]));
|
||||
trackWriter.writeCloseSegment();
|
||||
|
||||
// End the track
|
||||
trackFormatWriter.writeEndTrack(trackEq(track), locationEq(locations[5]));
|
||||
trackWriter.writeEndTrack(trackEq(track), locationEq(locations[5]));
|
||||
|
||||
trackFormatWriter.writeFooter();
|
||||
trackFormatWriter.close();
|
||||
trackWriter.writeFooter();
|
||||
|
||||
mocksControl.replay();
|
||||
trackWriter.writeTrack(outputStream);
|
||||
fileTrackExporter.writeTrack(outputStream);
|
||||
|
||||
assertTrue(trackWriter.wasSuccess());
|
||||
assertTrue(fileTrackExporter.isSuccess());
|
||||
mocksControl.verify();
|
||||
}
|
||||
|
||||
+6
-4
@@ -13,7 +13,9 @@
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
package com.google.android.apps.mytracks.io.file.export;
|
||||
|
||||
import com.google.android.apps.mytracks.io.file.export.GpxTrackWriter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -25,11 +27,11 @@ import org.w3c.dom.Element;
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class GpxTrackWriterTest extends TrackFormatWriterTest {
|
||||
public class GpxTrackWriterTest extends TrackWriterTest {
|
||||
|
||||
public void testXmlOutput() throws Exception {
|
||||
TrackFormatWriter writer = new GpxTrackWriter(getContext());
|
||||
String result = writeTrack(writer);
|
||||
GpxTrackWriter gpxTrackWriter = new GpxTrackWriter(getContext());
|
||||
String result = writeTrack(gpxTrackWriter);
|
||||
Document doc = parseXmlDocument(result);
|
||||
|
||||
Element gpxTag = getChildElement(doc, "gpx");
|
||||
+6
-4
@@ -13,10 +13,11 @@
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
package com.google.android.apps.mytracks.io.file.export;
|
||||
|
||||
import com.google.android.apps.mytracks.content.DescriptionGenerator;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.io.file.export.KmlTrackWriter;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
|
||||
import android.location.Location;
|
||||
@@ -32,7 +33,7 @@ import org.w3c.dom.Element;
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class KmlTrackWriterTest extends TrackFormatWriterTest {
|
||||
public class KmlTrackWriterTest extends TrackWriterTest {
|
||||
|
||||
private static final String FULL_TRACK_DESCRIPTION = "full track description";
|
||||
|
||||
@@ -54,8 +55,9 @@ public class KmlTrackWriterTest extends TrackFormatWriterTest {
|
||||
}
|
||||
|
||||
public void testXmlOutput() throws Exception {
|
||||
KmlTrackWriter writer = new KmlTrackWriter(getContext(), new FakeDescriptionGenerator());
|
||||
String result = writeTrack(writer);
|
||||
KmlTrackWriter kmlTrackWriter = new KmlTrackWriter(
|
||||
getContext(), false, new FakeDescriptionGenerator());
|
||||
String result = writeTrack(kmlTrackWriter);
|
||||
Document doc = parseXmlDocument(result);
|
||||
|
||||
Element kmlTag = getChildElement(doc, "kml");
|
||||
+5
-4
@@ -13,10 +13,11 @@
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
package com.google.android.apps.mytracks.io.file.export;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.io.file.export.TcxTrackWriter;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
@@ -29,11 +30,11 @@ import org.w3c.dom.Element;
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class TcxTrackWriterTest extends TrackFormatWriterTest {
|
||||
public class TcxTrackWriterTest extends TrackWriterTest {
|
||||
|
||||
public void testXmlOutput() throws Exception {
|
||||
TrackFormatWriter writer = new TcxTrackWriter(getContext());
|
||||
String result = writeTrack(writer);
|
||||
TcxTrackWriter tcxTrackWriter = new TcxTrackWriter(getContext());
|
||||
String result = writeTrack(tcxTrackWriter);
|
||||
Document doc = parseXmlDocument(result);
|
||||
|
||||
Element root = getChildElement(doc, "TrainingCenterDatabase");
|
||||
+22
-22
@@ -1,10 +1,11 @@
|
||||
// Copyright 2010 Google Inc. All Rights Reserved.
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
package com.google.android.apps.mytracks.io.file.export;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.io.file.export.TrackWriter;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
@@ -34,7 +35,7 @@ import org.xml.sax.SAXException;
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public abstract class TrackFormatWriterTest extends AndroidTestCase {
|
||||
public abstract class TrackWriterTest extends AndroidTestCase {
|
||||
|
||||
// All the user-provided strings have "]]>" to ensure that proper escaping is
|
||||
// being done.
|
||||
@@ -110,29 +111,28 @@ public abstract class TrackFormatWriterTest extends AndroidTestCase {
|
||||
* Makes the right sequence of calls to the writer in order to write the fake
|
||||
* track in {@link #track}.
|
||||
*
|
||||
* @param writer the writer to write to
|
||||
* @param trackWriter the track writer
|
||||
* @return the written contents
|
||||
*/
|
||||
protected String writeTrack(TrackFormatWriter writer) throws Exception {
|
||||
protected String writeTrack(TrackWriter trackWriter) throws Exception {
|
||||
OutputStream output = new ByteArrayOutputStream(BUFFER_SIZE);
|
||||
writer.prepare(output);
|
||||
writer.writeHeader(track);
|
||||
writer.writeBeginWaypoints();
|
||||
writer.writeWaypoint(wp1);
|
||||
writer.writeWaypoint(wp2);
|
||||
writer.writeEndWaypoints();
|
||||
writer.writeBeginTrack(track, location1);
|
||||
writer.writeOpenSegment();
|
||||
writer.writeLocation(location1);
|
||||
writer.writeLocation(location2);
|
||||
writer.writeCloseSegment();
|
||||
writer.writeOpenSegment();
|
||||
writer.writeLocation(location3);
|
||||
writer.writeLocation(location4);
|
||||
writer.writeCloseSegment();
|
||||
writer.writeEndTrack(track, location4);
|
||||
writer.writeFooter();
|
||||
writer.close();
|
||||
trackWriter.prepare(output);
|
||||
trackWriter.writeHeader(track);
|
||||
trackWriter.writeBeginWaypoints();
|
||||
trackWriter.writeWaypoint(wp1);
|
||||
trackWriter.writeWaypoint(wp2);
|
||||
trackWriter.writeEndWaypoints();
|
||||
trackWriter.writeBeginTrack(track, location1);
|
||||
trackWriter.writeOpenSegment();
|
||||
trackWriter.writeLocation(location1);
|
||||
trackWriter.writeLocation(location2);
|
||||
trackWriter.writeCloseSegment();
|
||||
trackWriter.writeOpenSegment();
|
||||
trackWriter.writeLocation(location3);
|
||||
trackWriter.writeLocation(location4);
|
||||
trackWriter.writeCloseSegment();
|
||||
trackWriter.writeEndTrack(track, location4);
|
||||
trackWriter.writeFooter();
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user