From eeaa50ddcb4c64abc56f2cf72a836291843862bb Mon Sep 17 00:00:00 2001 From: Rodrigo Damazio Date: Wed, 25 May 2011 04:50:21 -0300 Subject: [PATCH] Removing singleton usage: moving all send and save logic out of the MyTracks class. This is a non-trivial step: I decentralized dialog creation (since it made no sense to have a single place creating a lot of completely unrelated dialogs), made invisible activities just for sending/saving, and changed menu handling a bit, all to decentralize those functions from MyTracks. There's still a TODO to handle GET_LOGIN more nicely instead of returning from the depths of auth management into the current activity. --- MyTracks/AndroidManifest.xml | 7 + .../android/apps/mytracks/AccountChooser.java | 6 +- .../android/apps/mytracks/Constants.java | 4 +- .../android/apps/mytracks/DialogManager.java | 37 +- .../android/apps/mytracks/MapActivity.java | 28 +- .../android/apps/mytracks/MyMapsList.java | 48 +- .../android/apps/mytracks/MyTracks.java | 755 ++---------------- .../android/apps/mytracks/TrackList.java | 64 +- .../apps/mytracks/io/ModernAuthManager.java | 5 +- .../android/apps/mytracks/io/SendToDocs.java | 35 +- .../apps/mytracks/io/file/SaveActivity.java | 152 ++++ .../file}/WriteProgressController.java | 8 +- .../io/sendtogoogle/SendActivity.java | 619 ++++++++++++++ .../mytracks/io/sendtogoogle/SendDialog.java | 52 +- .../apps/mytracks/DialogManagerTest.java | 14 - .../file}/WriteProgressControllerTest.java | 7 +- 16 files changed, 978 insertions(+), 863 deletions(-) create mode 100644 MyTracks/src/com/google/android/apps/mytracks/io/file/SaveActivity.java rename MyTracks/src/com/google/android/apps/mytracks/{ => io/file}/WriteProgressController.java (95%) create mode 100644 MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendActivity.java rename MyTracksTest/src/com/google/android/apps/mytracks/{ => io/file}/WriteProgressControllerTest.java (92%) diff --git a/MyTracks/AndroidManifest.xml b/MyTracks/AndroidManifest.xml index 40c852901..ed3a78083 100755 --- a/MyTracks/AndroidManifest.xml +++ b/MyTracks/AndroidManifest.xml @@ -90,6 +90,13 @@ limitations under the License. android:label="@string/elevation_label" android:exported="false" /> + + + diff --git a/MyTracks/src/com/google/android/apps/mytracks/AccountChooser.java b/MyTracks/src/com/google/android/apps/mytracks/AccountChooser.java index 7a648a304..c26434440 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/AccountChooser.java +++ b/MyTracks/src/com/google/android/apps/mytracks/AccountChooser.java @@ -29,7 +29,7 @@ import android.util.Log; * @author Sandor Dornbush */ public class AccountChooser { - + /** * The last selected account. */ @@ -68,13 +68,13 @@ public class AccountChooser { handler.handleAccountSelected(accounts[0]); return; } - + // TODO This should be read out of a preference. if (selectedAccount != null) { handler.handleAccountSelected(selectedAccount); return; } - + // Let the user choose. Log.e(Constants.TAG, "Multiple matching accounts found."); final AlertDialog.Builder builder = new AlertDialog.Builder(activity); diff --git a/MyTracks/src/com/google/android/apps/mytracks/Constants.java b/MyTracks/src/com/google/android/apps/mytracks/Constants.java index c3fc58acf..063bb6679 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/Constants.java +++ b/MyTracks/src/com/google/android/apps/mytracks/Constants.java @@ -50,7 +50,7 @@ public abstract class Constants { public static final int AUTHENTICATE_TO_DOCLIST = 10; public static final int AUTHENTICATE_TO_TRIX = 11; public static final int DELETE_TRACK = 13; - public static final int SEND_TO_GOOGLE_DIALOG = 14; + public static final int SEND_TO_GOOGLE = 14; public static final int SHARE_LINK = 15; public static final int SHARE_GPX_FILE = 16; public static final int SHARE_KML_FILE = 17; @@ -190,7 +190,7 @@ public abstract class Constants { public static int getActionFromMenuId(int menuId) { switch (menuId) { case Constants.MENU_SEND_TO_GOOGLE: - return Constants.SEND_TO_GOOGLE_DIALOG; + return Constants.SEND_TO_GOOGLE; case Constants.MENU_EDIT: return Constants.EDIT_DETAILS; case Constants.MENU_DELETE: diff --git a/MyTracks/src/com/google/android/apps/mytracks/DialogManager.java b/MyTracks/src/com/google/android/apps/mytracks/DialogManager.java index 3b9d67377..722530884 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/DialogManager.java +++ b/MyTracks/src/com/google/android/apps/mytracks/DialogManager.java @@ -24,6 +24,8 @@ import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; import android.os.Bundle; import android.util.Log; import android.view.WindowManager.BadTokenException; @@ -37,7 +39,6 @@ public class DialogManager { public static final int DIALOG_IMPORT_PROGRESS = 2; public static final int DIALOG_PROGRESS = 3; - public static final int DIALOG_SEND_TO_GOOGLE = 4; private ProgressDialog progressDialog; private ProgressDialog importProgressDialog; @@ -69,21 +70,10 @@ public class DialogManager { progressDialog.setMax(100); progressDialog.setProgress(10); return progressDialog; - case DIALOG_SEND_TO_GOOGLE: - sendToGoogleDialog = new SendDialog(activity); - return sendToGoogleDialog; } return null; } - protected void onPrepareDialog(int id, Dialog dialog) { - switch (id) { - case DIALOG_SEND_TO_GOOGLE: - activity.resetSendToGoogleStatus(); - break; - } - } - public void setProgressMessage(final String message) { activity.runOnUiThread(new Runnable() { public void run() { @@ -126,19 +116,24 @@ public class DialogManager { public void showMessageDialog(final int message, final boolean success) { activity.runOnUiThread(new Runnable() { public void run() { - AlertDialog dialog = null; - AlertDialog.Builder builder = new AlertDialog.Builder(activity); - builder.setMessage(activity.getString(message)); - builder.setNegativeButton(activity.getString(R.string.ok), null); - builder.setIcon(success ? android.R.drawable.ic_dialog_info : - android.R.drawable.ic_dialog_alert); - builder.setTitle(success ? R.string.success : R.string.error); - dialog = builder.create(); - dialog.show(); + showMessageDialog(activity, message, success, null); } }); } + public static void showMessageDialog( + Context ctx, int message, boolean success, DialogInterface.OnClickListener okListener) { + AlertDialog dialog = null; + AlertDialog.Builder builder = new AlertDialog.Builder(ctx); + builder.setMessage(message); + builder.setNeutralButton(R.string.ok, okListener); + builder.setIcon(success ? android.R.drawable.ic_dialog_info : + android.R.drawable.ic_dialog_alert); + builder.setTitle(success ? R.string.success : R.string.error); + dialog = builder.create(); + dialog.show(); + } + /** * Just like showDialog, but will catch a {@link BadTokenException} that * sometimes (very rarely) gets thrown. This might happen if the user hits diff --git a/MyTracks/src/com/google/android/apps/mytracks/MapActivity.java b/MyTracks/src/com/google/android/apps/mytracks/MapActivity.java index 25af090a4..4ee5d26cd 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/MapActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/MapActivity.java @@ -23,6 +23,8 @@ import com.google.android.apps.mytracks.content.TrackDataHub; import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType; import com.google.android.apps.mytracks.content.TrackDataListener; import com.google.android.apps.mytracks.content.Waypoint; +import com.google.android.apps.mytracks.io.file.SaveActivity; +import com.google.android.apps.mytracks.io.sendtogoogle.SendActivity; import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory; import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.apps.mytracks.util.ApiFeatures; @@ -391,13 +393,27 @@ public class MapActivity extends com.google.android.maps.MapActivity @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { - if (!super.onMenuItemSelected(featureId, item)) { - MyTracks.getInstance().onActivityResult( - Constants.getActionFromMenuId(item.getItemId()), RESULT_OK, - new Intent()); - return true; + switch (item.getItemId()) { + case Constants.MENU_SEND_TO_GOOGLE: + SendActivity.sendToGoogle(this, dataHub.getSelectedTrackId(), false); + return true; + case Constants.MENU_SHARE_LINK: + SendActivity.sendToGoogle(this, dataHub.getSelectedTrackId(), true); + return true; + case Constants.MENU_SAVE_GPX_FILE: + case Constants.MENU_SAVE_KML_FILE: + case Constants.MENU_SAVE_CSV_FILE: + case Constants.MENU_SAVE_TCX_FILE: + case Constants.MENU_SHARE_GPX_FILE: + case Constants.MENU_SHARE_KML_FILE: + case Constants.MENU_SHARE_CSV_FILE: + case Constants.MENU_SHARE_TCX_FILE: + SaveActivity.handleExportTrackAction(this, dataHub.getSelectedTrackId(), + Constants.getActionFromMenuId(item.getItemId())); + return true; + default: + return super.onMenuItemSelected(featureId, item); } - return false; } @Override diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyMapsList.java b/MyTracks/src/com/google/android/apps/mytracks/MyMapsList.java index 7b74ac606..0ee852e29 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/MyMapsList.java +++ b/MyTracks/src/com/google/android/apps/mytracks/MyMapsList.java @@ -25,11 +25,7 @@ import com.google.android.maps.mytracks.R; import android.app.Activity; import android.content.Intent; import android.os.Bundle; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.MenuItem; import android.view.View; -import android.view.View.OnCreateContextMenuListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ListView; @@ -42,29 +38,12 @@ import android.widget.TextView; * @author Rodrigo Damazio */ public class MyMapsList extends Activity implements MapsFacade.MapsListCallback { - private static final int MENU_OPEN = 0; - private static final int MENU_SHARE = 2; private static final int GET_LOGIN = 1; private MapsFacade mapsClient; private AuthManager auth; private MyMapsListAdapter listAdapter; - private int contextPosition; - - private final OnCreateContextMenuListener contextMenuListener = - new OnCreateContextMenuListener() { - @Override - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { - AdapterView.AdapterContextMenuInfo info = - (AdapterView.AdapterContextMenuInfo) menuInfo; - contextPosition = info.position; - menu.add(0, MENU_OPEN, 0, R.string.open_map); - menu.add(0, MENU_SHARE, 0, R.string.share_map); - } - }; - private final OnItemClickListener clickListener = new OnItemClickListener() { @Override @@ -91,7 +70,6 @@ public class MyMapsList extends Activity implements MapsFacade.MapsListCallback ListView list = (ListView) findViewById(R.id.maplist); list.setOnItemClickListener(clickListener); - list.setOnCreateContextMenuListener(contextMenuListener); list.setAdapter(listAdapter); startLogin(); @@ -101,7 +79,8 @@ public class MyMapsList extends Activity implements MapsFacade.MapsListCallback // Starts in the UI thread. // TODO fix this for non-froyo devices. if (AuthManagerFactory.useModernAuthManager()) { - MyTracks.getInstance().getAccountChooser().chooseAccount( + AccountChooser accountChooser = new AccountChooser(); + accountChooser.chooseAccount( MyMapsList.this, new AccountChooser.AccountHandler() { @Override @@ -183,27 +162,4 @@ public class MyMapsList extends Activity implements MapsFacade.MapsListCallback } super.onActivityResult(requestCode, resultCode, data); } - - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - switch (item.getItemId()) { - case MENU_OPEN: - clickListener.onItemClick(null, null, contextPosition, 0); - return true; - case MENU_SHARE: - Intent shareIntent = new Intent(Intent.ACTION_SEND); - shareIntent.setType("text/plain"); - shareIntent.putExtra(Intent.EXTRA_SUBJECT, - getText(R.string.share_map_subject)); - String[] listItem = (String[]) listAdapter.getMapListingArray(contextPosition); - shareIntent.putExtra(Intent.EXTRA_TEXT, String.format( - getText(R.string.share_map_body_format).toString(), - listItem[1], - MapsFacade.buildMapUrl(listItem[0]))); - startActivity(Intent.createChooser(shareIntent, - getText(R.string.share_map).toString())); - return true; - } - return false; - } } diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java index 4313c2f9d..de3fc31bb 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java +++ b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java @@ -17,36 +17,16 @@ package com.google.android.apps.mytracks; import static com.google.android.apps.mytracks.Constants.TAG; import static com.google.android.apps.mytracks.DialogManager.DIALOG_IMPORT_PROGRESS; -import static com.google.android.apps.mytracks.DialogManager.DIALOG_PROGRESS; -import static com.google.android.apps.mytracks.DialogManager.DIALOG_SEND_TO_GOOGLE; -import com.google.android.accounts.Account; import com.google.android.apps.mytracks.content.MyTracksProviderUtils; -import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.TrackDataHub; import com.google.android.apps.mytracks.content.WaypointCreationRequest; -import com.google.android.apps.mytracks.io.AuthManager; -import com.google.android.apps.mytracks.io.AuthManagerFactory; -import com.google.android.apps.mytracks.io.SendToDocs; -import com.google.android.apps.mytracks.io.SendToFusionTables; -import com.google.android.apps.mytracks.io.SendToFusionTables.OnSendCompletedListener; -import com.google.android.apps.mytracks.io.SendToMyMaps; import com.google.android.apps.mytracks.io.file.GpxImporter; import com.google.android.apps.mytracks.io.file.TempFileCleaner; -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.io.mymaps.MapsFacade; -import com.google.android.apps.mytracks.io.mymaps.MyMapsConstants; -import com.google.android.apps.mytracks.io.sendtogoogle.ResultDialogFactory; -import com.google.android.apps.mytracks.io.sendtogoogle.SendDialog; -import com.google.android.apps.mytracks.io.sendtogoogle.SendResult; -import com.google.android.apps.mytracks.io.sendtogoogle.SendType; import com.google.android.apps.mytracks.services.ITrackRecordingService; import com.google.android.apps.mytracks.services.TrackRecordingService; import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory; import com.google.android.apps.mytracks.util.ApiFeatures; -import com.google.android.apps.mytracks.util.FileUtils; import com.google.android.apps.mytracks.util.SystemUtils; import com.google.android.maps.mytracks.R; @@ -60,13 +40,9 @@ import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.res.Resources; -import android.net.Uri; import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; import android.os.IBinder; import android.os.RemoteException; -import android.text.TextUtils; import android.util.Log; import android.view.Menu; import android.view.MenuItem; @@ -79,13 +55,9 @@ import android.widget.RelativeLayout; import android.widget.TabHost; import android.widget.Toast; -import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; import javax.xml.parsers.ParserConfigurationException; @@ -98,21 +70,7 @@ import org.xml.sax.SAXException; */ public class MyTracks extends TabActivity implements OnTouchListener, ProgressIndicator { - /** - * Singleton instance - */ - private static MyTracks instance; - private TrackDataHub dataHub; - private ChartActivity chartActivity; - - /* - * Authentication - */ - private AuthManager auth; - private final HashMap authMap = - new HashMap(); - private final AccountChooser accountChooser = new AccountChooser(); /* * Dialogs manager. @@ -124,21 +82,6 @@ public class MyTracks extends TabActivity implements OnTouchListener, */ private MenuManager menuManager; - /* - * Information on upload success to MyMaps/Docs. - * Used by SendToGoogleResultDialog. - */ - - public long sendToTrackId = -1; - public boolean sendToMyMapsSuccess = false; - public boolean sendToFusionTablesSuccess = false; - public boolean sendToDocsSuccess = false; - public String sendToMyMapsMapId; - public String sendToMyMapsMessage = ""; - public String sendToFusionTablesTableId; - public String sendToFusionTablesMessage = ""; - public String sendToDocsMessage = ""; - /** * True if a new track should be created after the track recording service * binds. @@ -147,11 +90,6 @@ public class MyTracks extends TabActivity implements OnTouchListener, private ITrackRecordingService trackRecordingService; - /** - * Does the user want to share the current track. - */ - private boolean shareRequested = false; - /** * Utilities to deal with the database. */ @@ -205,10 +143,6 @@ public class MyTracks extends TabActivity implements OnTouchListener, } }; - public static MyTracks getInstance() { - return instance; - } - /** * Checks whether we have a track recording session in progress. * In some cases, when the service has crashed or has been restarted @@ -318,6 +252,53 @@ public class MyTracks extends TabActivity implements OnTouchListener, } } + private void importGpxFile(final String fileName) { + dialogManager.showDialogSafely(DIALOG_IMPORT_PROGRESS); + Thread t = new Thread() { + @Override + public void run() { + int message = R.string.success; + + long[] trackIdsImported = null; + + try { + try { + InputStream is = new FileInputStream(fileName); + trackIdsImported = GpxImporter.importGPXFile(is, providerUtils); + } catch (SAXException e) { + Log.e(TAG, "Caught an unexpected exception.", e); + message = R.string.error_generic; + } catch (ParserConfigurationException e) { + Log.e(TAG, "Caught an unexpected exception.", e); + message = R.string.error_generic; + } catch (IOException e) { + Log.e(TAG, "Caught an unexpected exception.", e); + message = R.string.error_unable_to_read_file; + } catch (NullPointerException e) { + Log.e(TAG, "Caught an unexpected exception.", e); + message = R.string.error_invalid_gpx_format; + } catch (OutOfMemoryError e) { + Log.e(TAG, "Caught an unexpected exception.", e); + message = R.string.error_out_of_memory; + } + if (trackIdsImported != null && trackIdsImported.length > 0) { + // select last track from import file + dataHub.loadTrack(trackIdsImported[trackIdsImported.length - 1]); + } else { + dialogManager.showMessageDialog(message, false/* success */); + } + } finally { + runOnUiThread(new Runnable() { + public void run() { + dismissDialog(DIALOG_IMPORT_PROGRESS); + } + }); + } + } + }; + t.start(); + } + @Override protected void onDestroy() { Log.d(TAG, "MyTracks.onDestroy"); @@ -410,12 +391,6 @@ public class MyTracks extends TabActivity implements OnTouchListener, return dialogManager.onCreateDialog(id, null); } - @Override - protected void onPrepareDialog(int id, Dialog dialog) { - super.onPrepareDialog(id, dialog); - dialogManager.onPrepareDialog(id, dialog); - } - /* * Key events: * =========== @@ -442,19 +417,12 @@ public class MyTracks extends TabActivity implements OnTouchListener, public void onActivityResult(int requestCode, int resultCode, final Intent results) { Log.d(TAG, "MyTracks.onActivityResult"); - TrackFileFormat exportFormat = null; long trackId = dataHub.getSelectedTrackId(); if (results != null) { trackId = results.getLongExtra("trackid", trackId); } switch (requestCode) { - case Constants.GET_LOGIN: { - if (resultCode != RESULT_OK || auth == null || !auth.authResult(resultCode, results)) { - dialogManager.dismissDialogSafely(DIALOG_PROGRESS); - } - break; - } case Constants.SHOW_TRACK: { if (results != null) { if (trackId >= 0) { @@ -497,118 +465,6 @@ public class MyTracks extends TabActivity implements OnTouchListener, } break; } - case Constants.SEND_TO_GOOGLE_DIALOG: { - shareRequested = false; - dialogManager.showDialogSafely(DIALOG_SEND_TO_GOOGLE); - break; - } - case Constants.GET_MAP: { - // User picked a map to upload to - if (resultCode == RESULT_OK) { - results.putExtra("trackid", dataHub.getSelectedTrackId()); - if (results.hasExtra("mapid")) { - sendToMyMapsMapId = results.getStringExtra("mapid"); - } - authenticateToGoogleMaps(results); - } else { - onSendToGoogleDone(); - } - break; - } - case Constants.AUTHENTICATE_TO_MY_MAPS: { - // Authenticated with Google My Maps - if (results != null && resultCode == RESULT_OK) { - final String mapId; - if (results.hasExtra("mapid")) { - mapId = results.getStringExtra("mapid"); - } else { - mapId = "new"; - } - - sendToGoogleMaps(trackId, mapId); - } else { - onSendToGoogleDone(); - } - break; - } - case Constants.AUTHENTICATE_TO_FUSION_TABLES: { - // Authenticated with Google Fusion Tables - if (results != null && resultCode == RESULT_OK) { - sendToFusionTables(trackId); - } else { - onSendToGoogleDone(); - } - break; - } - case Constants.AUTHENTICATE_TO_DOCLIST: { - // Authenticated with Google Docs - if (resultCode == RESULT_OK) { - authenticateToGoogleTrix(); - } else { - onSendToGoogleDone(); - } - break; - } - case Constants.AUTHENTICATE_TO_TRIX: { - // Authenticated with Trix - if (resultCode == RESULT_OK) { - sendToGoogleDocs(trackId); - } else { - onSendToGoogleDone(); - } - break; - } - case Constants.SAVE_GPX_FILE: - if (exportFormat == null) { exportFormat = TrackFileFormat.GPX; } - //$FALL-THROUGH$ - case Constants.SAVE_KML_FILE: - if (exportFormat == null) { exportFormat = TrackFileFormat.KML; } - //$FALL-THROUGH$ - case Constants.SAVE_CSV_FILE: - if (exportFormat == null) { exportFormat = TrackFileFormat.CSV; } - //$FALL-THROUGH$ - case Constants.SAVE_TCX_FILE: - if (exportFormat == null) { exportFormat = TrackFileFormat.TCX; } - - if (results != null && resultCode == Activity.RESULT_OK) { - if (trackId >= 0) { - saveTrack(trackId, exportFormat); - } - } - break; - case Constants.SHARE_LINK: { - Track selectedTrack = providerUtils.getTrack(dataHub.getSelectedTrackId()); - if (selectedTrack != null) { - if (!TextUtils.isEmpty(selectedTrack.getMapId())) { - shareLinkToMap(MapsFacade.buildMapUrl(selectedTrack.getMapId())); - } else if (!TextUtils.isEmpty(selectedTrack.getTableId())) { - shareLinkToMap(getFusionTablesUrl(dataHub.getSelectedTrackId())); - } else { - shareRequested = true; - dialogManager.showDialogSafely(DIALOG_SEND_TO_GOOGLE); - } - } - break; - } - case Constants.SHARE_GPX_FILE: - if (exportFormat == null) { exportFormat = TrackFileFormat.GPX; } - //$FALL-THROUGH$ - case Constants.SHARE_KML_FILE: - if (exportFormat == null) { exportFormat = TrackFileFormat.KML; } - //$FALL-THROUGH$ - case Constants.SHARE_CSV_FILE: - if (exportFormat == null) { exportFormat = TrackFileFormat.CSV; } - //$FALL-THROUGH$ - case Constants.SHARE_TCX_FILE: { - if (exportFormat == null) { exportFormat = TrackFileFormat.TCX; } - - if (results != null && resultCode == Activity.RESULT_OK) { - if (trackId >= 0) { - sendTrack(trackId, exportFormat); - } - } - break; - } case Constants.CLEAR_MAP: { dataHub.unloadCurrentTrack(); break; @@ -631,68 +487,6 @@ public class MyTracks extends TabActivity implements OnTouchListener, } return false; } - - /** - * Resets status information for sending to MyMaps/Docs. - */ - public void resetSendToGoogleStatus() { - sendToMyMapsMapId = null; - sendToMyMapsMessage = ""; - sendToMyMapsSuccess = true; - sendToFusionTablesMessage = ""; - sendToFusionTablesSuccess = true; - sendToDocsMessage = ""; - sendToDocsSuccess = true; - sendToFusionTablesTableId = null; - } - - private void importGpxFile(final String fileName) { - dialogManager.showDialogSafely(DIALOG_IMPORT_PROGRESS); - Thread t = new Thread() { - @Override - public void run() { - int message = R.string.success; - - long[] trackIdsImported = null; - - try { - try { - InputStream is = new FileInputStream(fileName); - trackIdsImported = GpxImporter.importGPXFile(is, providerUtils); - } catch (SAXException e) { - Log.e(TAG, "Caught an unexpected exception.", e); - message = R.string.error_generic; - } catch (ParserConfigurationException e) { - Log.e(TAG, "Caught an unexpected exception.", e); - message = R.string.error_generic; - } catch (IOException e) { - Log.e(TAG, "Caught an unexpected exception.", e); - message = R.string.error_unable_to_read_file; - } catch (NullPointerException e) { - Log.e(TAG, "Caught an unexpected exception.", e); - message = R.string.error_invalid_gpx_format; - } catch (OutOfMemoryError e) { - Log.e(TAG, "Caught an unexpected exception.", e); - message = R.string.error_out_of_memory; - } - if (trackIdsImported != null && trackIdsImported.length > 0) { - // select last track from import file - dataHub.loadTrack(trackIdsImported[trackIdsImported.length - 1]); - } else { - dialogManager.showMessageDialog(message, false/* success */); - } - } finally { - runOnUiThread(new Runnable() { - public void run() { - dismissDialog(DIALOG_IMPORT_PROGRESS); - } - }); - } - } - }; - t.start(); - } - // ProgressIndicator implementation @Override @@ -710,29 +504,6 @@ public class MyTracks extends TabActivity implements OnTouchListener, dialogManager.setProgressValue(percent); } - /** - * Shares a link to a My Map or Fusion Table via external app (email, gmail, ...) - * A chooser with apps that support text/plain will be shown to the user. - */ - public void shareLinkToMap(String url) { - Intent shareIntent = new Intent(Intent.ACTION_SEND); - shareIntent.setType("text/plain"); - shareIntent.putExtra(Intent.EXTRA_SUBJECT, - getResources().getText(R.string.share_map_subject).toString()); - - boolean shareUrlOnly = true; - if (sharedPreferences != null) { - shareUrlOnly = sharedPreferences.getBoolean( - getString(R.string.share_url_only_key), false); - } - - String msg = shareUrlOnly ? url : String.format( - getResources().getText(R.string.share_map_body_format).toString(), url); - shareIntent.putExtra(Intent.EXTRA_TEXT, msg); - startActivity(Intent.createChooser(shareIntent, - getResources().getText(R.string.share_map).toString())); - } - /** * Deletes the track with the given id. * Prompts the user if he want to really delete the track first. @@ -787,54 +558,6 @@ public class MyTracks extends TabActivity implements OnTouchListener, } } - /** - * Initializes the authentication manager which obtains an authentication - * token, prompting the user for a login and password if needed. - */ - private void authenticate(final Intent results, final int requestCode, - final String service) { - auth = authMap.get(service); - if (auth == null) { - Log.i(TAG, "Creating a new authentication for service: " + service); - auth = AuthManagerFactory.getAuthManager(this, - Constants.GET_LOGIN, - null, - true, - service); - authMap.put(service, auth); - } - Log.d(TAG, "Logging in to " + service + "..."); - if (AuthManagerFactory.useModernAuthManager()) { - runOnUiThread(new Runnable() { - @Override - public void run() { - accountChooser.chooseAccount(MyTracks.this, - new AccountChooser.AccountHandler() { - @Override - public void handleAccountSelected(Account account) { - if (account == null) { - dialogManager.dismissDialogSafely(DIALOG_PROGRESS); - return; - } - doLogin(results, requestCode, service, account); - } - }); - } - }); - } else { - doLogin(results, requestCode, service, null); - } - } - - private void doLogin(final Intent results, final int requestCode, - final String service, final Account account) { - auth.doLogin(new Runnable() { - public void run() { - Log.d(TAG, "Loggin success for " + service + "!"); - onActivityResult(requestCode, RESULT_OK, results); - } - }, account); - } private void startRecordingNewTrack( ITrackRecordingService trackRecordingService) { @@ -900,290 +623,6 @@ public class MyTracks extends TabActivity implements OnTouchListener, } trackRecordingService = null; } - - /** - * Initiates the process to send tracks to google. - * This is called once the user has selected sending options via the - * SendToGoogleDialog. - * - * TODO: Change this whole flow to an actual state machine. - */ - public void sendToGoogle() { - SendDialog sendToGoogleDialog = - dialogManager.getSendToGoogleDialog(); - if (sendToGoogleDialog == null) { - return; - } - setProgressValue(0); - clearProgressMessage(); - dialogManager.showDialogSafely(DIALOG_PROGRESS); - - if (sendToGoogleDialog.getSendToMyMaps()) { - sendToGoogleMapsOrPickMap(sendToGoogleDialog); - } else if (sendToGoogleDialog.getSendToFusionTables()) { - authenticateToFusionTables(null); - } else if (sendToGoogleDialog.getSendToDocs()) { - authenticateToGoogleDocs(); - } else { - Log.w(TAG, "Nowhere to upload to"); - onSendToGoogleDone(); - } - } - - private void sendToGoogleMapsOrPickMap(SendDialog sendToGoogleDialog) { - if (!sendToGoogleDialog.getCreateNewMap()) { - // Ask the user to choose a map to upload into - Intent listIntent = new Intent(this, MyMapsList.class); - startActivityForResult(listIntent, Constants.GET_MAP); - // The callback for GET_MAP calls authenticateToGoogleMaps - } else { - authenticateToGoogleMaps(null); - } - } - - private void authenticateToGoogleMaps(Intent results) { - if (results == null) { results = new Intent(); } - - setProgressValue(0); - setProgressMessage( - R.string.progress_message_authenticating_mymaps); - authenticate(results, Constants.AUTHENTICATE_TO_MY_MAPS, - MyMapsConstants.SERVICE_NAME); - // AUTHENTICATE_TO_MY_MAPS callback calls sendToGoogleMaps - } - - private void sendToGoogleMaps(final long trackId, String mapId) { - SendToMyMaps.OnSendCompletedListener onCompletion = new SendToMyMaps.OnSendCompletedListener() { - @Override - public void onSendCompleted(String mapId, boolean success, int statusMessage) { - sendToMyMapsMessage = getString(statusMessage); - sendToMyMapsSuccess = success; - if (sendToMyMapsSuccess) { - sendToMyMapsMapId = mapId; - // Update the map id for this track: - try { - Track track = providerUtils.getTrack(trackId); - track.setMapId(mapId); - providerUtils.updateTrack(track); - } catch (RuntimeException e) { - // If that fails whatever reasons we'll just log an error, but - // continue. - Log.w(TAG, "Updating map id failed.", e); - } - } - - onSendToGoogleMapsDone(); - } - }; - final SendToMyMaps sender = new SendToMyMaps(this, mapId, auth, - trackId, this /*progressIndicator*/, onCompletion); - - HandlerThread handlerThread = new HandlerThread("SendToMyMaps"); - handlerThread.start(); - Handler handler = new Handler(handlerThread.getLooper()); - handler.post(sender); - } - - private void onSendToGoogleMapsDone() { - SendDialog sendToGoogleDialog = dialogManager.getSendToGoogleDialog(); - if (sendToGoogleDialog.getSendToFusionTables()) { - authenticateToFusionTables(null); - } else if (sendToGoogleDialog.getSendToDocs()) { - authenticateToGoogleDocs(); - } else { - onSendToGoogleDone(); - } - } - - private void authenticateToFusionTables(Intent results) { - if (results == null) { results = new Intent(); } - - setProgressValue(0); - setProgressMessage(R.string.progress_message_authenticating_fusiontables); - authenticate(results, Constants.AUTHENTICATE_TO_FUSION_TABLES, - SendToFusionTables.SERVICE_ID); - // AUTHENTICATE_TO_FUSION_TABLES callback calls sendToFusionTables - } - - private void sendToFusionTables(final long trackId) { - OnSendCompletedListener onCompletion = new OnSendCompletedListener() { - @Override - public void onSendCompleted(String tableId, boolean success, - int statusMessage) { - sendToFusionTablesMessage = getString(statusMessage); - sendToFusionTablesSuccess = success; - if (sendToFusionTablesSuccess) { - sendToFusionTablesTableId = tableId; - // Update the table id for this track: - try { - Track track = providerUtils.getTrack(trackId); - track.setTableId(tableId); - providerUtils.updateTrack(track); - } catch (RuntimeException e) { - // If that fails whatever reasons we'll just log an error, but - // continue. - Log.w(TAG, "Updating table id failed.", e); - } - } - - onSendToFusionTablesDone(); - } - }; - sendToTrackId = trackId; - final SendToFusionTables sender = new SendToFusionTables(this, auth, - trackId, this/*progressIndicator*/, onCompletion); - - HandlerThread handlerThread = new HandlerThread("SendToFusionTables"); - handlerThread.start(); - Handler handler = new Handler(handlerThread.getLooper()); - handler.post(sender); - } - - private void onSendToFusionTablesDone() { - SendDialog sendToGoogleDialog = dialogManager.getSendToGoogleDialog(); - if (sendToGoogleDialog.getSendToDocs()) { - authenticateToGoogleDocs(); - } else { - onSendToGoogleDone(); - } - } - - private void authenticateToGoogleDocs() { - setProgressValue(0); - setProgressMessage( - R.string.progress_message_authenticating_docs); - authenticate(new Intent(), - Constants.AUTHENTICATE_TO_DOCLIST, - SendToDocs.GDATA_SERVICE_NAME_DOCLIST); - // AUTHENTICATE_TO_DOCLIST callback calls authenticateToGoogleTrix - } - - private void authenticateToGoogleTrix() { - setProgressValue(30); - setProgressMessage( - R.string.progress_message_authenticating_docs); - authenticate(new Intent(), - Constants.AUTHENTICATE_TO_TRIX, - SendToDocs.GDATA_SERVICE_NAME_TRIX); - // AUTHENTICATE_TO_TRIX callback calls sendToGoogleDocs - } - - private void sendToGoogleDocs(final long trackId) { - Log.d(TAG, "Sending to Docs...."); - setProgressValue(50); - setProgressMessage(R.string.progress_message_sending_docs); - final SendToDocs sender = new SendToDocs(this, - authMap.get(SendToDocs.GDATA_SERVICE_NAME_TRIX), - authMap.get(SendToDocs.GDATA_SERVICE_NAME_DOCLIST), trackId); - sendToTrackId = trackId; - Runnable onCompletion = new Runnable() { - public void run() { - setProgressValue(100); - dialogManager.dismissDialogSafely(DIALOG_PROGRESS); - sendToDocsMessage = sender.getStatusMessage(); - sendToDocsSuccess = sender.wasSuccess(); - - onSendToGoogleDocsDone(); - } - }; - sender.setOnCompletion(onCompletion); - sender.run(); - } - - private void onSendToGoogleDocsDone() { - onSendToGoogleDone(); - } - - private void onSendToGoogleDone() { - SendDialog sendToGoogleDialog = dialogManager.getSendToGoogleDialog(); - final boolean sentToMyMaps = sendToGoogleDialog.getSendToMyMaps(); - final boolean sentToFusionTables = sendToGoogleDialog.getSendToFusionTables(); - dialogManager.dismissDialogSafely(DIALOG_PROGRESS); - - // We've finished sending the track to the user-selected services. Now - // we tell them the results of the upload, and optionally share the track. - // There are a few different paths through this code: - // - // 1. The user pre-requested a share (shareRequested == true). We're going - // to display the result dialog *without* the share button (the share - // listener will be null). The OK button listener will initiate the - // share. - // - // 2. The user did not pre-request a share, and the set of services to - // which we succeeded in uploading the track are compatible with - // sharing. We'll display a share button (the share listener will be - // non-null), and will share the link if the user clicks it. - // - // 3. The user did not pre-request a share, and the set of services to - // which we succeeded in uploading the track are incompatible with - // sharing. We won't display a share button. - - final boolean canShare = getSendToFusionTablesTableId() != null - || getSendToMyMapsMapId() != null; - - DialogInterface.OnClickListener doShareListener = null; - if (canShare) { - doShareListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - shareLinkToMap(sentToMyMaps, sentToFusionTables); - } - }; - } - - DialogInterface.OnClickListener onOkListener = (canShare && shareRequested) - ? doShareListener : null; - DialogInterface.OnClickListener onShareListener = (canShare && !shareRequested) - ? doShareListener : null; - - AlertDialog sendToGoogleResultDialog = ResultDialogFactory.makeDialog(this, - makeSendToGoogleResults(sendToGoogleDialog), onOkListener, onShareListener); - DialogManager.showDialogSafely(this, sendToGoogleResultDialog); - } - - boolean shareLinkToMap(boolean sentToMyMaps, boolean sentToFusionTables) { - String url = null; - if (sentToMyMaps && sendToMyMapsSuccess) { - // Prefer a link to My Maps - url = MapsFacade.buildMapUrl(sendToMyMapsMapId); - } else if (sentToFusionTables && sendToFusionTablesSuccess) { - // Otherwise try using the link to fusion tables - url = getFusionTablesUrl(sendToTrackId); - } - - if (url != null) { - shareLinkToMap(url); - return true; - } - - return false; - } - - protected String getFusionTablesUrl(long trackId) { - Track track = providerUtils.getTrack(trackId); - return track == null ? "" : SendToFusionTables.getMapVisualizationUrl(track); - } - - /** - * Creates a list of {@link SendResult} instances based on the set of - * services selected in {@link SendDialog} and the results as known to - * this class. - */ - private List makeSendToGoogleResults(SendDialog dialog) { - List results = new ArrayList(); - if (dialog.getSendToMyMaps()) { - results.add(new SendResult(SendType.MYMAPS, sendToMyMapsSuccess)); - } - if (dialog.getSendToFusionTables()) { - results.add(new SendResult(SendType.FUSION_TABLES, sendToFusionTablesSuccess)); - } - if (dialog.getSendToDocs()) { - results.add(new SendResult(SendType.DOCS, sendToDocsSuccess)); - } - - return results; - } - void clearSelectedTrack() { dataHub.unloadCurrentTrack(); } @@ -1221,94 +660,10 @@ public class MyTracks extends TabActivity implements OnTouchListener, } } - /** - * Saves the track with the given id to the SD card. - * - * @param trackId The id of the track to be sent - */ - public void saveTrack(long trackId, TrackFileFormat format) { - TrackWriter writer = TrackWriterFactory.newWriter(this, providerUtils, trackId, format); - WriteProgressController controller = new WriteProgressController(this, writer); - controller.setOnCompletionListener(new WriteProgressController.OnCompletionListener() { - @Override - public void onComplete(TrackWriter writer) { - dialogManager.showMessageDialog(writer.getErrorMessage(), writer.wasSuccess()); - } - }); - controller.startWrite(); - } - - /** - * Sends the requested track as an email attachment. - * This will leave the gpx file on the SD card for at least one hour. - * Temporary gpx files will be deleted in onStop. - * - * @param trackId The id of the track to be sent - */ - public void sendTrack(long trackId, final TrackFileFormat format) { - TrackWriter writer = TrackWriterFactory.newWriter(this, providerUtils, trackId, format); - - FileUtils fileUtils = new FileUtils(); - String extension = format.getExtension(); - String dirName = fileUtils.buildExternalDirectoryPath(extension, "tmp"); - - File dir = new File(dirName); - writer.setDirectory(dir); - - WriteProgressController controller = new WriteProgressController(this, writer); - controller.setOnCompletionListener(new WriteProgressController.OnCompletionListener() { - @Override - public void onComplete(TrackWriter writer) { - if (!writer.wasSuccess()) { - dialogManager.showMessageDialog(writer.getErrorMessage(), writer.wasSuccess()); - return; - } - - Intent shareIntent = new Intent(Intent.ACTION_SEND); - shareIntent.putExtra(Intent.EXTRA_SUBJECT, - getResources().getText(R.string.send_track_subject).toString()); - shareIntent.putExtra(Intent.EXTRA_TEXT, - getResources().getText(R.string.send_track_body_format) - .toString()); - shareIntent.setType(format.getMimeType()); - Uri u = Uri.fromFile(new File(writer.getAbsolutePath())); - shareIntent.putExtra(Intent.EXTRA_STREAM, u); - startActivity(Intent.createChooser(shareIntent, - getResources().getText(R.string.share_track).toString())); - } - }); - - controller.startWrite(); - } - - public AccountChooser getAccountChooser() { - return accountChooser; - } - - public ChartActivity getChartActivity() { - return chartActivity; - } - - public void setChartActivity(ChartActivity chartActivity) { - this.chartActivity = chartActivity; - } - public DialogManager getDialogManager() { return dialogManager; } - public String getSendToMyMapsMapId() { - return sendToMyMapsMapId; - } - - public String getSendToFusionTablesTableId() { - return sendToFusionTablesTableId; - } - - public boolean getSendToGoogleSuccess() { - return sendToFusionTablesSuccess && sendToDocsSuccess; - } - // @VisibleForTesting long getRecordingTrackId() { return sharedPreferences.getLong(getString(R.string.recording_track_key), -1); @@ -1319,11 +674,6 @@ public class MyTracks extends TabActivity implements OnTouchListener, return sharedPreferences; } - // @VisibleForTesting - static void clearInstance() { - instance = null; - } - // @VisibleForTesting ITrackRecordingService getTrackRecordingService() { return trackRecordingService; @@ -1332,4 +682,15 @@ public class MyTracks extends TabActivity implements OnTouchListener, public TrackDataHub getDataHub() { return dataHub; } + + // TODO: Remove very soon + private static MyTracks instance; + + public static MyTracks getInstance() { + return instance; + } + + public static void clearInstance() { + instance = null; + } } diff --git a/MyTracks/src/com/google/android/apps/mytracks/TrackList.java b/MyTracks/src/com/google/android/apps/mytracks/TrackList.java index d39fbc032..d75cfbbbd 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/TrackList.java +++ b/MyTracks/src/com/google/android/apps/mytracks/TrackList.java @@ -16,6 +16,8 @@ package com.google.android.apps.mytracks; import com.google.android.apps.mytracks.content.TracksColumns; +import com.google.android.apps.mytracks.io.file.SaveActivity; +import com.google.android.apps.mytracks.io.sendtogoogle.SendActivity; import com.google.android.apps.mytracks.util.StringUtils; import com.google.android.apps.mytracks.util.UnitConversions; import com.google.android.maps.mytracks.R; @@ -138,32 +140,46 @@ public class TrackList extends ListActivity @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { - if (!super.onMenuItemSelected(featureId, item)) { - switch (item.getItemId()) { - case Constants.MENU_SHOW: { - onListItemClick(null, null, 0, trackId); - return true; - } - case Constants.MENU_EDIT: { - Intent intent = new Intent(this, TrackDetails.class); - intent.putExtra("trackid", trackId); - startActivity(intent); - return true; - } - case Constants.MENU_SHARE: - case Constants.MENU_WRITE_TO_SD_CARD: - return false; - default: { - Intent result = new Intent(); - result.putExtra("trackid", trackId); - setResult( - Constants.getActionFromMenuId(item.getItemId()), result); - finish(); - return true; - } + switch (item.getItemId()) { + case Constants.MENU_SHOW: { + onListItemClick(null, null, 0, trackId); + return true; + } + case Constants.MENU_EDIT: { + Intent intent = new Intent(this, TrackDetails.class); + intent.putExtra("trackid", trackId); + startActivity(intent); + return true; + } + case Constants.MENU_SHARE: + case Constants.MENU_WRITE_TO_SD_CARD: + return false; + case Constants.MENU_SEND_TO_GOOGLE: + SendActivity.sendToGoogle(this, trackId, false); + return true; + case Constants.MENU_SHARE_LINK: + SendActivity.sendToGoogle(this, trackId, true); + return true; + case Constants.MENU_SAVE_GPX_FILE: + case Constants.MENU_SAVE_KML_FILE: + case Constants.MENU_SAVE_CSV_FILE: + case Constants.MENU_SAVE_TCX_FILE: + case Constants.MENU_SHARE_GPX_FILE: + case Constants.MENU_SHARE_KML_FILE: + case Constants.MENU_SHARE_CSV_FILE: + case Constants.MENU_SHARE_TCX_FILE: + SaveActivity.handleExportTrackAction(this, trackId, + Constants.getActionFromMenuId(item.getItemId())); + return true; + default: { + Intent result = new Intent(); + result.putExtra("trackid", trackId); + setResult( + Constants.getActionFromMenuId(item.getItemId()), result); + finish(); + return true; } } - return false; } @Override diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/ModernAuthManager.java b/MyTracks/src/com/google/android/apps/mytracks/io/ModernAuthManager.java index 24c721bc4..8048f4fab 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/ModernAuthManager.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/ModernAuthManager.java @@ -22,7 +22,6 @@ import com.google.android.accounts.AccountManagerFuture; import com.google.android.accounts.AuthenticatorException; import com.google.android.accounts.OperationCanceledException; import com.google.android.apps.mytracks.AccountChooser; -import com.google.android.apps.mytracks.MyTracks; import com.google.android.apps.mytracks.Constants; import android.app.Activity; @@ -183,7 +182,9 @@ public class ModernAuthManager implements AuthManager { public void run() { accountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE, authToken); - MyTracks.getInstance().getAccountChooser().chooseAccount(activity, + + AccountChooser accountChooser = new AccountChooser(); + accountChooser.chooseAccount(activity, new AccountChooser.AccountHandler() { @Override public void handleAccountSelected(Account account) { diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/SendToDocs.java b/MyTracks/src/com/google/android/apps/mytracks/io/SendToDocs.java index 5105285e4..1b0047740 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/SendToDocs.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/SendToDocs.java @@ -15,8 +15,8 @@ */ package com.google.android.apps.mytracks.io; -import com.google.android.apps.mytracks.MyTracks; import com.google.android.apps.mytracks.Constants; +import com.google.android.apps.mytracks.ProgressIndicator; import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.io.docs.DocsHelper; @@ -25,10 +25,10 @@ import com.google.android.apps.mytracks.io.gdata.GDataWrapper; import com.google.android.common.gdata.AndroidXmlParserFactory; import com.google.android.maps.mytracks.R; import com.google.wireless.gdata.client.GDataClient; +import com.google.wireless.gdata.client.GDataServiceClient; import com.google.wireless.gdata.docs.DocumentsClient; import com.google.wireless.gdata.docs.SpreadsheetsClient; import com.google.wireless.gdata.docs.XmlDocsGDataParserFactory; -import com.google.wireless.gdata.client.GDataServiceClient; import android.app.Activity; import android.content.SharedPreferences; @@ -49,11 +49,11 @@ public class SendToDocs { /** The GData service name for the Google Docs Document List */ public static final String GDATA_SERVICE_NAME_DOCLIST = "writely"; - + private final Activity activity; private final AuthManager trixAuth; private final AuthManager docListAuth; - private final long trackId; + private final ProgressIndicator progressIndicator; private final boolean metricUnits; private final HandlerThread handlerThread; private final Handler handler; @@ -64,12 +64,13 @@ public class SendToDocs { private String statusMessage = ""; private Runnable onCompletion = null; + public SendToDocs(Activity activity, AuthManager trixAuth, - AuthManager docListAuth, long trackId) { + AuthManager docListAuth, ProgressIndicator progressIndicator) { this.activity = activity; this.trixAuth = trixAuth; this.docListAuth = docListAuth; - this.trackId = trackId; + this.progressIndicator = progressIndicator; SharedPreferences preferences = activity.getSharedPreferences( Constants.SETTINGS_NAME, 0); @@ -81,23 +82,23 @@ public class SendToDocs { metricUnits = true; } - Log.d(Constants.TAG, - "Sending to Google Docs: trackId = " + trackId); handlerThread = new HandlerThread("SendToGoogleDocs"); handlerThread.start(); handler = new Handler(handlerThread.getLooper()); } - public void run() { + public void sendToDocs(final long trackId) { + Log.d(Constants.TAG, + "Sending to Google Docs: trackId = " + trackId); handler.post(new Runnable() { @Override public void run() { - doUpload(); + doUpload(trackId); } }); } - private void doUpload() { + private void doUpload(long trackId) { // TODO statusMessage = activity.getString(R.string.error_sending_to_fusiontables); success = false; @@ -198,7 +199,7 @@ public class SendToDocs { } if (spreadsheetId == null) { - MyTracks.getInstance().setProgressValue(65); + progressIndicator.setProgressValue(65); // Waiting a few seconds and trying again. Maybe the server just had a // hickup (unfortunately that happens quite a lot...). try { @@ -217,7 +218,7 @@ public class SendToDocs { } // We were unable to find an existing spreadsheet, so create a new one. - MyTracks.getInstance().setProgressValue(70); + progressIndicator.setProgressValue(70); if (spreadsheetId == null) { Log.i(Constants.TAG, "Creating new spreadsheet: " + sheetTitle); @@ -229,11 +230,11 @@ public class SendToDocs { + sheetTitle, e); return false; } - MyTracks.getInstance().setProgressValue(80); + progressIndicator.setProgressValue(80); createdNewSpreadSheet = true; if (spreadsheetId == null) { - MyTracks.getInstance().setProgressValue(85); + progressIndicator.setProgressValue(85); // The previous creation might have succeeded even though GData // reported an error. Seems to be a know bug, // see http://code.google.com/p/gdata-issues/issues/detail?id=929 @@ -255,7 +256,7 @@ public class SendToDocs { } if (spreadsheetId == null) { - MyTracks.getInstance().setProgressValue(87); + progressIndicator.setProgressValue(87); // Re-try try { Thread.sleep(5000); @@ -290,7 +291,7 @@ public class SendToDocs { return false; } - MyTracks.getInstance().setProgressValue(90); + progressIndicator.setProgressValue(90); docsHelper.addTrackRow(activity, trixAuth, spreadsheetId, worksheetId, track, metricUnits); 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 new file mode 100644 index 000000000..f5c9e8688 --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveActivity.java @@ -0,0 +1,152 @@ +package com.google.android.apps.mytracks.io.file; + +import com.google.android.apps.mytracks.Constants; +import com.google.android.apps.mytracks.DialogManager; +import com.google.android.apps.mytracks.content.MyTracksProviderUtils; +import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat; +import com.google.android.apps.mytracks.util.FileUtils; +import com.google.android.maps.mytracks.R; + +import android.app.Activity; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; + +import java.io.File; + +public class SaveActivity extends Activity { + public static final String EXTRA_TRACK_ID = "track_id"; + public static final String EXTRA_SHARE_FILE = "share_file"; + public static final String EXTRA_FILE_FORMAT = "file_format"; + + private MyTracksProviderUtils providerUtils; + private long trackId; + private TrackWriter writer; + private boolean shareFile; + private TrackFileFormat format; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + providerUtils = MyTracksProviderUtils.Factory.get(this); + } + + @Override + protected void onStart() { + super.onStart(); + + Intent intent = getIntent(); + trackId = intent.getLongExtra(EXTRA_TRACK_ID, -1); + int formatIdx = intent.getIntExtra(EXTRA_FILE_FORMAT, -1); + format = TrackFileFormat.values()[formatIdx]; + shareFile = intent.getBooleanExtra(EXTRA_SHARE_FILE, false); + + writer = TrackWriterFactory.newWriter(this, providerUtils, trackId, format); + + if (shareFile) { + // 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); + } + + WriteProgressController controller = new WriteProgressController(this, writer); + controller.setOnCompletionListener(new WriteProgressController.OnCompletionListener() { + @Override + public void onComplete() { + onWriteComplete(); + } + }); + controller.startWrite(); + } + + private void onWriteComplete() { + if (shareFile) { + shareWrittenFile(); + } else { + showResultDialog(); + } + } + + private void shareWrittenFile() { + if (!writer.wasSuccess()) { + showResultDialog(); + return; + } + + // Share the file. + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.putExtra(Intent.EXTRA_SUBJECT, + getResources().getText(R.string.send_track_subject).toString()); + shareIntent.putExtra(Intent.EXTRA_TEXT, + getResources().getText(R.string.send_track_body_format) + .toString()); + shareIntent.setType(format.getMimeType()); + Uri u = Uri.fromFile(new File(writer.getAbsolutePath())); + shareIntent.putExtra(Intent.EXTRA_STREAM, u); + startActivity(Intent.createChooser(shareIntent, + getResources().getText(R.string.share_track).toString())); + } + + private void showResultDialog() { + DialogManager.showMessageDialog(this, writer.getErrorMessage(), writer.wasSuccess(), + new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int arg1) { + dialog.dismiss(); + finish(); + } + }); + } + + 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; + } + + Intent intent = new Intent(ctx, SaveActivity.class); + intent.putExtra(EXTRA_TRACK_ID, trackId); + intent.putExtra(EXTRA_FILE_FORMAT, exportFormat.ordinal()); + intent.putExtra(EXTRA_SHARE_FILE, shareFile); + intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + ctx.startActivity(intent); + } +} diff --git a/MyTracks/src/com/google/android/apps/mytracks/WriteProgressController.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/WriteProgressController.java similarity index 95% rename from MyTracks/src/com/google/android/apps/mytracks/WriteProgressController.java rename to MyTracks/src/com/google/android/apps/mytracks/io/file/WriteProgressController.java index 3f0356756..861df8ddd 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/WriteProgressController.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/WriteProgressController.java @@ -13,9 +13,9 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.google.android.apps.mytracks; +package com.google.android.apps.mytracks.io.file; -import com.google.android.apps.mytracks.io.file.TrackWriter; +import com.google.android.apps.mytracks.DialogManager; import com.google.android.maps.mytracks.R; import android.app.Activity; @@ -41,7 +41,7 @@ class WriteProgressController { * dialog has been dismissed. Whether the write succeeded can be * determined by examining the {@link TrackWriter}. */ - public void onComplete(TrackWriter writer); + public void onComplete(); } private final Activity activity; @@ -104,7 +104,7 @@ class WriteProgressController { DialogManager.dismissDialogSafely(activity, dialog); if (onCompletionListener != null) { - onCompletionListener.onComplete(writer); + onCompletionListener.onComplete(); } } }; diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendActivity.java b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendActivity.java new file mode 100644 index 000000000..cda4ec755 --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendActivity.java @@ -0,0 +1,619 @@ +package com.google.android.apps.mytracks.io.sendtogoogle; + +import static com.google.android.apps.mytracks.Constants.TAG; + +import com.google.android.accounts.Account; +import com.google.android.apps.mytracks.AccountChooser; +import com.google.android.apps.mytracks.Constants; +import com.google.android.apps.mytracks.DialogManager; +import com.google.android.apps.mytracks.MyMapsList; +import com.google.android.apps.mytracks.ProgressIndicator; +import com.google.android.apps.mytracks.content.MyTracksProviderUtils; +import com.google.android.apps.mytracks.content.Track; +import com.google.android.apps.mytracks.io.AuthManager; +import com.google.android.apps.mytracks.io.AuthManagerFactory; +import com.google.android.apps.mytracks.io.SendToDocs; +import com.google.android.apps.mytracks.io.SendToFusionTables; +import com.google.android.apps.mytracks.io.SendToFusionTables.OnSendCompletedListener; +import com.google.android.apps.mytracks.io.SendToMyMaps; +import com.google.android.apps.mytracks.io.mymaps.MapsFacade; +import com.google.android.apps.mytracks.io.mymaps.MyMapsConstants; +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.DialogInterface.OnClickListener; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.text.TextUtils; +import android.util.Log; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Helper for managing the sending of tracks to Google services. + * + * @author Rodrigo Damazio + */ +public class SendActivity extends Activity implements ProgressIndicator { + public static final String EXTRA_SHARE_LINK = "share_link"; + public static final String EXTRA_TRACK_ID = "track_id"; + + // Services + private MyTracksProviderUtils providerUtils; + private SharedPreferences sharedPreferences; + + // Authentication + private AuthManager lastAuth; + private final HashMap authMap = + new HashMap(); + private final AccountChooser accountChooser = new AccountChooser(); + + // Send request information. + private boolean shareRequested = false; + private long sendTrackId; + + // Send result information, used by SendToGoogleResultDialog. + private boolean sendToMyMapsSuccess = false; + private boolean sendToFusionTablesSuccess = false; + private boolean sendToDocsSuccess = false; + private String sendToMyMapsMapId; + private String sendToFusionTablesTableId; + + // TODO: Make these be used for showing results + @SuppressWarnings("unused") + private String sendToMyMapsMessage; + @SuppressWarnings("unused") + private String sendToFusionTablesMessage; + @SuppressWarnings("unused") + private String sendToDocsMessage; + + // State used while sending. + private SendDialog sendDialog; + private ProgressDialog progressDialog; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + providerUtils = MyTracksProviderUtils.Factory.get(this); + sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, 0); + } + + @Override + protected void onStart() { + super.onStart(); + resetState(); + + sendTrackId = getIntent().getLongExtra(EXTRA_TRACK_ID, -1); + + sendDialog = new SendDialog(this); + sendDialog.setOwnerActivity(this); + sendDialog.setOnClickListener(new OnClickListener() { + @Override + public void onClick(DialogInterface arg0, int which) { + if (which != DialogInterface.BUTTON_POSITIVE) { + finish(); + return; + } + + doSend(); + } + }); + sendDialog.show(); + } + + /** + * Initiates the process to send tracks to google. + * This is called once the user has selected sending options via the + * SendToGoogleDialog. + * + * TODO: Change this whole flow to an actual state machine. + */ + private void doSend() { + progressDialog = new ProgressDialog(this); + progressDialog.setIcon(android.R.drawable.ic_dialog_info); + progressDialog.setTitle(R.string.progress_title); + progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + progressDialog.setMessage(""); + progressDialog.setMax(100); + progressDialog.setProgress(0); + progressDialog.show(); + + if (sendDialog.getSendToMyMaps()) { + sendToGoogleMapsOrPickMap(); + } else if (sendDialog.getSendToFusionTables()) { + authenticateToFusionTables(null); + } else if (sendDialog.getSendToDocs()) { + authenticateToGoogleDocs(); + } else { + Log.w(TAG, "Nowhere to upload to"); + onSendToGoogleDone(); + } + } + + private void sendToGoogleMapsOrPickMap() { + if (!sendDialog.getCreateNewMap()) { + // Ask the user to choose a map to upload into + Intent listIntent = new Intent(this, MyMapsList.class); + startActivityForResult(listIntent, Constants.GET_MAP); + // The callback for GET_MAP calls authenticateToGoogleMaps + } else { + authenticateToGoogleMaps(null); + } + } + + private void authenticateToGoogleMaps(Intent results) { + if (results == null) { results = new Intent(); } + + progressDialog.setProgress(0); + progressDialog.setMessage(getString( + R.string.progress_message_authenticating_mymaps)); + authenticate(results, Constants.AUTHENTICATE_TO_MY_MAPS, + MyMapsConstants.SERVICE_NAME); + // AUTHENTICATE_TO_MY_MAPS callback calls sendToGoogleMaps + } + + private void sendToGoogleMaps(String mapId) { + SendToMyMaps.OnSendCompletedListener onCompletion = new SendToMyMaps.OnSendCompletedListener() { + @Override + public void onSendCompleted(String mapId, boolean success, int statusMessage) { + // TODO: Use this message + sendToMyMapsMessage = getString(statusMessage); + sendToMyMapsSuccess = success; + if (sendToMyMapsSuccess) { + sendToMyMapsMapId = mapId; + // Update the map id for this track: + try { + Track track = providerUtils.getTrack(sendTrackId); + track.setMapId(mapId); + providerUtils.updateTrack(track); + } catch (RuntimeException e) { + // If that fails whatever reasons we'll just log an error, but + // continue. + Log.w(TAG, "Updating map id failed.", e); + } + } + + onSendToGoogleMapsDone(); + } + }; + final SendToMyMaps sender = new SendToMyMaps(this, mapId, lastAuth, + sendTrackId, this /*progressIndicator*/, onCompletion); + + HandlerThread handlerThread = new HandlerThread("SendToMyMaps"); + handlerThread.start(); + Handler handler = new Handler(handlerThread.getLooper()); + handler.post(sender); + } + + private void onSendToGoogleMapsDone() { + if (sendDialog.getSendToFusionTables()) { + authenticateToFusionTables(null); + } else if (sendDialog.getSendToDocs()) { + authenticateToGoogleDocs(); + } else { + onSendToGoogleDone(); + } + } + + private void authenticateToFusionTables(Intent results) { + if (results == null) { results = new Intent(); } + + progressDialog.setProgress(0); + progressDialog.setMessage(getString( + R.string.progress_message_authenticating_fusiontables)); + authenticate(results, Constants.AUTHENTICATE_TO_FUSION_TABLES, + SendToFusionTables.SERVICE_ID); + // AUTHENTICATE_TO_FUSION_TABLES callback calls sendToFusionTables + } + + private void sendToFusionTables() { + OnSendCompletedListener onCompletion = new OnSendCompletedListener() { + @Override + public void onSendCompleted(String tableId, boolean success, + int statusMessage) { + // TODO: Use this message + sendToFusionTablesMessage = getString(statusMessage); + sendToFusionTablesSuccess = success; + if (sendToFusionTablesSuccess) { + sendToFusionTablesTableId = tableId; + // Update the table id for this track: + try { + Track track = providerUtils.getTrack(sendTrackId); + track.setTableId(tableId); + providerUtils.updateTrack(track); + } catch (RuntimeException e) { + // If that fails whatever reasons we'll just log an error, but + // continue. + Log.w(TAG, "Updating table id failed.", e); + } + } + + onSendToFusionTablesDone(); + } + }; + final SendToFusionTables sender = new SendToFusionTables(this, lastAuth, + sendTrackId, this/*progressIndicator*/, onCompletion); + + HandlerThread handlerThread = new HandlerThread("SendToFusionTables"); + handlerThread.start(); + Handler handler = new Handler(handlerThread.getLooper()); + handler.post(sender); + } + + private void onSendToFusionTablesDone() { + if (sendDialog.getSendToDocs()) { + authenticateToGoogleDocs(); + } else { + onSendToGoogleDone(); + } + } + + private void authenticateToGoogleDocs() { + setProgressValue(0); + setProgressMessage( + R.string.progress_message_authenticating_docs); + authenticate(new Intent(), + Constants.AUTHENTICATE_TO_DOCLIST, + SendToDocs.GDATA_SERVICE_NAME_DOCLIST); + // AUTHENTICATE_TO_DOCLIST callback calls authenticateToGoogleTrix + } + + private void authenticateToGoogleTrix() { + setProgressValue(30); + setProgressMessage( + R.string.progress_message_authenticating_docs); + authenticate(new Intent(), + Constants.AUTHENTICATE_TO_TRIX, + SendToDocs.GDATA_SERVICE_NAME_TRIX); + // AUTHENTICATE_TO_TRIX callback calls sendToGoogleDocs + } + + private void sendToGoogleDocs() { + Log.d(TAG, "Sending to Docs...."); + setProgressValue(50); + setProgressMessage(R.string.progress_message_sending_docs); + final SendToDocs sender = new SendToDocs(this, + authMap.get(SendToDocs.GDATA_SERVICE_NAME_TRIX), + authMap.get(SendToDocs.GDATA_SERVICE_NAME_DOCLIST), + this); + Runnable onCompletion = new Runnable() { + public void run() { + setProgressValue(100); + + // TODO: Use this message + sendToDocsMessage = sender.getStatusMessage(); + sendToDocsSuccess = sender.wasSuccess(); + + onSendToGoogleDocsDone(); + } + }; + sender.setOnCompletion(onCompletion); + sender.sendToDocs(sendTrackId); + } + + private void onSendToGoogleDocsDone() { + onSendToGoogleDone(); + } + + private void onSendToGoogleDone() { + final boolean sentToMyMaps = sendDialog.getSendToMyMaps(); + final boolean sentToFusionTables = sendDialog.getSendToFusionTables(); + List results = makeSendToGoogleResults(); + + runOnUiThread(new Runnable() { + @Override + public void run() { + progressDialog.dismiss(); + progressDialog = null; + sendDialog = null; + } + }); + + // We've finished sending the track to the user-selected services. Now + // we tell them the results of the upload, and optionally share the track. + // There are a few different paths through this code: + // + // 1. The user pre-requested a share (shareRequested == true). We're going + // to display the result dialog *without* the share button (the share + // listener will be null). The OK button listener will initiate the + // share. + // + // 2. The user did not pre-request a share, and the set of services to + // which we succeeded in uploading the track are compatible with + // sharing. We'll display a share button (the share listener will be + // non-null), and will share the link if the user clicks it. + // + // 3. The user did not pre-request a share, and the set of services to + // which we succeeded in uploading the track are incompatible with + // sharing. We won't display a share button. + + final boolean canShare = sendToFusionTablesTableId != null + || sendToMyMapsMapId != null; + + DialogInterface.OnClickListener doShareListener = null; + if (canShare) { + doShareListener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + shareLinkToMap(sentToMyMaps, sentToFusionTables); + } + }; + } + + DialogInterface.OnClickListener onOkListener = (canShare && shareRequested) + ? doShareListener : null; + DialogInterface.OnClickListener onShareListener = (canShare && !shareRequested) + ? doShareListener : null; + + AlertDialog sendToGoogleResultDialog = ResultDialogFactory.makeDialog(this, + results, onOkListener, onShareListener); + DialogManager.showDialogSafely(this, sendToGoogleResultDialog); + } + + boolean shareLinkToMap(boolean sentToMyMaps, boolean sentToFusionTables) { + String url = null; + if (sentToMyMaps && sendToMyMapsSuccess) { + // Prefer a link to My Maps + url = MapsFacade.buildMapUrl(sendToMyMapsMapId); + } else if (sentToFusionTables && sendToFusionTablesSuccess) { + // Otherwise try using the link to fusion tables + url = getFusionTablesUrl(sendTrackId); + } + + if (url != null) { + shareLinkToMap(url); + return true; + } + + return false; + } + + /** + * Shares a link to a My Map or Fusion Table via external app (email, gmail, ...) + * A chooser with apps that support text/plain will be shown to the user. + */ + private void shareLinkToMap(String url) { + boolean shareUrlOnly = sharedPreferences.getBoolean( + getString(R.string.share_url_only_key), false); + String msg = shareUrlOnly ? url : String.format( + getResources().getText(R.string.share_map_body_format).toString(), url); + + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType("text/plain"); + shareIntent.putExtra(Intent.EXTRA_SUBJECT, + getResources().getText(R.string.share_map_subject).toString()); + shareIntent.putExtra(Intent.EXTRA_TEXT, msg); + startActivity(Intent.createChooser(shareIntent, + getResources().getText(R.string.share_map).toString())); + } + + protected String getFusionTablesUrl(long trackId) { + Track track = providerUtils.getTrack(trackId); + return track == null ? "" : SendToFusionTables.getMapVisualizationUrl(track); + } + + /** + * Creates a list of {@link SendResult} instances based on the set of + * services selected in {@link SendDialog} and the results as known to + * this class. + */ + private List makeSendToGoogleResults() { + List results = new ArrayList(); + if (sendDialog.getSendToMyMaps()) { + results.add(new SendResult(SendType.MYMAPS, sendToMyMapsSuccess)); + } + if (sendDialog.getSendToFusionTables()) { + results.add(new SendResult(SendType.FUSION_TABLES, sendToFusionTablesSuccess)); + } + if (sendDialog.getSendToDocs()) { + results.add(new SendResult(SendType.DOCS, sendToDocsSuccess)); + } + + return results; + } + + /** + * Initializes the authentication manager which obtains an authentication + * token, prompting the user for a login and password if needed. + */ + private void authenticate(final Intent results, final int requestCode, + final String service) { + lastAuth = authMap.get(service); + if (lastAuth == null) { + Log.i(TAG, "Creating a new authentication for service: " + service); + lastAuth = AuthManagerFactory.getAuthManager(this, + Constants.GET_LOGIN, + null, + true, + service); + authMap.put(service, lastAuth); + } + + Log.d(TAG, "Logging in to " + service + "..."); + if (AuthManagerFactory.useModernAuthManager()) { + runOnUiThread(new Runnable() { + @Override + public void run() { + chooseAccount(results, requestCode, service); + } + }); + } else { + doLogin(results, requestCode, service, null); + } + } + + private void chooseAccount(final Intent results, final int requestCode, + final String service) { + accountChooser.chooseAccount(SendActivity.this, + new AccountChooser.AccountHandler() { + @Override + public void handleAccountSelected(Account account) { + if (account == null) { + progressDialog.dismiss(); + return; + } + + doLogin(results, requestCode, service, account); + } + }); + } + + private void doLogin(final Intent results, final int requestCode, + final String service, final Account account) { + lastAuth.doLogin(new Runnable() { + public void run() { + Log.i(TAG, "Loggin success for " + service + "!"); + onActivityResult(requestCode, RESULT_OK, results); + } + }, account); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, + final Intent results) { + switch (requestCode) { + case Constants.GET_LOGIN: { + // TODO: This is a result from inside the auth manager, + // make this return path explicit. + if (resultCode != RESULT_OK || lastAuth == null || + !lastAuth.authResult(resultCode, results)) { + progressDialog.dismiss(); + } + break; + } + case Constants.GET_MAP: { + // User picked a map to upload to + if (resultCode == RESULT_OK) { + results.putExtra("trackid", sendTrackId); + if (results.hasExtra("mapid")) { + sendToMyMapsMapId = results.getStringExtra("mapid"); + } + authenticateToGoogleMaps(results); + } else { + onSendToGoogleDone(); + } + break; + } + case Constants.AUTHENTICATE_TO_MY_MAPS: { + // Authenticated with Google My Maps + if (results != null && resultCode == RESULT_OK) { + final String mapId; + if (results.hasExtra("mapid")) { + mapId = results.getStringExtra("mapid"); + } else { + mapId = "new"; + } + + sendToGoogleMaps(mapId); + } else { + onSendToGoogleDone(); + } + break; + } + case Constants.AUTHENTICATE_TO_FUSION_TABLES: { + // Authenticated with Google Fusion Tables + if (results != null && resultCode == RESULT_OK) { + sendToFusionTables(); + } else { + onSendToGoogleDone(); + } + break; + } + case Constants.AUTHENTICATE_TO_DOCLIST: { + // Authenticated with Google Docs + if (resultCode == RESULT_OK) { + authenticateToGoogleTrix(); + } else { + onSendToGoogleDone(); + } + break; + } + case Constants.AUTHENTICATE_TO_TRIX: { + // Authenticated with Trix + if (resultCode == RESULT_OK) { + sendToGoogleDocs(); + } else { + onSendToGoogleDone(); + } + break; + } + case Constants.SHARE_LINK: { + Track selectedTrack = providerUtils.getTrack(sendTrackId); + if (selectedTrack != null) { + if (!TextUtils.isEmpty(selectedTrack.getMapId())) { + shareLinkToMap(MapsFacade.buildMapUrl(selectedTrack.getMapId())); + } else if (!TextUtils.isEmpty(selectedTrack.getTableId())) { + shareLinkToMap(getFusionTablesUrl(sendTrackId)); + } else { + shareRequested = true; + sendDialog.dismiss(); + } + } + break; + } + + default: { + Log.w(TAG, "Warning unhandled request code: " + requestCode); + } + } + } + + /** + * Resets status information for sending to MyMaps/Docs. + */ + private void resetState() { + sendToMyMapsMapId = null; + sendToMyMapsMessage = ""; + sendToMyMapsSuccess = true; + sendToFusionTablesMessage = ""; + sendToFusionTablesSuccess = true; + sendToDocsMessage = ""; + sendToDocsSuccess = true; + sendToFusionTablesTableId = null; + } + + @Override + public void setProgressMessage(final int resId) { + runOnUiThread(new Runnable() { + public void run() { + if (progressDialog != null) { + progressDialog.setMessage(getString(resId)); + } + } + }); + } + + @Override + public void setProgressValue(final int percent) { + runOnUiThread(new Runnable() { + public void run() { + if (progressDialog != null) { + progressDialog.setProgress(percent); + } + } + }); + } + + @Override + public void clearProgressMessage() { + progressDialog.setMessage(""); + } + + public static void sendToGoogle(Context ctx, long trackId, boolean shareLink) { + Intent intent = new Intent(ctx, SendActivity.class); + intent.putExtra(SendActivity.EXTRA_TRACK_ID, trackId); + intent.putExtra(SendActivity.EXTRA_SHARE_LINK, shareLink); + intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + ctx.startActivity(intent); + } +} diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendDialog.java b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendDialog.java index 16df9c5e3..868e25ed1 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendDialog.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendDialog.java @@ -16,8 +16,6 @@ package com.google.android.apps.mytracks.io.sendtogoogle; import com.google.android.apps.mytracks.Constants; -import com.google.android.apps.mytracks.DialogManager; -import com.google.android.apps.mytracks.MyTracks; import com.google.android.maps.mytracks.R; import android.app.Dialog; @@ -42,15 +40,13 @@ import android.widget.RadioGroup; */ public class SendDialog extends Dialog { - private RadioGroup groupMyMaps; private RadioButton createNewMapRadioButton; private RadioButton pickMapRadioButton; private CheckBox sendToMyMapsCheckBox; private CheckBox sendToFusionTablesCheckBox; private CheckBox sendToDocsCheckBox; - private RadioButton sendStatsRadioButton; private RadioButton sendStatsAndPointsRadioButton; - private Button sendButton; + private OnClickListener clickListener; public SendDialog(Context context) { super(context); @@ -62,18 +58,38 @@ public class SendDialog extends Dialog { requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.mytracks_send_to_google); + final Button sendButton = (Button) findViewById(R.id.sendtogoogle_send_now); + final RadioGroup groupMyMaps = (RadioGroup) findViewById(R.id.sendtogoogle_group_mymaps); + sendToMyMapsCheckBox = + (CheckBox) findViewById(R.id.sendtogoogle_google_mymaps); + sendToFusionTablesCheckBox = + (CheckBox) findViewById(R.id.sendtogoogle_google_fusiontables); + sendToDocsCheckBox = (CheckBox) findViewById(R.id.sendtogoogle_google_docs); + createNewMapRadioButton = + (RadioButton) findViewById(R.id.sendtogoogle_create_new_map); + pickMapRadioButton = + (RadioButton) findViewById(R.id.sendtogoogle_pick_existing_map); + RadioButton sendStatsRadioButton = (RadioButton) findViewById(R.id.sendtogoogle_send_stats); + sendStatsAndPointsRadioButton = (RadioButton) findViewById( + R.id.sendtogoogle_send_stats_and_points); + Button cancel = (Button) findViewById(R.id.sendtogoogle_cancel); cancel.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { - MyTracks.getInstance().dismissDialog(DialogManager.DIALOG_SEND_TO_GOOGLE); + if (clickListener != null) { + clickListener.onClick(SendDialog.this, BUTTON_NEGATIVE); + } + dismiss(); } }); Button send = (Button) findViewById(R.id.sendtogoogle_send_now); send.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { + if (clickListener != null) { + clickListener.onClick(SendDialog.this, BUTTON_POSITIVE); + } dismiss(); - MyTracks.getInstance().sendToGoogle(); } }); @@ -86,25 +102,9 @@ public class SendDialog extends Dialog { groupMyMaps.setVisibility(sendToMyMapsCheckBox.isChecked() ? View.VISIBLE : View.INVISIBLE); } }; - - sendButton = (Button) findViewById(R.id.sendtogoogle_send_now); - groupMyMaps = (RadioGroup) findViewById(R.id.sendtogoogle_group_mymaps); - sendToMyMapsCheckBox = - (CheckBox) findViewById(R.id.sendtogoogle_google_mymaps); sendToMyMapsCheckBox.setOnCheckedChangeListener(checkBoxListener); - sendToFusionTablesCheckBox = - (CheckBox) findViewById(R.id.sendtogoogle_google_fusiontables); sendToFusionTablesCheckBox.setOnCheckedChangeListener(checkBoxListener); - sendToDocsCheckBox = (CheckBox) findViewById(R.id.sendtogoogle_google_docs); sendToDocsCheckBox.setOnCheckedChangeListener(checkBoxListener); - createNewMapRadioButton = - (RadioButton) findViewById(R.id.sendtogoogle_create_new_map); - pickMapRadioButton = - (RadioButton) findViewById(R.id.sendtogoogle_pick_existing_map); - sendStatsRadioButton = - (RadioButton) findViewById(R.id.sendtogoogle_send_stats); - sendStatsAndPointsRadioButton = (RadioButton) findViewById( - R.id.sendtogoogle_send_stats_and_points); SharedPreferences prefs = getContext().getSharedPreferences(Constants.SETTINGS_NAME, 0); @@ -163,6 +163,10 @@ public class SendDialog extends Dialog { super.onStop(); } + public void setOnClickListener(OnClickListener clickListener) { + this.clickListener = clickListener; + } + public boolean getSendToMyMaps() { return sendToMyMapsCheckBox.isChecked(); } @@ -182,4 +186,4 @@ public class SendDialog extends Dialog { public boolean getSendStatsAndPoints() { return sendStatsAndPointsRadioButton.isChecked(); } -} +} \ No newline at end of file diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/DialogManagerTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/DialogManagerTest.java index 1b23a0315..5a50fc677 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/DialogManagerTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/DialogManagerTest.java @@ -38,13 +38,6 @@ public class DialogManagerTest assertNull(MyTracks.getInstance()); } - public void test_onCreateChartSettings() { - Dialog d = - getActivity().onCreateDialog(DialogManager.DIALOG_CHART_SETTINGS, null); - assertNotNull(d); - assertTrue(d instanceof ChartSettingsDialog); - } - public void test_onCreateImportProgress() { Dialog d = getActivity().onCreateDialog( @@ -62,11 +55,4 @@ public class DialogManagerTest assertEquals(100, pd.getMax()); assertEquals(10, pd.getProgress()); } - - public void test_onCreateSendToGoogle() { - Dialog d = - getActivity().onCreateDialog(DialogManager.DIALOG_SEND_TO_GOOGLE, null); - assertNotNull(d); - assertTrue(d instanceof SendDialog); - } } diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/WriteProgressControllerTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/WriteProgressControllerTest.java similarity index 92% rename from MyTracksTest/src/com/google/android/apps/mytracks/WriteProgressControllerTest.java rename to MyTracksTest/src/com/google/android/apps/mytracks/io/file/WriteProgressControllerTest.java index 2f4349b32..19d251281 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/WriteProgressControllerTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/WriteProgressControllerTest.java @@ -13,10 +13,11 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.google.android.apps.mytracks; +package com.google.android.apps.mytracks.io.file; -import com.google.android.apps.mytracks.io.file.MockTrackWriter; +import com.google.android.apps.mytracks.MyTracks; import com.google.android.apps.mytracks.io.file.TrackWriter; +import com.google.android.apps.mytracks.io.file.WriteProgressController; import android.app.ProgressDialog; import android.test.ActivityInstrumentationTestCase2; @@ -60,7 +61,7 @@ public class WriteProgressControllerTest extends ActivityInstrumentationTestCase getActivity(), mockWriter); controller.setOnCompletionListener(new WriteProgressController.OnCompletionListener() { @Override - public void onComplete(TrackWriter writer) { + public void onComplete() { controllerDoneRef.set(true); } });