diff --git a/MyTracks/AndroidManifest.xml b/MyTracks/AndroidManifest.xml
index 5ff5ac77e..5dc90998b 100755
--- a/MyTracks/AndroidManifest.xml
+++ b/MyTracks/AndroidManifest.xml
@@ -158,17 +158,26 @@ limitations under the License.
-
+
+
-
+
+
+
+
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/MyTracks/res/values/strings.xml b/MyTracks/res/values/strings.xml
index e11616a30..ec8c509b1 100644
--- a/MyTracks/res/values/strings.xml
+++ b/MyTracks/res/values/strings.xml
@@ -1537,8 +1537,7 @@ limitations under the License.
and it will overwrite all the current tracks and settings.
Screenshot: settings_backup_restore_confirm_message.png">
- Restoring a backup from the SD card will overwrite all your current tracks and settings. Are you
- sure?
+ Restoring a backup from the SD card will overwrite all your current tracks and settings.
{
+
+ private ExportAllActivity exportAllActivity;
+ private final TrackFileFormat trackFileFormat;
+ private final Context context;
+ private final MyTracksProviderUtils myTracksProviderUtils;
+ private WakeLock wakeLock;
+ private TrackWriter trackWriter;
+
+ // true if the AsyncTask result is success
+ private boolean success;
+
+ // true if the AsyncTask has completed
+ private boolean completed;
+
+ // message id to return to the activity
+ private int messageId;
+
+ /**
+ * Creates an AsyncTask.
+ *
+ * @param exportAllActivity the activity currently associated with this
+ * AsyncTask
+ * @param trackFileFormat the track file format
+ */
+ public ExportAllAsyncTask(ExportAllActivity exportAllActivity, TrackFileFormat trackFileFormat) {
+ this.exportAllActivity = exportAllActivity;
+ this.trackFileFormat = trackFileFormat;
+ context = exportAllActivity.getApplicationContext();
+ myTracksProviderUtils = MyTracksProviderUtils.Factory.get(exportAllActivity);
+
+ SharedPreferences sharedPreferences = exportAllActivity.getSharedPreferences(
+ Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
+ long recordingTrackId = sharedPreferences.getLong(
+ exportAllActivity.getString(R.string.recording_track_key), -1L);
+
+ // Get the wake lock if not recording
+ if (recordingTrackId == -1L) {
+ wakeLock = SystemUtils.acquireWakeLock(exportAllActivity, wakeLock);
+ }
+ success = false;
+ completed = false;
+ messageId = R.string.export_error;
+ }
+
+ /**
+ * Sets the current {@link ExportAllActivity} associated with this AyncTask.
+ *
+ * @param exportAllActivity the current {@link ExportAllActivity}, can be null
+ */
+ public void setActivity(ExportAllActivity exportAllActivity) {
+ this.exportAllActivity = exportAllActivity;
+ if (completed && exportAllActivity != null) {
+ exportAllActivity.onAsyncTaskCompleted(success, messageId);
+ }
+ }
+
+ @Override
+ protected void onPreExecute() {
+ if (exportAllActivity != null) {
+ exportAllActivity.showProgressDialog();
+ }
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ Cursor cursor = null;
+ try {
+ cursor = myTracksProviderUtils.getTracksCursor(null, null, TracksColumns._ID);
+ if (cursor == null) {
+ messageId = R.string.export_success;
+ return true;
+ }
+ int count = cursor.getCount();
+ int idIndex = cursor.getColumnIndexOrThrow(TracksColumns._ID);
+ for (int i = 0; i < count; i++) {
+ if (isCancelled()) {
+ return false;
+ }
+ cursor.moveToPosition(i);
+ long id = cursor.getLong(idIndex);
+ trackWriter = TrackWriterFactory.newWriter(
+ context, myTracksProviderUtils, id, trackFileFormat);
+ if (trackWriter == null) {
+ return false;
+ }
+ trackWriter.writeTrack();
+
+ if (!trackWriter.wasSuccess()) {
+ messageId = trackWriter.getErrorMessage();
+ return false;
+ }
+ publishProgress(i + 1, count);
+ }
+ messageId = R.string.export_success;
+ return true;
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ // Release the wake lock if obtained
+ if (wakeLock != null && wakeLock.isHeld()) {
+ wakeLock.release();
+ }
+ }
+ }
+
+ @Override
+ protected void onProgressUpdate(Integer... values) {
+ if (exportAllActivity != null) {
+ exportAllActivity.setProgressDialogValue(values[0], values[1]);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ success = result;
+ completed = true;
+ if (exportAllActivity != null) {
+ exportAllActivity.onAsyncTaskCompleted(success, messageId);
+ }
+ }
+
+ @Override
+ protected void onCancelled() {
+ if (trackWriter != null) {
+ trackWriter.stopWriteTrack();
+ }
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/ExportAllTracks.java b/MyTracks/src/com/google/android/apps/mytracks/ExportAllTracks.java
deleted file mode 100644
index ef6169658..000000000
--- a/MyTracks/src/com/google/android/apps/mytracks/ExportAllTracks.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.android.apps.mytracks;
-
-import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
-import com.google.android.apps.mytracks.content.TracksColumns;
-import com.google.android.apps.mytracks.io.file.TrackWriter;
-import com.google.android.apps.mytracks.io.file.TrackWriterFactory;
-import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
-import com.google.android.apps.mytracks.util.SystemUtils;
-import com.google.android.maps.mytracks.R;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.os.PowerManager.WakeLock;
-import android.util.Log;
-import android.widget.Toast;
-
-/**
- * A class that will export all tracks to the sd card.
- *
- * @author Sandor Dornbush
- */
-public class ExportAllTracks {
- // These must line up with the index in the array.
- public static final int GPX_OPTION_INDEX = 0;
- public static final int KML_OPTION_INDEX = 1;
- public static final int CSV_OPTION_INDEX = 2;
- public static final int TCX_OPTION_INDEX = 3;
-
- private final Activity activity;
- private WakeLock wakeLock;
- private ProgressDialog progress;
-
- private TrackFileFormat format = TrackFileFormat.GPX;
-
- private final DialogInterface.OnClickListener itemClick =
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- switch (which) {
- case GPX_OPTION_INDEX:
- format = TrackFileFormat.GPX;
- break;
- case KML_OPTION_INDEX:
- format = TrackFileFormat.KML;
- break;
- case CSV_OPTION_INDEX:
- format = TrackFileFormat.CSV;
- break;
- case TCX_OPTION_INDEX:
- format = TrackFileFormat.TCX;
- break;
- default:
- Log.w(Constants.TAG, "Unknown export format: " + which);
- }
- }
- };
-
- public ExportAllTracks(Activity activity) {
- this.activity = activity;
- Log.i(Constants.TAG, "ExportAllTracks: Starting");
-
- String exportFileFormat = activity.getString(R.string.track_list_export_file);
- String fileTypes[] = activity.getResources().getStringArray(R.array.file_types);
-
- String[] choices = new String[fileTypes.length];
- for (int i = 0; i < fileTypes.length; i++) {
- choices[i] = String.format(exportFileFormat, fileTypes[i]);
- }
-
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setTitle(R.string.track_list_export_all);
- builder.setSingleChoiceItems(choices, 0, itemClick);
- builder.setPositiveButton(R.string.generic_ok, positiveClick);
- builder.setNegativeButton(R.string.generic_cancel, null);
- builder.show();
- }
-
- private final DialogInterface.OnClickListener positiveClick =
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- new Thread(runner, "ExportAllTracks").start();
- }
- };
-
- private final Runnable runner = new Runnable() {
- public void run() {
- aquireLocksAndExport();
- }
- };
-
- /**
- * Makes sure that we keep the phone from sleeping.
- * See if there is a current track. Aquire a wake lock if there is no
- * current track.
- */
- private void aquireLocksAndExport() {
- SharedPreferences prefs = activity.getSharedPreferences(
- Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
- long recordingTrackId = -1;
- if (prefs != null) {
- recordingTrackId =
- prefs.getLong(activity.getString(R.string.recording_track_key), -1);
- }
- if (recordingTrackId != -1) {
- wakeLock = SystemUtils.acquireWakeLock(activity, wakeLock);
- }
-
- // Now we can safely export everything.
- exportAll();
-
- // Release the wake lock if we recorded one.
- // TODO check what happens if we started recording after getting this lock.
- if (wakeLock != null && wakeLock.isHeld()) {
- wakeLock.release();
- Log.i(Constants.TAG, "ExportAllTracks: Releasing wake lock.");
- }
- Log.i(Constants.TAG, "ExportAllTracks: Done");
- showToast(R.string.export_success, Toast.LENGTH_SHORT);
- }
-
- private void makeProgressDialog(final int trackCount) {
- String exportMsg = activity.getString(R.string.track_list_export_all);
- progress = new ProgressDialog(activity);
- progress.setIcon(android.R.drawable.ic_dialog_info);
- progress.setTitle(exportMsg);
- progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- progress.setMax(trackCount);
- progress.setProgress(0);
- progress.show();
- }
-
- /**
- * Actually export the tracks.
- * This should be called after the wake locks have been aquired.
- */
- private void exportAll() {
- // Get a cursor over all tracks.
- Cursor cursor = null;
- try {
- MyTracksProviderUtils providerUtils =
- MyTracksProviderUtils.Factory.get(activity);
- cursor = providerUtils.getTracksCursor(null, null, TracksColumns._ID);
- if (cursor == null) {
- return;
- }
-
- final int trackCount = cursor.getCount();
- Log.i(Constants.TAG,
- "ExportAllTracks: Exporting: " + cursor.getCount() + " tracks.");
- int idxTrackId = cursor.getColumnIndexOrThrow(TracksColumns._ID);
- activity.runOnUiThread(new Runnable() {
- public void run() {
- makeProgressDialog(trackCount);
- }
- });
-
- for (int i = 0; cursor.moveToNext(); i++) {
- final int status = i;
- activity.runOnUiThread(new Runnable() {
- public void run() {
- synchronized (this) {
- if (progress == null) {
- return;
- }
- progress.setProgress(status);
- }
- }
- });
-
- long id = cursor.getLong(idxTrackId);
- Log.i(Constants.TAG, "ExportAllTracks: exporting: " + id);
- TrackWriter writer =
- TrackWriterFactory.newWriter(activity, providerUtils, id, format);
- if (writer == null) {
- showToast(R.string.export_error, Toast.LENGTH_LONG);
- return;
- }
-
- writer.writeTrack();
-
- if (!writer.wasSuccess()) {
- // Abort the whole export on the first error.
- showToast(writer.getErrorMessage(), Toast.LENGTH_LONG);
- return;
- }
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- if (progress != null) {
- synchronized (this) {
- progress.dismiss();
- progress = null;
- }
- }
- }
- }
-
- private void showToast(final int messageId, final int length) {
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(activity, messageId, length).show();
- }
- });
- }
-}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/ImportActivity.java b/MyTracks/src/com/google/android/apps/mytracks/ImportActivity.java
new file mode 100644
index 000000000..8d47e1be3
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/ImportActivity.java
@@ -0,0 +1,207 @@
+/*
+ * 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;
+
+import com.google.android.apps.mytracks.content.TracksColumns;
+import com.google.android.apps.mytracks.util.FileUtils;
+import com.google.android.apps.mytracks.util.UriUtils;
+import com.google.android.maps.mytracks.R;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.ContentUris;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Toast;
+
+/**
+ * An activity to import GPX files from the SD card. Optionally to import one
+ * GPX file and display it in My Tracks.
+ *
+ * @author Rodrigo Damazio
+ */
+public class ImportActivity extends Activity {
+
+ public static final String EXTRA_IMPORT_ALL = "import_all";
+
+ private static final String TAG = ImportActivity.class.getSimpleName();
+
+ private static final int DIALOG_PROGRESS_ID = 0;
+ private static final int DIALOG_RESULT_ID = 1;
+
+ private ImportAsyncTask importAsyncTask;
+ private ProgressDialog progressDialog;
+
+ private boolean importAll;
+
+ // path on the SD card to import
+ private String path;
+
+ // number of succesfully imported files
+ private int successCount;
+
+ // number of files to import
+ private int totalCount;
+
+ // last successfully imported track id
+ private long trackId;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Intent intent = getIntent();
+ importAll = intent.getBooleanExtra(EXTRA_IMPORT_ALL, false);
+ if (importAll) {
+ path = new FileUtils().buildExternalDirectoryPath("gpx");
+ } else {
+ String action = intent.getAction();
+ if (!(Intent.ACTION_ATTACH_DATA.equals(action) || Intent.ACTION_VIEW.equals(action))) {
+ Log.d(TAG, "Invalid action: " + intent);
+ finish();
+ return;
+ }
+
+ Uri data = intent.getData();
+ if (!UriUtils.isFileUri(data)) {
+ Log.d(TAG, "Invalid data: " + intent);
+ finish();
+ return;
+ }
+ path = data.getPath();
+ }
+
+ Object retained = getLastNonConfigurationInstance();
+ if (retained instanceof ImportAsyncTask) {
+ importAsyncTask = (ImportAsyncTask) retained;
+ importAsyncTask.setActivity(this);
+ } else {
+ importAsyncTask = new ImportAsyncTask(this, importAll, path);
+ importAsyncTask.execute();
+ }
+ }
+
+ @Override
+ public Object onRetainNonConfigurationInstance() {
+ importAsyncTask.setActivity(null);
+ return importAsyncTask;
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case DIALOG_PROGRESS_ID:
+ progressDialog = new ProgressDialog(this);
+ progressDialog.setCancelable(true);
+ progressDialog.setIcon(android.R.drawable.ic_dialog_info);
+ progressDialog.setIndeterminate(true);
+ progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ importAsyncTask.cancel(true);
+ finish();
+ }
+ });
+ progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ progressDialog.setTitle(R.string.track_list_import_all);
+ return progressDialog;
+ case DIALOG_RESULT_ID:
+ String message;
+ if (successCount == 0) {
+ message = getString(R.string.import_no_file, path);
+ } else {
+ String totalFiles = getResources()
+ .getQuantityString(R.plurals.importGpxFiles, totalCount, totalCount);
+ message = getString(R.string.import_success, successCount, totalFiles, path);
+ }
+ return new AlertDialog.Builder(this).setCancelable(true)
+ .setCancelable(true)
+ .setMessage(message)
+ .setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ finish();
+ }
+ })
+ .setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (!importAll && trackId != -1L) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setDataAndType(
+ ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId),
+ TracksColumns.CONTENT_ITEMTYPE);
+ startActivity(intent);
+ }
+ finish();
+ }
+ })
+ .create();
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Invokes when the associated AsyncTask completes.
+ *
+ * @param success true if the AsyncTask is successful
+ * @param imported the number of files successfully imported
+ * @param total the total number of files to import
+ * @param id the last successfully imported track id
+ */
+ public void onAsyncTaskCompleted(boolean success, int imported, int total, long id) {
+ successCount = imported;
+ totalCount = total;
+ trackId = id;
+ removeDialog(DIALOG_PROGRESS_ID);
+ if (success) {
+ showDialog(DIALOG_RESULT_ID);
+ } else {
+ Toast.makeText(this, getString(R.string.import_error, path), Toast.LENGTH_LONG).show();
+ finish();
+ }
+ }
+
+ /**
+ * Shows the progress dialog.
+ */
+ public void showProgressDialog() {
+ showDialog(DIALOG_PROGRESS_ID);
+ }
+
+ /**
+ * Sets the progress dialog value.
+ *
+ * @param number the number of files imported
+ * @param max the maximum number of files
+ */
+ public void setProgressDialogValue(int number, int max) {
+ if (progressDialog != null) {
+ progressDialog.setIndeterminate(false);
+ progressDialog.setMax(max);
+ progressDialog.setProgress(Math.min(number, max));
+ }
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/ImportAllTracks.java b/MyTracks/src/com/google/android/apps/mytracks/ImportAllTracks.java
deleted file mode 100644
index db329f7e7..000000000
--- a/MyTracks/src/com/google/android/apps/mytracks/ImportAllTracks.java
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * 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;
-
-import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
-import com.google.android.apps.mytracks.content.TracksColumns;
-import com.google.android.apps.mytracks.io.file.GpxImporter;
-import com.google.android.apps.mytracks.util.FileUtils;
-import com.google.android.apps.mytracks.util.SystemUtils;
-import com.google.android.maps.mytracks.R;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.ContentUris;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.net.Uri;
-import android.os.PowerManager.WakeLock;
-import android.util.Log;
-import android.widget.Toast;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.xml.sax.SAXException;
-
-/**
- * A class that will import all GPX tracks in /sdcard/MyTracks/gpx/
- *
- * @author David Piggott
- */
-public class ImportAllTracks {
-
- private final Activity activity;
- private FileUtils fileUtils;
- private boolean singleTrackSelected;
- private String gpxPath;
- private WakeLock wakeLock;
- private ProgressDialog progress;
- private int gpxFileCount;
- private int importSuccessCount;
- private long importedTrackIds[];
-
- public ImportAllTracks(Activity activity) {
- this(activity, null);
- }
-
- /**
- * Constructor to import tracks.
- *
- * @param activity the activity
- * @param path path of the gpx file to import and display. If null, then just
- * import all the gpx files under MyTracks/gpx and do not display any
- * track.
- */
- public ImportAllTracks(Activity activity, String path) {
- Log.i(Constants.TAG, "ImportAllTracks: Starting");
- this.activity = activity;
- fileUtils = new FileUtils();
- singleTrackSelected = path != null;
- gpxPath = path == null ? fileUtils.buildExternalDirectoryPath("gpx") : path;
- new Thread(runner).start();
- }
-
- private final Runnable runner = new Runnable() {
- public void run() {
- aquireLocksAndImport();
- }
- };
-
- /**
- * Makes sure that we keep the phone from sleeping. See if there is a current
- * track. Acquire a wake lock if there is no current track.
- */
- private void aquireLocksAndImport() {
- SharedPreferences prefs = activity.getSharedPreferences(
- Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
- long recordingTrackId = -1;
- if (prefs != null) {
- recordingTrackId = prefs.getLong(activity.getString(R.string.recording_track_key), -1);
- }
- if (recordingTrackId == -1) {
- wakeLock = SystemUtils.acquireWakeLock(activity, wakeLock);
- }
-
- // Now we can safely import everything.
- importAll();
-
- // Release the wake lock if we acquired one.
- // TODO check what happens if we started recording after getting this lock.
- if (wakeLock != null && wakeLock.isHeld()) {
- wakeLock.release();
- Log.i(Constants.TAG, "ImportAllTracks: Releasing wake lock.");
- }
-
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- showDoneDialog();
- }
- });
- }
-
- private void showDoneDialog() {
- Log.i(Constants.TAG, "ImportAllTracks: Done");
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- if (gpxFileCount == 0) {
- builder.setMessage(activity.getString(R.string.import_no_file, gpxPath));
- } else {
- String totalFiles = activity.getResources().getQuantityString(
- R.plurals.importGpxFiles, gpxFileCount, gpxFileCount);
- builder.setMessage(
- activity.getString(R.string.import_success, importSuccessCount, totalFiles, gpxPath));
- }
- builder.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (singleTrackSelected) {
- long lastTrackId = importedTrackIds[importedTrackIds.length - 1];
- Uri trackUri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, lastTrackId);
-
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(trackUri, TracksColumns.CONTENT_ITEMTYPE);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- activity.startActivity(intent);
- activity.finish();
- }
- }
- });
- builder.show();
- }
-
- private void makeProgressDialog(final int trackCount) {
- String importMsg = activity.getString(R.string.track_list_import_all);
- progress = new ProgressDialog(activity);
- progress.setIcon(android.R.drawable.ic_dialog_info);
- progress.setTitle(importMsg);
- progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- progress.setMax(trackCount);
- progress.setProgress(0);
- progress.show();
- }
-
- /**
- * Actually import the tracks. This should be called after the wake locks have
- * been acquired.
- */
- private void importAll() {
- MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(activity);
-
- if (!fileUtils.isSdCardAvailable()) {
- return;
- }
-
- List gpxFiles = getGpxFiles();
- gpxFileCount = gpxFiles.size();
- if (gpxFileCount == 0) {
- return;
- }
-
- Log.i(Constants.TAG, "ImportAllTracks: Importing: " + gpxFileCount + " tracks.");
- activity.runOnUiThread(new Runnable() {
- public void run() {
- makeProgressDialog(gpxFileCount);
- }
- });
-
- Iterator gpxFilesIterator = gpxFiles.iterator();
- for (int currentFileNumber = 0; gpxFilesIterator.hasNext(); currentFileNumber++) {
- File currentFile = gpxFilesIterator.next();
- final int status = currentFileNumber;
- activity.runOnUiThread(new Runnable() {
- public void run() {
- synchronized (this) {
- if (progress == null) {
- return;
- }
- progress.setProgress(status);
- }
- }
- });
- if (importFile(currentFile, providerUtils)) {
- importSuccessCount++;
- }
- }
-
- if (progress != null) {
- synchronized (this) {
- progress.dismiss();
- progress = null;
- }
- }
- }
-
- /**
- * Attempts to import a GPX file. Returns true on success, issues error
- * notifications and returns false on failure.
- */
- private boolean importFile(final File gpxFile, MyTracksProviderUtils providerUtils) {
- Log.i(Constants.TAG, "ImportAllTracks: importing: " + gpxFile.getName());
- try {
- importedTrackIds = GpxImporter.importGPXFile(new FileInputStream(gpxFile), providerUtils);
- return true;
- } catch (FileNotFoundException e) {
- Log.w(Constants.TAG, "GPX file wasn't found/went missing: "
- + gpxFile.getAbsolutePath(), e);
- } catch (ParserConfigurationException e) {
- Log.w(Constants.TAG, "Error parsing file: " + gpxFile.getAbsolutePath(), e);
- } catch (SAXException e) {
- Log.w(Constants.TAG, "Error parsing file: " + gpxFile.getAbsolutePath(), e);
- } catch (IOException e) {
- Log.w(Constants.TAG, "Error reading file: " + gpxFile.getAbsolutePath(), e);
- }
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(activity, activity.getString(R.string.import_error, gpxFile.getName()),
- Toast.LENGTH_LONG).show();
- }
- });
- return false;
- }
-
- /**
- * Gets a list of the GPX files. If singleTrackSelected is true, returns a
- * list containing just the gpxPath file. If singleTrackSelected is false,
- * returns a list of GPX files under the gpxPath directory.
- */
- private List getGpxFiles() {
- List gpxFiles = new LinkedList();
- File file = new File(gpxPath);
- if (singleTrackSelected) {
- gpxFiles.add(file);
- } else {
- File[] gpxFileCandidates = file.listFiles();
- if (gpxFileCandidates != null) {
- for (File candidate : gpxFileCandidates) {
- if (!candidate.isDirectory() && candidate.getName().endsWith(".gpx")) {
- gpxFiles.add(candidate);
- }
- }
- }
- }
- return gpxFiles;
- }
-}
\ No newline at end of file
diff --git a/MyTracks/src/com/google/android/apps/mytracks/ImportAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/ImportAsyncTask.java
new file mode 100644
index 000000000..4e8898936
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/ImportAsyncTask.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.android.apps.mytracks;
+
+import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
+import com.google.android.apps.mytracks.io.file.GpxImporter;
+import com.google.android.apps.mytracks.util.FileUtils;
+import com.google.android.apps.mytracks.util.SystemUtils;
+import com.google.android.maps.mytracks.R;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+import android.os.PowerManager.WakeLock;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.xml.sax.SAXException;
+
+/**
+ * AsyncTask to import GPX files from the SD card.
+ *
+ * @author Jimmy Shih
+ */
+public class ImportAsyncTask extends AsyncTask {
+
+ private static final String TAG = ImportAsyncTask.class.getSimpleName();
+
+ private ImportActivity importActivity;
+ private final boolean importAll;
+ private final String path;
+ private final MyTracksProviderUtils myTracksProviderUtils;
+ private WakeLock wakeLock;
+
+ // true if the AsyncTask result is success
+ private boolean success;
+
+ // true if the AsyncTask has completed
+ private boolean completed;
+
+ // number of files successfully imported
+ private int successCount;
+
+ // number of files to import
+ private int totalCount;
+
+ // the last successfully imported track id
+ private long trackId;
+
+ /**
+ * Creates an AsyncTask.
+ *
+ * @param importActivity the activity currently associated with this AsyncTask
+ * @param importAll true to import all GPX files
+ * @param path path to import GPX files
+ */
+ public ImportAsyncTask(ImportActivity importActivity, boolean importAll, String path) {
+ this.importActivity = importActivity;
+ this.importAll = importAll;
+ this.path = path;
+
+ myTracksProviderUtils = MyTracksProviderUtils.Factory.get(importActivity);
+ SharedPreferences sharedPreferences = importActivity.getSharedPreferences(
+ Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
+ long recordingTrackId = sharedPreferences.getLong(
+ importActivity.getString(R.string.recording_track_key), -1L);
+
+ // Get the wake lock if not recording
+ if (recordingTrackId == -1L) {
+ wakeLock = SystemUtils.acquireWakeLock(importActivity, wakeLock);
+ }
+
+ success = false;
+ completed = false;
+ successCount = 0;
+ totalCount = 0;
+ trackId = -1L;
+ }
+
+ /**
+ * Sets the current {@link ImportActivity} associated with this AyncTask.
+ *
+ * @param importActivity the current {@link ImportActivity}, can be null
+ */
+ public void setActivity(ImportActivity importActivity) {
+ this.importActivity = importActivity;
+ if (completed && importActivity != null) {
+ importActivity.onAsyncTaskCompleted(success, successCount, totalCount, trackId);
+ }
+ }
+
+ @Override
+ protected void onPreExecute() {
+ if (importActivity != null) {
+ importActivity.showProgressDialog();
+ }
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ try {
+ FileUtils fileUtils = new FileUtils();
+ if (!fileUtils.isSdCardAvailable()) {
+ return false;
+ }
+
+ List files = getFiles();
+ totalCount = files.size();
+ if (totalCount == 0) {
+ return true;
+ }
+
+ for (int i = 0; i < totalCount; i++) {
+ if (isCancelled()) {
+ // If cancelled, return true to show the number of files imported
+ return true;
+ }
+ File file = files.get(i);
+ if (importFile(file)) {
+ successCount++;
+ }
+ publishProgress(i + 1, totalCount);
+ }
+ return true;
+ } finally {
+ // Release the wake lock if obtained
+ if (wakeLock != null && wakeLock.isHeld()) {
+ wakeLock.release();
+ }
+ }
+ }
+
+ @Override
+ protected void onProgressUpdate(Integer... values) {
+ if (importActivity != null) {
+ importActivity.setProgressDialogValue(values[0], values[1]);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ success = result;
+ completed = true;
+ if (importActivity != null) {
+ importActivity.onAsyncTaskCompleted(success, successCount, totalCount, trackId);
+ }
+ }
+
+ /**
+ * Imports a GPX file.
+ *
+ * @param file the file
+ */
+ private boolean importFile(final File file) {
+ try {
+ long trackIds[] = GpxImporter.importGPXFile(new FileInputStream(file), myTracksProviderUtils);
+ int length = trackIds.length;
+ if (length > 0) {
+ trackId = trackIds[length - 1];
+ }
+ return true;
+ } catch (FileNotFoundException e) {
+ Log.d(TAG, "file: " + file.getAbsolutePath(), e);
+ return false;
+ } catch (ParserConfigurationException e) {
+ Log.d(TAG, "file: " + file.getAbsolutePath(), e);
+ return false;
+ } catch (SAXException e) {
+ Log.d(TAG, "file: " + file.getAbsolutePath(), e);
+ return false;
+ } catch (IOException e) {
+ Log.d(TAG, "file: " + file.getAbsolutePath(), e);
+ return false;
+ }
+ }
+
+ /**
+ * Gets a list of GPX files. If importAll is true, returns a list of GPX files
+ * under the path directory. If importAll is false, returns a list containing
+ * just the path file.
+ */
+ private List getFiles() {
+ List files = new ArrayList();
+ File file = new File(path);
+ if (importAll) {
+ File[] candidates = file.listFiles();
+ if (candidates != null) {
+ for (File candidate : candidates) {
+ if (!candidate.isDirectory() && candidate.getName().endsWith(".gpx")) {
+ files.add(candidate);
+ }
+ }
+ }
+ } else {
+ files.add(file);
+ }
+ return files;
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MapActivity.java b/MyTracks/src/com/google/android/apps/mytracks/MapActivity.java
index c4d5ab2d9..7214687d0 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MapActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/MapActivity.java
@@ -22,13 +22,14 @@ import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TrackDataHub;
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
import com.google.android.apps.mytracks.content.TrackDataListener;
-import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.file.SaveActivity;
+import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
+import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.GeoRect;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.PlayTrackUtils;
@@ -38,11 +39,14 @@ import com.google.android.maps.MapView;
import com.google.android.maps.mytracks.R;
import android.app.Dialog;
-import android.content.ContentUris;
+import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
import android.location.Location;
-import android.net.Uri;
import android.os.Bundle;
+import android.os.Parcelable;
import android.provider.Settings;
import android.speech.tts.TextToSpeech;
import android.util.Log;
@@ -72,7 +76,8 @@ public class MapActivity extends com.google.android.maps.MapActivity
implements View.OnTouchListener, View.OnClickListener,
TrackDataListener {
- private static final int DIALOG_INSTALL_EARTH = 0;
+ private static final int DIALOG_INSTALL_EARTH_ID = 0;
+ private static final int DIALOG_DELETE_CURRENT_ID = 1;
// Saved instance state keys:
// ---------------------------
@@ -241,8 +246,26 @@ public class MapActivity extends com.google.android.maps.MapActivity
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
- case DIALOG_INSTALL_EARTH:
+ case DIALOG_INSTALL_EARTH_ID:
return PlayTrackUtils.createInstallEarthDialog(this);
+ case DIALOG_DELETE_CURRENT_ID:
+ return DialogUtils.createConfirmationDialog(this,
+ R.string.track_list_delete_track_confirm_message,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ long trackId = dataHub.getSelectedTrackId();
+ MyTracksProviderUtils.Factory.get(MapActivity.this).deleteTrack(trackId);
+ // If the deleted track was selected, unselect it.
+ String selectedTrackKey = getString(R.string.selected_track_key);
+ SharedPreferences sharedPreferences = getSharedPreferences(
+ Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
+ if (sharedPreferences.getLong(selectedTrackKey, -1L) == trackId) {
+ Editor editor = sharedPreferences.edit().putLong(selectedTrackKey, -1L);
+ ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
+ }
+ }
+ });
default:
return null;
}
@@ -508,7 +531,7 @@ public class MapActivity extends com.google.android.maps.MapActivity
PlayTrackUtils.playTrack(this, trackId);
return true;
} else {
- showDialog(DIALOG_INSTALL_EARTH);
+ showDialog(DIALOG_INSTALL_EARTH_ID);
return true;
}
case Constants.MENU_SEND_TO_GOOGLE:
@@ -527,29 +550,56 @@ public class MapActivity extends com.google.android.maps.MapActivity
startActivity(intent);
return true;
case Constants.MENU_SHARE_GPX_FILE:
- case Constants.MENU_SHARE_KML_FILE:
- case Constants.MENU_SHARE_CSV_FILE:
- case Constants.MENU_SHARE_TCX_FILE:
- case Constants.MENU_SAVE_GPX_FILE:
- case Constants.MENU_SAVE_KML_FILE:
- case Constants.MENU_SAVE_CSV_FILE:
- case Constants.MENU_SAVE_TCX_FILE:
- SaveActivity.handleExportTrackAction(
- this, trackId, Constants.getActionFromMenuId(item.getItemId()));
+ startSaveActivity(trackId, TrackFileFormat.GPX, true);
return true;
+ case Constants.MENU_SHARE_KML_FILE:
+ startSaveActivity(trackId, TrackFileFormat.KML, true);
+ return true;
+ case Constants.MENU_SHARE_CSV_FILE:
+ startSaveActivity(trackId, TrackFileFormat.CSV, true);
+ return true;
+ case Constants.MENU_SHARE_TCX_FILE:
+ startSaveActivity(trackId, TrackFileFormat.TCX, true);
+ return true;
+ case Constants.MENU_SAVE_GPX_FILE:
+ startSaveActivity(trackId, TrackFileFormat.GPX, false);
+ return true;
+ case Constants.MENU_SAVE_KML_FILE:
+ startSaveActivity(trackId, TrackFileFormat.KML, false);
+ return true;
+ case Constants.MENU_SAVE_CSV_FILE:
+ startSaveActivity(trackId, TrackFileFormat.CSV, false);
+ return true;
+ case Constants.MENU_SAVE_TCX_FILE:
+ startSaveActivity(trackId, TrackFileFormat.TCX, false);
+ return true;
case Constants.MENU_CLEAR_MAP:
dataHub.unloadCurrentTrack();
return true;
case Constants.MENU_DELETE:
- Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
- intent = new Intent(Intent.ACTION_DELETE, uri);
- startActivity(intent);
+ showDialog(DIALOG_DELETE_CURRENT_ID);
return true;
default:
return super.onMenuItemSelected(featureId, item);
}
}
+ /**
+ * Starts the {@link SaveActivity} to save a track.
+ *
+ * @param trackId the track id
+ * @param trackFileFormat the track file format
+ * @param shareTrack true to share the track after saving
+ */
+ private void startSaveActivity(
+ long trackId, TrackFileFormat trackFileFormat, boolean shareTrack) {
+ Intent intent = new Intent(this, SaveActivity.class)
+ .putExtra(SaveActivity.EXTRA_TRACK_ID, trackId)
+ .putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) trackFileFormat)
+ .putExtra(SaveActivity.EXTRA_SHARE_TRACK, shareTrack);
+ startActivity(intent);
+ }
+
/**
* Returns whether the map is currently in satellite view mode.
*/
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java
index 2c156b54c..479739111 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java
@@ -70,7 +70,10 @@ import android.widget.Toast;
@SuppressWarnings("deprecation")
public class MyTracks extends TabActivity implements OnTouchListener {
private static final int DIALOG_EULA_ID = 0;
-
+ private static final int DIALOG_CHECK_UNITS_ID = 1;
+ private static final String CHECK_UNITS_PREFERENCE_FILE = "checkunits";
+ private static final String CHECK_UNITS_PREFERENCE_KEY = "checkunits.checked";
+
private TrackDataHub dataHub;
/**
@@ -262,31 +265,59 @@ public class MyTracks extends TabActivity implements OnTouchListener {
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_EULA_ID:
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.eula_title);
- builder.setMessage(EulaUtils.getEulaMessage(this));
- builder.setPositiveButton(R.string.eula_accept, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- EulaUtils.setEulaValue(MyTracks.this);
- Intent startIntent = new Intent(MyTracks.this, WelcomeActivity.class);
- startActivityForResult(startIntent, Constants.WELCOME);
- }
- });
- builder.setNegativeButton(R.string.eula_decline, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- finish();
- }
- });
- builder.setCancelable(true);
- builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialog) {
- finish();
- }
- });
- return builder.create();
+ return new AlertDialog.Builder(this)
+ .setCancelable(true)
+ .setMessage(EulaUtils.getEulaMessage(this))
+ .setNegativeButton(R.string.eula_decline, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ })
+ .setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ finish();
+ }
+ })
+ .setPositiveButton(R.string.eula_accept, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ EulaUtils.setEulaValue(MyTracks.this);
+ Intent startIntent = new Intent(MyTracks.this, WelcomeActivity.class);
+ startActivityForResult(startIntent, Constants.WELCOME);
+ }
+ })
+ .setTitle(R.string.eula_title)
+ .create();
+ case DIALOG_CHECK_UNITS_ID:
+ return new AlertDialog.Builder(this)
+ .setCancelable(true)
+ .setOnCancelListener(new DialogInterface.OnCancelListener() {
+ public void onCancel(DialogInterface dialog) {
+ SharedPreferences sharedPreferences = getSharedPreferences(
+ CHECK_UNITS_PREFERENCE_FILE, Context.MODE_PRIVATE);
+ ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(
+ sharedPreferences.edit().putBoolean(CHECK_UNITS_PREFERENCE_KEY, true));
+ }
+ })
+ .setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ SharedPreferences sharedPreferences = getSharedPreferences(
+ CHECK_UNITS_PREFERENCE_FILE, Context.MODE_PRIVATE);
+ ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(
+ sharedPreferences.edit().putBoolean(CHECK_UNITS_PREFERENCE_KEY, true));
+
+ int position = ((AlertDialog) dialog).getListView().getSelectedItemPosition();
+ SharedPreferences.Editor editor = preferences.edit();
+ ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(
+ editor.putBoolean(getString(R.string.metric_units_key), position == 0));
+ }
+ })
+ .setSingleChoiceItems(new CharSequence[] { getString(R.string.preferred_units_metric),
+ getString(R.string.preferred_units_imperial) }, 0, null)
+ .setTitle(R.string.preferred_units_title)
+ .create();
default:
return null;
}
@@ -380,7 +411,11 @@ public class MyTracks extends TabActivity implements OnTouchListener {
break;
}
case Constants.WELCOME: {
- CheckUnits.check(this);
+ SharedPreferences sharedPreferences = getSharedPreferences(
+ CHECK_UNITS_PREFERENCE_FILE, Context.MODE_PRIVATE);
+ if (!sharedPreferences.getBoolean(CHECK_UNITS_PREFERENCE_KEY, false)) {
+ showDialog(DIALOG_CHECK_UNITS_ID);
+ }
break;
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/SettingsActivity.java b/MyTracks/src/com/google/android/apps/mytracks/SettingsActivity.java
index 76af12627..0d66d3c85 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/SettingsActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/SettingsActivity.java
@@ -17,8 +17,9 @@ package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.Constants.TAG;
-import com.google.android.apps.mytracks.io.backup.BackupActivityHelper;
+import com.google.android.apps.mytracks.io.backup.BackupActivity;
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
+import com.google.android.apps.mytracks.io.backup.RestoreChooserActivity;
import com.google.android.apps.mytracks.services.sensors.ant.AntUtils;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.BluetoothDeviceUtils;
@@ -62,8 +63,9 @@ import java.util.Set;
*/
public class SettingsActivity extends PreferenceActivity {
- private static final int DIALOG_CONFIRM_RESET = 0;
- private static final int DIALOG_CONFIRM_ACCESS = 1;
+ private static final int DIALOG_CONFIRM_RESET_ID = 0;
+ private static final int DIALOG_CONFIRM_ACCESS_ID = 1;
+ private static final int DIALOG_CONFIRM_RESTORE_ID = 2;
// Value when the task frequency is off.
private static final String TASK_FREQUENCY_OFF = "0";
@@ -150,7 +152,7 @@ public class SettingsActivity extends PreferenceActivity {
resetPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference arg0) {
- showDialog(DIALOG_CONFIRM_RESET);
+ showDialog(DIALOG_CONFIRM_RESET_ID);
return true;
}
});
@@ -162,7 +164,7 @@ public class SettingsActivity extends PreferenceActivity {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if ((Boolean) newValue) {
- showDialog(DIALOG_CONFIRM_ACCESS);
+ showDialog(DIALOG_CONFIRM_ACCESS_ID);
return false;
} else {
return true;
@@ -174,7 +176,7 @@ public class SettingsActivity extends PreferenceActivity {
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
- case DIALOG_CONFIRM_RESET:
+ case DIALOG_CONFIRM_RESET_ID:
return DialogUtils.createConfirmationDialog(
this, R.string.settings_reset_confirm_message, new OnClickListener() {
@Override
@@ -182,7 +184,7 @@ public class SettingsActivity extends PreferenceActivity {
onResetPreferencesConfirmed();
}
});
- case DIALOG_CONFIRM_ACCESS:
+ case DIALOG_CONFIRM_ACCESS_ID:
return DialogUtils.createConfirmationDialog(
this, R.string.settings_sharing_allow_access_confirm_message, new OnClickListener() {
@Override
@@ -192,6 +194,14 @@ public class SettingsActivity extends PreferenceActivity {
pref.setChecked(true);
}
});
+ case DIALOG_CONFIRM_RESTORE_ID:
+ return DialogUtils.createConfirmationDialog(
+ this, R.string.settings_backup_restore_confirm_message, new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ startActivity(new Intent(SettingsActivity.this, RestoreChooserActivity.class));
+ }
+ });
default:
return null;
}
@@ -354,9 +364,7 @@ public class SettingsActivity extends PreferenceActivity {
new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
- BackupActivityHelper backupHelper =
- new BackupActivityHelper(SettingsActivity.this);
- backupHelper.writeBackup();
+ startActivity(new Intent(SettingsActivity.this, BackupActivity.class));
return true;
}
});
@@ -364,9 +372,7 @@ public class SettingsActivity extends PreferenceActivity {
new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
- BackupActivityHelper backupHelper =
- new BackupActivityHelper(SettingsActivity.this);
- backupHelper.restoreBackup();
+ showDialog(DIALOG_CONFIRM_RESTORE_ID);
return true;
}
});
diff --git a/MyTracks/src/com/google/android/apps/mytracks/TrackList.java b/MyTracks/src/com/google/android/apps/mytracks/TrackList.java
index cbbf32efa..c71b03aab 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/TrackList.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/TrackList.java
@@ -17,26 +17,31 @@ package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.Constants.TAG;
+import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.io.file.SaveActivity;
+import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity;
import com.google.android.apps.mytracks.services.ServiceUtils;
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
+import com.google.android.apps.mytracks.util.ApiAdapterFactory;
+import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.PlayTrackUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
+import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
-import android.content.ContentUris;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
import android.database.Cursor;
-import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
+import android.os.Parcelable;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
@@ -62,7 +67,10 @@ public class TrackList extends ListActivity
implements SharedPreferences.OnSharedPreferenceChangeListener,
View.OnClickListener {
- private static final int DIALOG_INSTALL_EARTH = 0;
+ private static final int DIALOG_INSTALL_EARTH_ID = 0;
+ private static final int DIALOG_EXPORT_ALL_ID = 1;
+ private static final int DIALOG_DELETE_ALL_ID = 2;
+ private static final int DIALOG_DELETE_CURRENT_ID = 3;
private int contextPosition = -1;
private long trackId = -1;
@@ -178,7 +186,7 @@ public class TrackList extends ListActivity
PlayTrackUtils.playTrack(this, trackId);
return true;
} else {
- showDialog(DIALOG_INSTALL_EARTH);
+ showDialog(DIALOG_INSTALL_EARTH_ID);
return true;
}
case Constants.MENU_SEND_TO_GOOGLE:
@@ -197,21 +205,31 @@ public class TrackList extends ListActivity
startActivity(intent);
return true;
case Constants.MENU_SHARE_GPX_FILE:
- case Constants.MENU_SHARE_KML_FILE:
- case Constants.MENU_SHARE_CSV_FILE:
- case Constants.MENU_SHARE_TCX_FILE:
- case Constants.MENU_SAVE_GPX_FILE:
- case Constants.MENU_SAVE_KML_FILE:
- case Constants.MENU_SAVE_CSV_FILE:
- case Constants.MENU_SAVE_TCX_FILE:
- SaveActivity.handleExportTrackAction(
- this, trackId, Constants.getActionFromMenuId(item.getItemId()));
+ startSaveActivity(TrackFileFormat.GPX, true);
return true;
+ case Constants.MENU_SHARE_KML_FILE:
+ startSaveActivity(TrackFileFormat.KML, true);
+ return true;
+ case Constants.MENU_SHARE_CSV_FILE:
+ startSaveActivity(TrackFileFormat.CSV, true);
+ return true;
+ case Constants.MENU_SHARE_TCX_FILE:
+ startSaveActivity(TrackFileFormat.TCX, true);
+ return true;
+ case Constants.MENU_SAVE_GPX_FILE:
+ startSaveActivity(TrackFileFormat.GPX, false);
+ return true;
+ case Constants.MENU_SAVE_KML_FILE:
+ startSaveActivity(TrackFileFormat.KML, false);
+ return true;
+ case Constants.MENU_SAVE_CSV_FILE:
+ startSaveActivity(TrackFileFormat.CSV, false);
+ return true;
+ case Constants.MENU_SAVE_TCX_FILE:
+ startSaveActivity(TrackFileFormat.TCX, false);
+ return true;
case Constants.MENU_DELETE:
- Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
- intent = new Intent(Intent.ACTION_DELETE)
- .setDataAndType(uri, TracksColumns.CONTENT_ITEMTYPE);
- startActivity(intent);
+ showDialog(DIALOG_DELETE_CURRENT_ID);
return true;
default:
Log.w(TAG, "Unknown menu item: " + item.getItemId() + "(" + item.getTitle() + ")");
@@ -219,22 +237,34 @@ public class TrackList extends ListActivity
}
}
+ /**
+ * Starts the {@link SaveActivity} to save trackId.
+ *
+ * @param trackFileFormat the track file format
+ * @param shareTrack true to share the track after saving
+ */
+ private void startSaveActivity(TrackFileFormat trackFileFormat, boolean shareTrack) {
+ Intent intent = new Intent(this, SaveActivity.class)
+ .putExtra(SaveActivity.EXTRA_TRACK_ID, trackId)
+ .putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) trackFileFormat)
+ .putExtra(SaveActivity.EXTRA_SHARE_TRACK, shareTrack);
+ startActivity(intent);
+ }
+
@Override
public void onClick(View v) {
switch (v.getId()) {
- case R.id.tracklist_btn_delete_all: {
- Handler h = new DeleteAllTracks(this, null);
- h.handleMessage(null);
+ case R.id.tracklist_btn_delete_all:
+ showDialog(DIALOG_DELETE_ALL_ID);
break;
- }
- case R.id.tracklist_btn_export_all: {
- new ExportAllTracks(this);
+ case R.id.tracklist_btn_export_all:
+ showDialog(DIALOG_EXPORT_ALL_ID);
break;
- }
- case R.id.tracklist_btn_import_all: {
- new ImportAllTracks(this);
- break;
- }
+ case R.id.tracklist_btn_import_all:
+ Intent intent = new Intent(this, ImportActivity.class)
+ .putExtra(ImportActivity.EXTRA_IMPORT_ALL, true);
+ startActivity(intent);
+ break;
}
}
@@ -298,8 +328,60 @@ public class TrackList extends ListActivity
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
- case DIALOG_INSTALL_EARTH:
+ case DIALOG_INSTALL_EARTH_ID:
return PlayTrackUtils.createInstallEarthDialog(this);
+ case DIALOG_EXPORT_ALL_ID:
+ String exportFileFormat = getString(R.string.track_list_export_file);
+ String fileTypes[] = getResources().getStringArray(R.array.file_types);
+ String[] choices = new String[fileTypes.length];
+ for (int i = 0; i < fileTypes.length; i++) {
+ choices[i] = String.format(exportFileFormat, fileTypes[i]);
+ }
+ return new AlertDialog.Builder(this)
+ .setNegativeButton(R.string.generic_cancel, null)
+ .setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ int index = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
+ Intent intent = new Intent(TrackList.this, ExportAllActivity.class);
+ intent.putExtra(ExportAllActivity.EXTRA_TRACK_FILE_FORMAT,
+ (Parcelable) TrackFileFormat.values()[index]);
+ TrackList.this.startActivity(intent);
+ }
+ })
+ .setSingleChoiceItems(choices, 0, null)
+ .setTitle(R.string.track_list_export_all)
+ .create();
+ case DIALOG_DELETE_ALL_ID:
+ return DialogUtils.createConfirmationDialog(this,
+ R.string.track_list_delete_all_confirm_message, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ MyTracksProviderUtils.Factory.get(TrackList.this).deleteAllTracks();
+ SharedPreferences sharedPreferences = getSharedPreferences(
+ Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
+ Editor editor = sharedPreferences.edit();
+ // TODO: Go through data manager
+ editor.putLong(getString(R.string.selected_track_key), -1L);
+ ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
+ }
+ });
+ case DIALOG_DELETE_CURRENT_ID:
+ return DialogUtils.createConfirmationDialog(this,
+ R.string.track_list_delete_track_confirm_message, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ MyTracksProviderUtils.Factory.get(TrackList.this).deleteTrack(trackId);
+ // If the deleted track was selected, unselect it.
+ String selectedTrackKey = getString(R.string.selected_track_key);
+ SharedPreferences sharedPreferences = getSharedPreferences(
+ Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
+ if (sharedPreferences.getLong(selectedTrackKey, -1L) == trackId) {
+ Editor editor = sharedPreferences.edit().putLong(selectedTrackKey, -1L);
+ ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
+ }
+ }
+ });
default:
return null;
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/WaypointsList.java b/MyTracks/src/com/google/android/apps/mytracks/WaypointsList.java
index 792026215..135caffc5 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/WaypointsList.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/WaypointsList.java
@@ -24,10 +24,11 @@ import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.content.WaypointsColumns;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
+import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
-import android.app.AlertDialog;
+import android.app.Dialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.DialogInterface;
@@ -57,9 +58,10 @@ import android.widget.Toast;
*
* @author Leif Hendrik Wilden
*/
-public class WaypointsList extends ListActivity
- implements View.OnClickListener {
+public class WaypointsList extends ListActivity implements View.OnClickListener {
+ private static final int DIALOG_DELETE_CURRENT_ID = 0;
+
private int contextPosition = -1;
private long trackId = -1;
private long selectedWaypointId = -1;
@@ -119,7 +121,7 @@ public class WaypointsList extends ListActivity
return true;
}
case Constants.MENU_DELETE: {
- deleteWaypoint(selectedWaypointId);
+ showDialog(DIALOG_DELETE_CURRENT_ID);
}
}
}
@@ -199,6 +201,24 @@ public class WaypointsList extends ListActivity
super.onDestroy();
}
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case DIALOG_DELETE_CURRENT_ID:
+ return DialogUtils.createConfirmationDialog(this,
+ R.string.marker_list_delete_marker_confirm_message,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ providerUtils.deleteWaypoint(
+ selectedWaypointId, new DescriptionGeneratorImpl(WaypointsList.this));
+ }
+ });
+ default:
+ return null;
+ }
+ }
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search_only, menu);
@@ -303,34 +323,4 @@ public class WaypointsList extends ListActivity
});
setListAdapter(adapter);
}
-
- /**
- * Deletes the way point with the given id.
- * Prompts the user if he want to really delete it.
- */
- public void deleteWaypoint(final long waypointId) {
- AlertDialog dialog = null;
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setMessage(getString(R.string.marker_list_delete_marker_confirm_message));
- builder.setTitle(getString(R.string.generic_confirm_title));
- builder.setIcon(android.R.drawable.ic_dialog_alert);
- builder.setPositiveButton(getString(R.string.generic_yes),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- dialogInterface.dismiss();
- providerUtils.deleteWaypoint(waypointId,
- new DescriptionGeneratorImpl(WaypointsList.this));
- }
- });
- builder.setNegativeButton(getString(R.string.generic_no),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- dialogInterface.dismiss();
- }
- });
- dialog = builder.create();
- dialog.show();
- }
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupActivity.java b/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupActivity.java
new file mode 100644
index 000000000..2db4e61da
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupActivity.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2012 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.backup;
+
+import com.google.android.maps.mytracks.R;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.widget.Toast;
+
+/**
+ * Activity to backup data to the SD card.
+ *
+ * @author Jimmy Shih
+ */
+public class BackupActivity extends Activity {
+
+ private static final int DIALOG_PROGRESS_ID = 0;
+
+ private BackupAsyncTask backupAsyncTask;
+ private ProgressDialog progressDialog;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Object retained = getLastNonConfigurationInstance();
+ if (retained instanceof BackupAsyncTask) {
+ backupAsyncTask = (BackupAsyncTask) retained;
+ backupAsyncTask.setActivity(this);
+ } else {
+ backupAsyncTask = new BackupAsyncTask(this);
+ backupAsyncTask.execute();
+ }
+ }
+
+ @Override
+ public Object onRetainNonConfigurationInstance() {
+ backupAsyncTask.setActivity(null);
+ return backupAsyncTask;
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case DIALOG_PROGRESS_ID:
+ progressDialog = new ProgressDialog(this);
+ progressDialog.setCancelable(true);
+ progressDialog.setIcon(android.R.drawable.ic_dialog_info);
+ progressDialog.setIndeterminate(true);
+ progressDialog.setMessage(getString(R.string.settings_backup_now_progress_message));
+ progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ finish();
+ }
+ });
+ progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ progressDialog.setTitle(R.string.generic_progress_title);
+ return progressDialog;
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Invokes when the associated AsyncTask completes.
+ *
+ * @param success true if the AsyncTask is successful
+ * @param messageId message id to display to user
+ */
+ public void onAsyncTaskCompleted(boolean success, int messageId) {
+ removeDialog(DIALOG_PROGRESS_ID);
+ Toast.makeText(this, messageId, success ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG).show();
+ finish();
+ }
+
+ /**
+ * Shows the progress dialog.
+ */
+ public void showProgressDialog() {
+ showDialog(DIALOG_PROGRESS_ID);
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupActivityHelper.java b/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupActivityHelper.java
deleted file mode 100644
index d78d8c96e..000000000
--- a/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupActivityHelper.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * 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.backup;
-
-import com.google.android.apps.mytracks.Constants;
-import com.google.android.apps.mytracks.MyTracks;
-import com.google.android.apps.mytracks.util.FileUtils;
-import com.google.android.apps.mytracks.util.StringUtils;
-import com.google.android.maps.mytracks.R;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.AlertDialog.Builder;
-import android.app.Dialog;
-import android.app.ProgressDialog;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.util.Log;
-import android.widget.Toast;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Date;
-
-/**
- * Helper which shows a UI for writing or restoring a backup,
- * and calls the appropriate handler for actually executing those
- * operations.
- *
- * @author Rodrigo Damazio
- */
-public class BackupActivityHelper {
-
- private static final Comparator REVERSE_DATE_ORDER =
- new Comparator() {
- @Override
- public int compare(Date s1, Date s2) {
- return s2.compareTo(s1);
- }
- };
-
- private final FileUtils fileUtils;
- private final ExternalFileBackup backup;
- private final Activity activity;
-
- public BackupActivityHelper(Activity activity) {
- this.activity = activity;
- this.fileUtils = new FileUtils();
- this.backup = new ExternalFileBackup(activity, fileUtils);
- }
-
- /**
- * Writes a full backup to the default file.
- * This shows the results to the user.
- */
- public void writeBackup() {
- if (!fileUtils.isSdCardAvailable()) {
- showToast(R.string.sd_card_error_no_storage);
- return;
- }
-
- if (!backup.isBackupsDirectoryAvailable(true)) {
- showToast(R.string.sd_card_error_create_dir);
- return;
- }
-
- final ProgressDialog progressDialog = ProgressDialog.show(
- activity,
- activity.getString(R.string.generic_progress_title),
- activity.getString(R.string.settings_backup_now_progress_message),
- true);
-
- // Do the writing in another thread
- new Thread() {
- @Override
- public void run() {
- try {
- backup.writeToDefaultFile();
- showToast(R.string.sd_card_success_write_file);
- } catch (IOException e) {
- Log.e(Constants.TAG, "Failed to write backup", e);
- showToast(R.string.sd_card_error_write_file);
- } finally {
- dismissDialog(progressDialog);
- }
- }
- }.start();
- }
-
- /**
- * Restores a full backup from the SD card.
- * The user will be given a choice of which backup to restore as well as a
- * confirmation dialog.
- */
- public void restoreBackup() {
- // Get the list of existing backups
- if (!fileUtils.isSdCardAvailable()) {
- showToast(R.string.sd_card_error_no_storage);
- return;
- }
-
- if (!backup.isBackupsDirectoryAvailable(false)) {
- showToast(R.string.settings_backup_restore_no_backup);
- return;
- }
-
- final Date[] backupDates = backup.getAvailableBackups();
- if (backupDates == null || backupDates.length == 0) {
- showToast(R.string.settings_backup_restore_no_backup);
- return;
- }
- Arrays.sort(backupDates, REVERSE_DATE_ORDER);
-
- // Show a confirmation dialog
- Builder confirmationDialogBuilder = new AlertDialog.Builder(activity);
- confirmationDialogBuilder.setMessage(R.string.settings_backup_restore_confirm_message);
- confirmationDialogBuilder.setCancelable(true);
- confirmationDialogBuilder.setPositiveButton(android.R.string.yes,
- new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- pickBackupForRestore(backupDates);
- }
- });
- confirmationDialogBuilder.setNegativeButton(android.R.string.no, null);
- confirmationDialogBuilder.create().show();
- }
-
- /**
- * Shows a backup list for the user to pick, then restores it.
- *
- * @param backupDates the list of available backup files
- */
- private void pickBackupForRestore(final Date[] backupDates) {
- if (backupDates.length == 1) {
- // Only one choice, don't bother showing the list
- restoreFromDateAsync(backupDates[0]);
- return;
- }
-
- // Make a user-visible version of the backup filenames
- final String backupDateStrs[] = new String[backupDates.length];
- for (int i = 0; i < backupDates.length; i++) {
- backupDateStrs[i] = StringUtils.formatDateTime(activity, backupDates[i].getTime());
- }
-
- // Show a dialog for the user to pick which backup to restore
- Builder dialogBuilder = new AlertDialog.Builder(activity);
- dialogBuilder.setCancelable(true);
- dialogBuilder.setTitle(R.string.settings_backup_restore_select_title);
- dialogBuilder.setItems(backupDateStrs, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // User picked to restore this one
- restoreFromDateAsync(backupDates[which]);
- }
- });
- dialogBuilder.create().show();
- }
-
- /**
- * Shows a progress dialog, then starts restoring the backup asynchronously.
- *
- * @param date the date
- */
- private void restoreFromDateAsync(final Date date) {
- // Show a progress dialog
- ProgressDialog.show(
- activity,
- activity.getString(R.string.generic_progress_title),
- activity.getString(R.string.settings_backup_restore_progress_message),
- true);
-
- // Do the actual importing in another thread (don't block the UI)
- new Thread() {
- @Override
- public void run() {
- try {
- backup.restoreFromDate(date);
- showToast(R.string.sd_card_success_read_file);
- } catch (IOException e) {
- Log.e(Constants.TAG, "Failed to restore backup", e);
- showToast(R.string.sd_card_error_read_file);
- } finally {
- // Data may have been restored, "reboot" the app to catch it
- restartApplication();
- }
- }
- }.start();
- }
-
- /**
- * Restarts My Tracks completely.
- * This forces any modified data to be re-read.
- */
- private void restartApplication() {
- Intent intent = new Intent(activity, MyTracks.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- activity.startActivity(intent);
- }
-
- /**
- * Shows a toast with the given contents.
- */
- private void showToast(final int resId) {
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(activity, resId, Toast.LENGTH_LONG).show();
- }
- });
- }
-
- /**
- * Safely dismisses the given dialog.
- */
- private void dismissDialog(final Dialog dialog) {
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- dialog.dismiss();
- }
- });
- }
-}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupAsyncTask.java
new file mode 100644
index 000000000..3ef19ad31
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupAsyncTask.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2012 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.backup;
+
+import com.google.android.apps.mytracks.util.FileUtils;
+import com.google.android.maps.mytracks.R;
+
+import android.os.AsyncTask;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * AsyncTask to backup data to the SD card.
+ *
+ * @author Jimmy Shih
+ */
+public class BackupAsyncTask extends AsyncTask {
+
+ private static final String TAG = BackupAsyncTask.class.getSimpleName();
+
+ private BackupActivity backupActivity;
+ private final ExternalFileBackup externalFileBackup;
+
+ // true if the AsyncTask result is success
+ private boolean success;
+
+ // true if the AsyncTask has completed
+ private boolean completed;
+
+ // message id to return to the activity
+ private int messageId;
+
+ /**
+ * Creates an AsyncTask.
+ *
+ * @param backupActivity the activity currently associated with this
+ * AsyncTask
+ */
+ public BackupAsyncTask(BackupActivity backupActivity) {
+ this.backupActivity = backupActivity;
+ this.externalFileBackup = new ExternalFileBackup(backupActivity, new FileUtils());
+ success = false;
+ completed = false;
+ messageId = R.string.sd_card_error_write_file;
+ }
+
+ /**
+ * Sets the current {@link BackupActivity} associated with this AyncTask.
+ *
+ * @param activity the current {@link BackupActivity}, can be null
+ */
+ public void setActivity(BackupActivity activity) {
+ this.backupActivity = activity;
+ if (completed && backupActivity != null) {
+ backupActivity.onAsyncTaskCompleted(success, messageId);
+ }
+ }
+
+ @Override
+ protected void onPreExecute() {
+ if (backupActivity != null) {
+ backupActivity.showProgressDialog();
+ }
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ FileUtils fileUtils = new FileUtils();
+
+ if (!fileUtils.isSdCardAvailable()) {
+ messageId = R.string.sd_card_error_no_storage;
+ return false;
+ }
+
+ if (!externalFileBackup.isBackupsDirectoryAvailable(true)) {
+ messageId = R.string.sd_card_error_create_dir;
+ return false;
+ }
+
+ try {
+ externalFileBackup.writeToDefaultFile();
+ messageId = R.string.sd_card_success_write_file;
+ return true;
+ } catch (IOException e) {
+ Log.d(TAG, "IO exception", e);
+ return false;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ success = result;
+ completed = true;
+ if (backupActivity != null) {
+ backupActivity.onAsyncTaskCompleted(success, messageId);
+ }
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/backup/RestoreActivity.java b/MyTracks/src/com/google/android/apps/mytracks/io/backup/RestoreActivity.java
new file mode 100644
index 000000000..5e3492394
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/backup/RestoreActivity.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2012 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.backup;
+
+import com.google.android.apps.mytracks.MyTracks;
+import com.google.android.maps.mytracks.R;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Toast;
+
+import java.util.Date;
+
+/**
+ * An activity to restore data from the SD card.
+ *
+ * @author Jimmy Shih
+ */
+public class RestoreActivity extends Activity {
+
+ public static final String EXTRA_DATE = "date";
+
+ private static final String TAG = RestoreActivity.class.getSimpleName();
+ private static final int DIALOG_PROGRESS_ID = 0;
+
+ private RestoreAsyncTask restoreAsyncTask;
+ private ProgressDialog progressDialog;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Object retained = getLastNonConfigurationInstance();
+ if (retained instanceof RestoreAsyncTask) {
+ restoreAsyncTask = (RestoreAsyncTask) retained;
+ restoreAsyncTask.setActivity(this);
+ } else {
+ long date = getIntent().getLongExtra(EXTRA_DATE, -1L);
+ if (date == -1L) {
+ Log.d(TAG, "Invalid date");
+ finish();
+ }
+ restoreAsyncTask = new RestoreAsyncTask(this, new Date(date));
+ restoreAsyncTask.execute();
+ }
+ }
+
+ @Override
+ public Object onRetainNonConfigurationInstance() {
+ restoreAsyncTask.setActivity(null);
+ return restoreAsyncTask;
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case DIALOG_PROGRESS_ID:
+ progressDialog = new ProgressDialog(this);
+ progressDialog.setCancelable(true);
+ progressDialog.setIcon(android.R.drawable.ic_dialog_info);
+ progressDialog.setIndeterminate(true);
+ progressDialog.setMessage(getString(R.string.settings_backup_restore_progress_message));
+ progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ finish();
+ }
+ });
+ progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ progressDialog.setTitle(R.string.generic_progress_title);
+ return progressDialog;
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Invokes when the associated AsyncTask completes.
+ *
+ * @param success true if the AsyncTask is successful
+ * @param messageId message id to display to user
+ */
+ public void onAsyncTaskCompleted(boolean success, int messageId) {
+ removeDialog(DIALOG_PROGRESS_ID);
+ Toast.makeText(this, messageId, success ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG).show();
+ startActivity(new Intent(this, MyTracks.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
+ finish();
+ }
+
+ /**
+ * Shows the progress dialog.
+ */
+ public void showProgressDialog() {
+ showDialog(DIALOG_PROGRESS_ID);
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/backup/RestoreAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/io/backup/RestoreAsyncTask.java
new file mode 100644
index 000000000..23917d521
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/backup/RestoreAsyncTask.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2012 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.backup;
+
+import com.google.android.apps.mytracks.util.FileUtils;
+import com.google.android.maps.mytracks.R;
+
+import android.os.AsyncTask;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.Date;
+
+/**
+ * AsyncTask to restore data from the SD card.
+ *
+ * @author Jimmy Shih
+ */
+public class RestoreAsyncTask extends AsyncTask {
+
+ private static final String TAG = RestoreAsyncTask.class.getSimpleName();
+
+ private RestoreActivity restoreActivity;
+ private final Date date;
+ private final ExternalFileBackup externalFileBackup;
+
+ // true if the AsyncTask result is success
+ private boolean success;
+
+ // true if the AsyncTask has completed
+ private boolean completed;
+
+ // message id to return to the activity
+ private int messageId;
+
+ /**
+ * Creates an AsyncTask.
+ *
+ * @param restoreActivity the activity currently associated with this
+ * AsyncTask
+ * @param date the date to retore from
+ */
+ public RestoreAsyncTask(RestoreActivity restoreActivity, Date date) {
+ this.restoreActivity = restoreActivity;
+ this.date = date;
+ this.externalFileBackup = new ExternalFileBackup(restoreActivity, new FileUtils());
+ success = false;
+ completed = false;
+ messageId = R.string.sd_card_error_read_file;
+ }
+
+ /**
+ * Sets the current {@link RestoreActivity} associated with this AyncTask.
+ *
+ * @param activity the current {@link RestoreActivity}, can be null
+ */
+ public void setActivity(RestoreActivity activity) {
+ this.restoreActivity = activity;
+ if (completed && restoreActivity != null) {
+ restoreActivity.onAsyncTaskCompleted(success, messageId);
+ }
+ }
+
+ @Override
+ protected void onPreExecute() {
+ if (restoreActivity != null) {
+ restoreActivity.showProgressDialog();
+ }
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ try {
+ externalFileBackup.restoreFromDate(date);
+ messageId = R.string.sd_card_success_read_file;
+ return true;
+ } catch (IOException e) {
+ Log.d(TAG, "IO exception", e);
+ return false;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ success = result;
+ completed = true;
+ if (restoreActivity != null) {
+ restoreActivity.onAsyncTaskCompleted(success, messageId);
+ }
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/backup/RestoreChooserActivity.java b/MyTracks/src/com/google/android/apps/mytracks/io/backup/RestoreChooserActivity.java
new file mode 100644
index 000000000..8b5fc81c7
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/backup/RestoreChooserActivity.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2012 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.backup;
+
+import com.google.android.apps.mytracks.util.FileUtils;
+import com.google.android.apps.mytracks.util.StringUtils;
+import com.google.android.maps.mytracks.R;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnCancelListener;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.Toast;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Date;
+
+/**
+ * An activity to choose a date to restore from.
+ *
+ * @author Jimmy Shih
+ */
+public class RestoreChooserActivity extends Activity {
+
+ private static final Comparator REVERSE_DATE_ORDER = new Comparator() {
+ @Override
+ public int compare(Date s1, Date s2) {
+ return s2.compareTo(s1);
+ }
+ };
+ private static final int DIALOG_CHOOSER_ID = 0;
+
+ private Date[] backupDates;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ FileUtils fileUtils = new FileUtils();
+ ExternalFileBackup externalFileBackup = new ExternalFileBackup(this, fileUtils);
+
+ // Get the list of existing backups
+ if (!fileUtils.isSdCardAvailable()) {
+ Toast.makeText(this, R.string.sd_card_error_no_storage, Toast.LENGTH_LONG).show();
+ finish();
+ return;
+ }
+
+ if (!externalFileBackup.isBackupsDirectoryAvailable(false)) {
+ Toast.makeText(this, R.string.settings_backup_restore_no_backup, Toast.LENGTH_LONG).show();
+ finish();
+ return;
+ }
+
+ backupDates = externalFileBackup.getAvailableBackups();
+ if (backupDates == null || backupDates.length == 0) {
+ Toast.makeText(this, R.string.settings_backup_restore_no_backup, Toast.LENGTH_LONG).show();
+ finish();
+ return;
+ }
+
+ if (backupDates.length == 1) {
+ startActivity(new Intent(this, RestoreActivity.class)
+ .putExtra(RestoreActivity.EXTRA_DATE, backupDates[0].getTime()));
+ finish();
+ return;
+ }
+
+ Arrays.sort(backupDates, REVERSE_DATE_ORDER);
+ showDialog(DIALOG_CHOOSER_ID);
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case DIALOG_CHOOSER_ID:
+ String items[] = new String[backupDates.length];
+ for (int i = 0; i < backupDates.length; i++) {
+ items[i] = StringUtils.formatDateTime(this, backupDates[i].getTime());
+ }
+ return new AlertDialog.Builder(this)
+ .setCancelable(true)
+ .setItems(items, new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ startActivity(new Intent(RestoreChooserActivity.this, RestoreActivity.class)
+ .putExtra(RestoreActivity.EXTRA_DATE, backupDates[which].getTime()));
+ finish();
+ }
+ })
+ .setOnCancelListener(new OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ finish();
+ }
+ })
+ .setTitle(R.string.settings_backup_restore_select_title)
+ .create();
+ default:
+ return null;
+ }
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/ImportActivity.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/ImportActivity.java
deleted file mode 100644
index 027e35002..000000000
--- a/MyTracks/src/com/google/android/apps/mytracks/io/file/ImportActivity.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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;
-
-import static com.google.android.apps.mytracks.Constants.TAG;
-
-import com.google.android.apps.mytracks.ImportAllTracks;
-import com.google.android.apps.mytracks.util.UriUtils;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.net.Uri;
-import android.util.Log;
-
-/**
- * An activity that imports a track from a file and displays the track in My Tracks.
- *
- * @author Rodrigo Damazio
- */
-public class ImportActivity extends Activity {
-
- @Override
- public void onStart() {
- super.onStart();
-
- Intent intent = getIntent();
- String action = intent.getAction();
- Uri data = intent.getData();
- if (!(Intent.ACTION_VIEW.equals(action) || Intent.ACTION_ATTACH_DATA.equals(action))) {
- Log.e(TAG, "Received an intent with unsupported action: " + intent);
- finish();
- return;
- }
-
- if (!UriUtils.isFileUri(data)) {
- Log.e(TAG, "Received an intent with unsupported data: " + intent);
- finish();
- return;
- }
-
- String path = data.getPath();
- Log.i(TAG, "Importing GPX file at " + path);
- new ImportAllTracks(this, path);
- }
-}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveActivity.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveActivity.java
index daa35dd3e..8ecbfb596 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveActivity.java
@@ -13,24 +13,19 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
+
package com.google.android.apps.mytracks.io.file;
-import static com.google.android.apps.mytracks.Constants.TAG;
-
-import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
-import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.apps.mytracks.util.PlayTrackUtils;
-import com.google.android.apps.mytracks.util.UriUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
-import android.content.ContentUris;
-import android.content.Context;
+import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
@@ -42,208 +37,190 @@ import android.util.Log;
import java.io.File;
/**
- * Activity for saving a track to a file (and optionally sending that file).
+ * Activity for saving a track to the SD card, and optionally share or play the
+ * track.
*
* @author Rodrigo Damazio
*/
public class SaveActivity extends Activity {
- public static final String EXTRA_FILE_FORMAT = "file_format";
- public static final String EXTRA_SHARE_FILE = "share_file";
- public static final String EXTRA_PLAY_FILE = "play_file";
- private static final int RESULT_DIALOG = 1;
- /* VisibleForTesting */
- static final int PROGRESS_DIALOG = 2;
+ public static final String EXTRA_TRACK_ID = "track_id";
+ public static final String EXTRA_TRACK_FILE_FORMAT = "track_file_format";
+ public static final String EXTRA_SHARE_TRACK = "share_track";
+ public static final String EXTRA_PLAY_TRACK = "play_track";
+
+ private static final String TAG = SaveActivity.class.getSimpleName();
+
+ private static final int DIALOG_PROGRESS_ID = 0;
+ private static final int DIALOG_RESULT_ID = 1;
- private MyTracksProviderUtils providerUtils;
private long trackId;
- private TrackWriter writer;
- private boolean shareFile;
- private boolean playFile;
- private TrackFileFormat format;
- private WriteProgressController controller;
+ private TrackFileFormat trackFileFormat;
+ private boolean shareTrack;
+ private boolean playTrack;
+
+ private SaveAsyncTask saveAsyncTask;
+ private ProgressDialog progressDialog;
+
+ // result from the AsyncTask
+ private boolean success;
+
+ // message id from the AsyncTask
+ private int messageId;
+
+ // path of the saved file
+ private String filePath;
@Override
- protected void onCreate(Bundle savedInstanceState) {
+ public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- providerUtils = MyTracksProviderUtils.Factory.get(this);
+ Intent intent = getIntent();
+ trackId = intent.getLongExtra(EXTRA_TRACK_ID, -1L);
+ if (trackId < 0) {
+ Log.d(TAG, "Invalid track id");
+ finish();
+ return;
+ }
+
+ trackFileFormat = intent.getParcelableExtra(EXTRA_TRACK_FILE_FORMAT);
+ shareTrack = intent.getBooleanExtra(EXTRA_SHARE_TRACK, false);
+ playTrack = intent.getBooleanExtra(EXTRA_PLAY_TRACK, false);
+
+ Object retained = getLastNonConfigurationInstance();
+ if (retained instanceof SaveAsyncTask) {
+ saveAsyncTask = (SaveAsyncTask) retained;
+ saveAsyncTask.setActivity(this);
+ } else {
+ TrackWriter trackWriter = TrackWriterFactory.newWriter(
+ this, MyTracksProviderUtils.Factory.get(this), trackId, trackFileFormat);
+ if (trackWriter == null) {
+ Log.e(TAG, "Track writer is null");
+ finish();
+ return;
+ }
+ if (shareTrack || playTrack) {
+ // Save to the temp directory
+ String dirName = new FileUtils().buildExternalDirectoryPath(
+ trackFileFormat.getExtension(), "tmp");
+ trackWriter.setDirectory(new File(dirName));
+ }
+ saveAsyncTask = new SaveAsyncTask(this, trackWriter);
+ saveAsyncTask.execute();
+ }
}
@Override
- protected void onStart() {
- super.onStart();
+ public Object onRetainNonConfigurationInstance() {
+ saveAsyncTask.setActivity(null);
+ return saveAsyncTask;
+ }
- Intent intent = getIntent();
- String action = intent.getAction();
- String type = intent.getType();
- Uri data = intent.getData();
- if (!getString(R.string.track_action_save).equals(action)
- || !TracksColumns.CONTENT_ITEMTYPE.equals(type)
- || !UriUtils.matchesContentUri(data, TracksColumns.CONTENT_URI)) {
- Log.e(TAG, "Got bad save intent: " + intent);
- finish();
- return;
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case DIALOG_PROGRESS_ID:
+ progressDialog = new ProgressDialog(this);
+ progressDialog.setCancelable(true);
+ progressDialog.setIcon(android.R.drawable.ic_dialog_info);
+ progressDialog.setIndeterminate(true);
+ progressDialog.setMessage(getString(R.string.sd_card_progress_write_file));
+ progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ saveAsyncTask.cancel(true);
+ finish();
+ }
+ });
+ progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ progressDialog.setTitle(R.string.generic_progress_title);
+ return progressDialog;
+ case DIALOG_RESULT_ID:
+ return new AlertDialog.Builder(this)
+ .setCancelable(true)
+ .setIcon(success
+ ? android.R.drawable.ic_dialog_info : android.R.drawable.ic_dialog_alert)
+ .setMessage(messageId)
+ .setOnCancelListener(new OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ dialog.dismiss();
+ onPostResultDialog();
+ }
+ })
+ .setPositiveButton(R.string.generic_ok, new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int arg1) {
+ dialog.dismiss();
+ onPostResultDialog();
+ }
+ })
+ .setTitle(success ? R.string.generic_success_title : R.string.generic_error_title)
+ .create();
+ default:
+ return null;
}
+ }
- trackId = ContentUris.parseId(data);
+ /**
+ * Invokes when the associated AsyncTask completes.
+ *
+ * @param isSuccess true if the AsyncTask is successful
+ * @param aMessageId the id of the AsyncTask message
+ * @param aPath the path of the saved file
+ */
+ public void onAsyncTaskCompleted(boolean isSuccess, int aMessageId, String aPath) {
+ this.success = isSuccess;
+ this.messageId = aMessageId;
+ this.filePath = aPath;
+ removeDialog(DIALOG_PROGRESS_ID);
+ showDialog(DIALOG_RESULT_ID);
+ }
- int formatIdx = intent.getIntExtra(EXTRA_FILE_FORMAT, -1);
- format = TrackFileFormat.values()[formatIdx];
- shareFile = intent.getBooleanExtra(EXTRA_SHARE_FILE, false);
- playFile = intent.getBooleanExtra(EXTRA_PLAY_FILE, false);
-
- writer = TrackWriterFactory.newWriter(this, providerUtils, trackId, format);
- if (writer == null) {
- Log.e(TAG, "Unable to build writer");
- finish();
- return;
+ /**
+ * Shows the progress dialog.
+ */
+ public void showProgressDialog() {
+ showDialog(DIALOG_PROGRESS_ID);
+ }
+
+ /**
+ * Sets the progress dialog value.
+ *
+ * @param number the number of points saved
+ * @param max the maximum number of points
+ */
+ public void setProgressDialogValue(int number, int max) {
+ if (progressDialog != null) {
+ progressDialog.setIndeterminate(false);
+ progressDialog.setMax(max);
+ progressDialog.setProgress(Math.min(number, max));
}
-
- if (shareFile || playFile) {
- // If the file is for sending, save it to a temporary location instead.
- FileUtils fileUtils = new FileUtils();
- String extension = format.getExtension();
- String dirName = fileUtils.buildExternalDirectoryPath(extension, "tmp");
-
- File dir = new File(dirName);
- writer.setDirectory(dir);
- }
-
- controller = new WriteProgressController(this, writer, PROGRESS_DIALOG);
- controller.setOnCompletionListener(new WriteProgressController.OnCompletionListener() {
- @Override
- public void onComplete() {
- showDialog(RESULT_DIALOG);
- }
- });
- controller.startWrite();
}
/**
* To be invoked after showing the result dialog.
*/
private void onPostResultDialog() {
- if (writer.wasSuccess()) {
- if (shareFile) {
- shareWrittenFile();
- } else if (playFile) {
- playWrittenFile();
+ if (success) {
+ if (shareTrack) {
+ Intent intent = new Intent(Intent.ACTION_SEND)
+ .putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(filePath)))
+ .putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_track_subject))
+ .putExtra(Intent.EXTRA_TEXT, getString(R.string.share_track_file_body_format))
+ .putExtra(getString(R.string.track_id_broadcast_extra), trackId)
+ .setType(trackFileFormat.getMimeType());
+ startActivity(Intent.createChooser(intent, getString(R.string.share_track_picker_title)));
+ } else if (playTrack) {
+ Intent intent = new Intent()
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .putExtra(PlayTrackUtils.TOUR_FEATURE_ID, KmlTrackWriter.TOUR_FEATURE_ID)
+ .setClassName(PlayTrackUtils.GOOGLE_EARTH_PACKAGE, PlayTrackUtils.GOOGLE_EARTH_CLASS)
+ .setDataAndType(Uri.fromFile(new File(filePath)), PlayTrackUtils.KML_MIME_TYPE);
+ startActivity(intent);
}
}
finish();
}
-
- private void shareWrittenFile() {
- // Share the file.
- Intent shareIntent = new Intent(Intent.ACTION_SEND);
- shareIntent.putExtra(Intent.EXTRA_SUBJECT,
- getResources().getText(R.string.share_track_subject).toString());
- shareIntent.putExtra(Intent.EXTRA_TEXT,
- getResources().getText(R.string.share_track_file_body_format)
- .toString());
- shareIntent.setType(format.getMimeType());
- Uri u = Uri.fromFile(new File(writer.getAbsolutePath()));
- shareIntent.putExtra(Intent.EXTRA_STREAM, u);
- shareIntent.putExtra(getString(R.string.track_id_broadcast_extra), trackId);
- startActivity(Intent.createChooser(shareIntent,
- getResources().getText(R.string.share_track_picker_title).toString()));
- }
-
- private void playWrittenFile() {
- Uri uri = Uri.fromFile(new File(writer.getAbsolutePath()));
- Intent intent = new Intent()
- .setClassName(PlayTrackUtils.GOOGLE_EARTH_PACKAGE, PlayTrackUtils.GOOGLE_EARTH_CLASS)
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- .setDataAndType(uri, PlayTrackUtils.KML_MIME_TYPE)
- .putExtra(PlayTrackUtils.TOUR_FEATURE_ID, KmlTrackWriter.TOUR_FEATURE_ID);
- startActivity(intent);
- }
-
- @Override
- protected Dialog onCreateDialog(int id) {
- switch (id) {
- case RESULT_DIALOG:
- return createResultDialog();
- case PROGRESS_DIALOG:
- if (controller != null) {
- return controller.createProgressDialog();
- }
- //$FALL-THROUGH$
- default:
- return super.onCreateDialog(id);
- }
- }
-
- private Dialog createResultDialog() {
- boolean success = writer.wasSuccess();
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setMessage(writer.getErrorMessage());
- builder.setPositiveButton(R.string.generic_ok, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int arg1) {
- dialog.dismiss();
- onPostResultDialog();
- }
- });
- builder.setOnCancelListener(new OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialog) {
- dialog.dismiss();
- onPostResultDialog();
- }
- });
- builder.setIcon(success ? android.R.drawable.ic_dialog_info :
- android.R.drawable.ic_dialog_alert);
- builder.setTitle(success ? R.string.generic_success_title : R.string.generic_error_title);
- return builder.create();
- }
-
- public static void handleExportTrackAction(Context ctx, long trackId, int actionCode) {
- if (trackId < 0) {
- return;
- }
-
- TrackFileFormat exportFormat = null;
- switch (actionCode) {
- case Constants.SAVE_GPX_FILE:
- case Constants.SHARE_GPX_FILE:
- exportFormat = TrackFileFormat.GPX;
- break;
- case Constants.SAVE_KML_FILE:
- case Constants.SHARE_KML_FILE:
- exportFormat = TrackFileFormat.KML;
- break;
- case Constants.SAVE_CSV_FILE:
- case Constants.SHARE_CSV_FILE:
- exportFormat = TrackFileFormat.CSV;
- break;
- case Constants.SAVE_TCX_FILE:
- case Constants.SHARE_TCX_FILE:
- exportFormat = TrackFileFormat.TCX;
- break;
- default:
- throw new IllegalArgumentException("Warning unhandled action code: " + actionCode);
- }
-
- boolean shareFile = false;
- switch (actionCode) {
- case Constants.SHARE_GPX_FILE:
- case Constants.SHARE_KML_FILE:
- case Constants.SHARE_CSV_FILE:
- case Constants.SHARE_TCX_FILE:
- shareFile = true;
- }
-
- Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
-
- Intent intent = new Intent(ctx, SaveActivity.class);
- intent.setAction(ctx.getString(R.string.track_action_save));
- intent.setDataAndType(uri, TracksColumns.CONTENT_ITEMTYPE);
- intent.putExtra(EXTRA_FILE_FORMAT, exportFormat.ordinal());
- intent.putExtra(EXTRA_SHARE_FILE, shareFile);
- ctx.startActivity(intent);
- }
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveAsyncTask.java
new file mode 100644
index 000000000..2c5aa929a
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveAsyncTask.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2012 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 android.os.AsyncTask;
+
+/**
+ * Async Task to save a track to the SD card.
+ *
+ * @author Jimmy Shih
+ */
+public class SaveAsyncTask extends AsyncTask {
+
+ private SaveActivity saveActivity;
+ private final TrackWriter trackWriter;
+
+ // true if the AsyncTask result is success
+ private boolean success;
+
+ // true if the AsyncTask has completed
+ private boolean completed;
+
+ /**
+ * Creates an AsyncTask.
+ *
+ * @param saveActivity the {@link SaveActivity} currently associated with this
+ * AsyncTask
+ * @param trackWriter the track writer
+ */
+ public SaveAsyncTask(SaveActivity saveActivity, TrackWriter trackWriter) {
+ this.saveActivity = saveActivity;
+ this.trackWriter = trackWriter;
+ success = false;
+ completed = false;
+ }
+
+ /**
+ * Sets the current {@link SaveActivity} associated with this AyncTask.
+ *
+ * @param saveActivity the current {@link SaveActivity}, can be null
+ */
+ public void setActivity(SaveActivity saveActivity) {
+ this.saveActivity = saveActivity;
+ if (completed && saveActivity != null) {
+ saveActivity.onAsyncTaskCompleted(
+ success, trackWriter.getErrorMessage(), trackWriter.getAbsolutePath());
+ }
+ }
+
+ @Override
+ protected void onPreExecute() {
+ if (saveActivity != null) {
+ saveActivity.showProgressDialog();
+ }
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ trackWriter.setOnWriteListener(new TrackWriter.OnWriteListener() {
+ @Override
+ public void onWrite(int number, int max) {
+ // Update the progress dialog once every 500 points
+ if (number % 500 == 0) {
+ publishProgress(number, max);
+ }
+ }
+ });
+ trackWriter.writeTrack();
+ return trackWriter.wasSuccess();
+ }
+
+ @Override
+ protected void onProgressUpdate(Integer... values) {
+ if (saveActivity != null) {
+ saveActivity.setProgressDialogValue(values[0], values[1]);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ success = result;
+ completed = true;
+ if (saveActivity != null) {
+ saveActivity.onAsyncTaskCompleted(
+ success, trackWriter.getErrorMessage(), trackWriter.getAbsolutePath());
+ }
+ }
+
+ @Override
+ protected void onCancelled() {
+ trackWriter.stopWriteTrack();
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriter.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriter.java
index bace24d33..26e1c59c6 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriter.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriter.java
@@ -27,10 +27,6 @@ import java.io.File;
* @author Rodrigo Damazio
*/
public interface TrackWriter {
- /** This listener is used to signal completion of track write */
- public interface OnCompletionListener {
- public void onComplete();
- }
/** This listener is used to signal track writes. */
public interface OnWriteListener {
@@ -43,11 +39,6 @@ public interface TrackWriter {
public void onWrite(int number, int max);
}
- /**
- * Sets listener to be invoked when the writer has finished.
- */
- void setOnCompletionListener(OnCompletionListener onCompletionListener);
-
/**
* Sets a listener to be invoked for each location writer.
*/
@@ -63,12 +54,6 @@ public interface TrackWriter {
*/
String getAbsolutePath();
- /**
- * Writes the given track id to the SD card.
- * This is non-blocking.
- */
- void writeTrackAsync();
-
/**
* Writes the given track id to the SD card.
* This is blocking.
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterFactory.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterFactory.java
index 7df87364f..37ea46b96 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterFactory.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterFactory.java
@@ -22,6 +22,8 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.util.Log;
/**
@@ -34,7 +36,7 @@ public class TrackWriterFactory {
/**
* Definition of all possible track formats.
*/
- public enum TrackFileFormat {
+ public enum TrackFileFormat implements Parcelable {
GPX {
@Override
TrackFormatWriter newFormatWriter(Context context) {
@@ -60,6 +62,28 @@ public class TrackWriterFactory {
}
};
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(final Parcel dest, final int flags) {
+ dest.writeInt(ordinal());
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public TrackFileFormat createFromParcel(final Parcel source) {
+ return TrackFileFormat.values()[source.readInt()];
+ }
+
+ @Override
+ public TrackFileFormat[] newArray(final int size) {
+ return new TrackFileFormat[size];
+ }
+ };
+
/**
* Creates and returns a new format writer for each format.
*/
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterImpl.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterImpl.java
index 21617daa3..76517544b 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterImpl.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterImpl.java
@@ -57,7 +57,6 @@ class TrackWriterImpl implements TrackWriter {
private int errorMessage = -1;
private File directory = null;
private File file = null;
- private OnCompletionListener onCompletionListener;
private OnWriteListener onWriteListener;
private Thread writeThread;
@@ -70,11 +69,6 @@ class TrackWriterImpl implements TrackWriter {
this.fileUtils = new FileUtils();
}
- @Override
- public void setOnCompletionListener(OnCompletionListener onCompletionListener) {
- this.onCompletionListener = onCompletionListener;
- }
-
@Override
public void setOnWriteListener(OnWriteListener onWriteListener) {
this.onWriteListener = onWriteListener;
@@ -90,8 +84,7 @@ class TrackWriterImpl implements TrackWriter {
return file.getAbsolutePath();
}
- @Override
- public void writeTrackAsync() {
+ private void writeTrackAsync() {
writeThread = new Thread() {
@Override
public void run() {
@@ -131,7 +124,6 @@ class TrackWriterImpl implements TrackWriter {
}
}
}
- finished();
}
public void stopWriteTrack() {
@@ -163,18 +155,6 @@ class TrackWriterImpl implements TrackWriter {
* ===============
*/
- private void finished() {
- if (onCompletionListener != null) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- onCompletionListener.onComplete();
- }
- });
- return;
- }
- }
-
/**
* Runs the given runnable in the UI thread.
*/
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/WriteProgressController.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/WriteProgressController.java
deleted file mode 100644
index 8da3a1871..000000000
--- a/MyTracks/src/com/google/android/apps/mytracks/io/file/WriteProgressController.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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;
-
-import com.google.android.maps.mytracks.R;
-
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.content.DialogInterface;
-
-/**
- * Given a {@link TrackWriter}, this class manages the process of writing the
- * data in the track represented by the writer. This includes the display of
- * a progress dialog, updating the progress bar in said dialog, and notifying
- * interested parties when the write completes.
- *
- * @author Matthew Simmons
- */
-class WriteProgressController {
- /**
- * This listener is used to notify interested parties when the write has
- * completed.
- */
- public interface OnCompletionListener {
- /**
- * When this method is invoked, the write has completed, and the progress
- * dialog has been dismissed. Whether the write succeeded can be
- * determined by examining the {@link TrackWriter}.
- */
- public void onComplete();
- }
-
- private final Activity activity;
- private final TrackWriter writer;
- private ProgressDialog dialog;
-
- private OnCompletionListener onCompletionListener;
- private final int progressDialogId;
-
- /**
- * @param activity the activity associated with this write
- * @param writer the writer which writes the track to disk. Note that this
- * class will use the writer's completion listener. If callers are
- * interested in notification upon completion of the write, they should
- * use {@link #setOnCompletionListener}.
- */
- public WriteProgressController(Activity activity, TrackWriter writer, int progressDialogId) {
- this.activity = activity;
- this.writer = writer;
- this.progressDialogId = progressDialogId;
-
- writer.setOnCompletionListener(writerCompleteListener);
- writer.setOnWriteListener(writerWriteListener);
- }
-
- /** Set a listener to be invoked when the write completes. */
- public void setOnCompletionListener(OnCompletionListener onCompletionListener) {
- this.onCompletionListener = onCompletionListener;
- }
-
- // For testing purpose
- OnCompletionListener getOnCompletionListener() {
- return onCompletionListener;
- }
-
- public ProgressDialog createProgressDialog() {
- dialog = new ProgressDialog(activity);
- dialog.setIcon(android.R.drawable.ic_dialog_info);
- dialog.setTitle(activity.getString(R.string.generic_progress_title));
- dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- dialog.setMessage(activity.getString(R.string.sd_card_progress_write_file));
- dialog.setIndeterminate(true);
- dialog.setOnCancelListener(dialogCancelListener);
- return dialog;
- }
-
- /** Initiate an asynchronous write. */
- public void startWrite() {
- activity.showDialog(progressDialogId);
- writer.writeTrackAsync();
- }
-
- /** VisibleForTesting */
- ProgressDialog getDialog() {
- return dialog;
- }
-
- private final DialogInterface.OnCancelListener dialogCancelListener =
- new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialogInterface) {
- writer.stopWriteTrack();
- }
- };
-
- private final TrackWriter.OnCompletionListener writerCompleteListener =
- new TrackWriter.OnCompletionListener() {
- @Override
- public void onComplete() {
- activity.dismissDialog(progressDialogId);
-
- if (onCompletionListener != null) {
- onCompletionListener.onComplete();
- }
- }
- };
-
- private final TrackWriter.OnWriteListener writerWriteListener =
- new TrackWriter.OnWriteListener() {
- @Override
- public void onWrite(int number, int max) {
- if (number % 500 == 0) {
- dialog.setIndeterminate(false);
- dialog.setMax(max);
- dialog.setProgress(Math.min(number, max));
- }
- }
- };
-}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/PlayTrackUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/PlayTrackUtils.java
index 09e37656d..675bef4f5 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/util/PlayTrackUtils.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/util/PlayTrackUtils.java
@@ -16,14 +16,12 @@
package com.google.android.apps.mytracks.util;
-import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.io.file.SaveActivity;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.maps.mytracks.R;
import android.app.AlertDialog;
import android.app.Dialog;
-import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
@@ -31,6 +29,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
+import android.os.Parcelable;
import java.util.List;
@@ -80,12 +79,10 @@ public class PlayTrackUtils {
public static void playTrack(Context context, long trackId) {
AnalyticsUtils.sendPageViews(context, "/action/play");
- Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
Intent intent = new Intent(context, SaveActivity.class)
- .putExtra(SaveActivity.EXTRA_FILE_FORMAT, TrackFileFormat.KML.ordinal())
- .putExtra(SaveActivity.EXTRA_PLAY_FILE, true)
- .setAction(context.getString(R.string.track_action_save))
- .setDataAndType(uri, TracksColumns.CONTENT_ITEMTYPE);
+ .putExtra(SaveActivity.EXTRA_TRACK_ID, trackId)
+ .putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.KML)
+ .putExtra(SaveActivity.EXTRA_PLAY_TRACK, true);
context.startActivity(intent);
}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/MockTrackWriter.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/MockTrackWriter.java
index 813d42a52..60e35bf20 100644
--- a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/MockTrackWriter.java
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/MockTrackWriter.java
@@ -19,21 +19,14 @@ import java.io.File;
/**
* A simple, fake {@link TrackWriter} subclass with all methods mocked out.
- * Tests are expected to override {@link #writeTrack} and/or
- * {@link #writeTrackAsync}, at the very least.
+ * Tests are expected to override {@link #writeTrack}.
*
* @author Matthew Simmons
*
*/
public class MockTrackWriter implements TrackWriter {
- public OnCompletionListener onCompletionListener;
public OnWriteListener onWriteListener;
- @Override
- public void setOnCompletionListener(OnCompletionListener onCompletionListener) {
- this.onCompletionListener = onCompletionListener;
- }
-
@Override
public void setOnWriteListener(OnWriteListener onWriteListener) {
this.onWriteListener = onWriteListener;
@@ -49,11 +42,6 @@ public class MockTrackWriter implements TrackWriter {
throw new UnsupportedOperationException("not implemented");
}
- @Override
- public void writeTrackAsync() {
- throw new UnsupportedOperationException("not implemented");
- }
-
@Override
public void writeTrack() {
throw new UnsupportedOperationException("not implemented");
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackWriterTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackWriterTest.java
index c2026d32b..90684bc04 100644
--- a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackWriterTest.java
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackWriterTest.java
@@ -169,13 +169,7 @@ public class TrackWriterTest extends AndroidTestCase {
writer = new WriteTracksTrackWriter(getContext(), providerUtils, track,
formatWriter, true);
- // Expect the completion listener to be run
- TrackWriter.OnCompletionListener completionListener
- = mocksControl.createMock(TrackWriter.OnCompletionListener.class);
- completionListener.onComplete();
-
mocksControl.replay();
- writer.setOnCompletionListener(completionListener);
writer.writeTrack();
assertEquals(1, writeDocumentCalls);
@@ -187,13 +181,7 @@ public class TrackWriterTest extends AndroidTestCase {
writer = new WriteTracksTrackWriter(getContext(), providerUtils, track,
formatWriter, false);
- // Expect the completion listener to be run
- TrackWriter.OnCompletionListener completionListener
- = mocksControl.createMock(TrackWriter.OnCompletionListener.class);
- completionListener.onComplete();
-
mocksControl.replay();
- writer.setOnCompletionListener(completionListener);
writer.writeTrack();
assertEquals(0, writeDocumentCalls);
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/WriteProgressControllerTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/WriteProgressControllerTest.java
deleted file mode 100644
index c6028c325..000000000
--- a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/WriteProgressControllerTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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;
-
-import android.app.ProgressDialog;
-import android.test.ActivityInstrumentationTestCase2;
-
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Tests {@link WriteProgressController}.
- *
- * @author Matthew Simmons
- */
-public class WriteProgressControllerTest extends ActivityInstrumentationTestCase2 {
- public WriteProgressControllerTest() {
- super(SaveActivity.class);
- }
-
- private static void assertProgress(ProgressDialog dialog, int expectedProgress,
- int expectedMax) {
- assertEquals(expectedProgress, dialog.getProgress());
- assertEquals(expectedMax, dialog.getMax());
- }
-
- public void testSimple() throws Exception {
- final AtomicReference dialogRef = new AtomicReference();
- final AtomicReference controllerDoneRef = new AtomicReference();
- final Semaphore writerDone = new Semaphore(0);
-
- TrackWriter mockWriter = new MockTrackWriter() {
- @Override
- public void writeTrackAsync() {
- onWriteListener.onWrite(1000, 10000);
- assertProgress(dialogRef.get(), 1000, 10000);
-
- onCompletionListener.onComplete();
- writerDone.release();
- }
- };
-
- final WriteProgressController controller = new WriteProgressController(
- getActivity(), mockWriter, SaveActivity.PROGRESS_DIALOG);
- controller.setOnCompletionListener(new WriteProgressController.OnCompletionListener() {
- @Override
- public void onComplete() {
- controllerDoneRef.set(true);
- }
- });
-
- /*
- * The WriteProgressController constructor calls the mockWriter's
- * setOnCompletionListener method with a listener that dismisses the
- * progress dialog. However, this unit test only tests the
- * WriteProgressController and doesn't actually show any progress dialog.
- * Thus after the WriteProgressController is setup, we need to call the
- * mockWriter's setOnCompletionListener method again with an listener that
- * doesn't dismiss dialog.
- */
- mockWriter.setOnCompletionListener(new TrackWriter.OnCompletionListener() {
- @Override
- public void onComplete() {
- controller.getOnCompletionListener().onComplete();
- }
- });
-
- dialogRef.set(controller.createProgressDialog());
-
- controller.startWrite();
-
- // wait for the writer to finish
- writerDone.acquire();
-
- assertTrue(controllerDoneRef.get());
- }
-}