From 8ee1066b9df986936178126d15e81380b7830c9a Mon Sep 17 00:00:00 2001 From: Jimmy Shih Date: Thu, 15 Mar 2012 19:08:54 -0700 Subject: [PATCH] Modify ExportAll to use the AsyncTask pattern to support screen rotations of dialogs. --- MyTracks/AndroidManifest.xml | 3 +- .../apps/mytracks/ExportAllActivity.java | 124 ++++++++++ .../apps/mytracks/ExportAllAsyncTask.java | 160 ++++++++++++ .../apps/mytracks/ExportAllTracks.java | 229 ------------------ .../android/apps/mytracks/TrackList.java | 33 ++- .../apps/mytracks/io/file/SaveActivity.java | 4 +- 6 files changed, 317 insertions(+), 236 deletions(-) create mode 100644 MyTracks/src/com/google/android/apps/mytracks/ExportAllActivity.java create mode 100644 MyTracks/src/com/google/android/apps/mytracks/ExportAllAsyncTask.java delete mode 100644 MyTracks/src/com/google/android/apps/mytracks/ExportAllTracks.java diff --git a/MyTracks/AndroidManifest.xml b/MyTracks/AndroidManifest.xml index f62a9b101..7f32148dc 100755 --- a/MyTracks/AndroidManifest.xml +++ b/MyTracks/AndroidManifest.xml @@ -283,7 +283,8 @@ limitations under the License. - + + { + + 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; + + /** + * 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; + } + + /** + * 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); + } + } + + @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) { + 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()) { + return false; + } + publishProgress(i + 1, count); + } + return true; + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + + @Override + protected void onProgressUpdate(Integer... values) { + if (exportAllActivity != null) { + exportAllActivity.setProgressDialogValue(values[0], values[1]); + } + } + + @Override + protected void onPostExecute(Boolean result) { + // Release the wake lock if obtained + if (wakeLock != null && wakeLock.isHeld()) { + wakeLock.release(); + } + success = result; + completed = true; + if (exportAllActivity != null) { + exportAllActivity.onAsyncTaskCompleted(success); + } + } + + @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/TrackList.java b/MyTracks/src/com/google/android/apps/mytracks/TrackList.java index 6af1e5ff5..e3886abdf 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/TrackList.java +++ b/MyTracks/src/com/google/android/apps/mytracks/TrackList.java @@ -28,10 +28,12 @@ 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.database.Cursor; @@ -64,7 +66,8 @@ 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 int contextPosition = -1; private long trackId = -1; @@ -180,7 +183,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: @@ -271,7 +274,7 @@ public class TrackList extends ListActivity break; } case R.id.tracklist_btn_export_all: { - new ExportAllTracks(this); + showDialog(DIALOG_EXPORT_ALL_ID); break; } case R.id.tracklist_btn_import_all: { @@ -341,8 +344,30 @@ 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(); default: return null; } 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 13aae9a44..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 @@ -51,8 +51,8 @@ public class SaveActivity extends Activity { private static final String TAG = SaveActivity.class.getSimpleName(); - private static final int DIALOG_PROGRESS_ID = 1; - private static final int DIALOG_RESULT_ID = 2; + private static final int DIALOG_PROGRESS_ID = 0; + private static final int DIALOG_RESULT_ID = 1; private long trackId; private TrackFileFormat trackFileFormat;