merge heads

This commit is contained in:
Jimmy Shih
2012-03-20 10:37:14 -07:00
parent 08a17a58ef
commit b8400cc0bf
6 changed files with 321 additions and 236 deletions
+2 -1
View File
@@ -171,6 +171,7 @@ limitations under the License.
<data android:mimeType="vnd.android.cursor.item/vnd.google.track" />
</intent-filter>
</activity>
<activity android:name="com.google.android.apps.mytracks.ExportAllActivity"/>
<activity
android:exported="false"
android:name="com.google.android.apps.mytracks.MapActivity" >
@@ -312,7 +313,7 @@ limitations under the License.
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.AccountChooserActivity" />
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity" />
<activity android:name="com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity" />
<service
android:exported="false"
android:name="com.google.android.apps.mytracks.services.ControlRecordingService" />
@@ -0,0 +1,121 @@
/*
* 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.io.file.TrackWriterFactory.TrackFileFormat;
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.widget.Toast;
/**
* An activity to export all the tracks to the SD card.
*
* @author Sandor Dornbush
*/
public class ExportAllActivity extends Activity {
public static final String EXTRA_TRACK_FILE_FORMAT = "track_file_format";
private static final int DIALOG_PROGRESS_ID = 0;
private ExportAllAsyncTask exportAllAsyncTask;
private ProgressDialog progressDialog;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Object retained = getLastNonConfigurationInstance();
if (retained instanceof ExportAllAsyncTask) {
exportAllAsyncTask = (ExportAllAsyncTask) retained;
exportAllAsyncTask.setActivity(this);
} else {
Intent intent = getIntent();
TrackFileFormat trackFileFormat = intent.getParcelableExtra(EXTRA_TRACK_FILE_FORMAT);
exportAllAsyncTask = new ExportAllAsyncTask(this, trackFileFormat);
exportAllAsyncTask.execute();
}
}
@Override
public Object onRetainNonConfigurationInstance() {
exportAllAsyncTask.setActivity(null);
return exportAllAsyncTask;
}
@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) {
exportAllAsyncTask.cancel(true);
finish();
}
});
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setTitle(R.string.track_list_export_all);
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);
}
/**
* Sets the progress dialog value.
*
* @param number the number of tracks exported
* @param max the maximum number of tracks
*/
public void setProgressDialogValue(int number, int max) {
if (progressDialog != null) {
progressDialog.setIndeterminate(false);
progressDialog.setMax(max);
progressDialog.setProgress(Math.min(number, max));
}
}
}
@@ -0,0 +1,167 @@
/*
* 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.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.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.PowerManager.WakeLock;
/**
* AsyncTask to export all the tracks to the SD card.
*
* @author Jimmy Shih
*/
public class ExportAllAsyncTask extends AsyncTask<Void, Integer, Boolean> {
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();
}
}
}
@@ -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();
}
});
}
}
@@ -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:
@@ -257,7 +260,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: {
@@ -327,8 +330,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;
}
@@ -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;