diff --git a/MyTracks/AndroidManifest.xml b/MyTracks/AndroidManifest.xml index cb928bac6..6b9aa585a 100755 --- a/MyTracks/AndroidManifest.xml +++ b/MyTracks/AndroidManifest.xml @@ -165,7 +165,6 @@ limitations under the License. android:name="android.app.default_searchable" android:value="com.google.android.apps.mytracks.SearchListActivity" /> - @@ -206,7 +205,6 @@ limitations under the License. - diff --git a/MyTracks/res/drawable-hdpi/menu_split_frequency.png b/MyTracks/res/drawable-hdpi/menu_split_frequency.png new file mode 100644 index 000000000..bdf97e2a5 Binary files /dev/null and b/MyTracks/res/drawable-hdpi/menu_split_frequency.png differ diff --git a/MyTracks/res/drawable-hdpi/menu_voice_frequency.png b/MyTracks/res/drawable-hdpi/menu_voice_frequency.png new file mode 100644 index 000000000..7b69ea56b Binary files /dev/null and b/MyTracks/res/drawable-hdpi/menu_voice_frequency.png differ diff --git a/MyTracks/res/drawable-mdpi/menu_split_frequency.png b/MyTracks/res/drawable-mdpi/menu_split_frequency.png new file mode 100644 index 000000000..2bd0c919e Binary files /dev/null and b/MyTracks/res/drawable-mdpi/menu_split_frequency.png differ diff --git a/MyTracks/res/drawable-mdpi/menu_voice_frequency.png b/MyTracks/res/drawable-mdpi/menu_voice_frequency.png new file mode 100644 index 000000000..f8dd8469c Binary files /dev/null and b/MyTracks/res/drawable-mdpi/menu_voice_frequency.png differ diff --git a/MyTracks/res/drawable-xhdpi/menu_split_frequency.png b/MyTracks/res/drawable-xhdpi/menu_split_frequency.png new file mode 100644 index 000000000..982df112d Binary files /dev/null and b/MyTracks/res/drawable-xhdpi/menu_split_frequency.png differ diff --git a/MyTracks/res/drawable-xhdpi/menu_voice_frequency.png b/MyTracks/res/drawable-xhdpi/menu_voice_frequency.png new file mode 100644 index 000000000..dfd2b33c7 Binary files /dev/null and b/MyTracks/res/drawable-xhdpi/menu_voice_frequency.png differ diff --git a/MyTracks/res/layout/choose_activity_list_item.xml b/MyTracks/res/layout/choose_activity_list_item.xml new file mode 100644 index 000000000..86bff7de9 --- /dev/null +++ b/MyTracks/res/layout/choose_activity_list_item.xml @@ -0,0 +1,51 @@ + + + + + + + + + \ No newline at end of file diff --git a/MyTracks/res/layout/upload_service_chooser.xml b/MyTracks/res/layout/choose_upload_service.xml similarity index 70% rename from MyTracks/res/layout/upload_service_chooser.xml rename to MyTracks/res/layout/choose_upload_service.xml index 189ed9921..3b24cf482 100644 --- a/MyTracks/res/layout/upload_service_chooser.xml +++ b/MyTracks/res/layout/choose_upload_service.xml @@ -21,51 +21,51 @@ limitations under the License. android:layout_width="fill_parent" android:padding="8dp" android:stretchColumns="1" > - + + style="@style/ChooseUploadServiceImageView" /> + style="@style/ChooseUploadServiceCheckBox" /> - + - + + style="@style/ChooseUploadServiceImageView" /> + style="@style/ChooseUploadServiceCheckBox" /> - + + style="@style/ChooseUploadServiceImageView" /> + style="@style/ChooseUploadServiceCheckBox" /> \ No newline at end of file diff --git a/MyTracks/res/layout/help.xml b/MyTracks/res/layout/help.xml index d34e5020d..4324c9a41 100644 --- a/MyTracks/res/layout/help.xml +++ b/MyTracks/res/layout/help.xml @@ -91,16 +91,16 @@ limitations under the License. android:text="@string/help_saved_files_answer" style="@style/HelpAnswer" /> - + \ No newline at end of file diff --git a/MyTracks/res/menu/track_detail.xml b/MyTracks/res/menu/track_detail.xml index ccc42927c..8bcc9f781 100644 --- a/MyTracks/res/menu/track_detail.xml +++ b/MyTracks/res/menu/track_detail.xml @@ -39,18 +39,6 @@ limitations under the License. android:orderInCategory="4" android:showAsAction="ifRoom" android:title="@string/menu_share"> - - - - - - - - + + @@ -79,26 +77,26 @@ limitations under the License. \ No newline at end of file diff --git a/MyTracks/res/values/arrays_do_not_translate.xml b/MyTracks/res/values/arrays_do_not_translate.xml index fb5aeb571..4ca399897 100644 --- a/MyTracks/res/values/arrays_do_not_translate.xml +++ b/MyTracks/res/values/arrays_do_not_translate.xml @@ -96,6 +96,22 @@ limitations under the License. CSV TCX + + 0 + 1 + 2 + 5 + 10 + 15 + 30 + 60 + -1 + -5 + -10 + -25 + -50 + -100 + 50 100 @@ -142,22 +158,6 @@ limitations under the License. 2000 5000 - - 0 - 1 - 2 - 5 - 10 - 15 - 30 - 60 - -1 - -5 - -10 - -25 - -50 - -100 - @string/settings_sensor_type_none @string/settings_sensor_type_ant diff --git a/MyTracks/res/values/keys.xml b/MyTracks/res/values/keys.xml index 3e46e54e0..64e356e48 100644 --- a/MyTracks/res/values/keys.xml +++ b/MyTracks/res/values/keys.xml @@ -39,7 +39,6 @@ limitations under the License. minRecordingInterval minRequiredAccuracy pickExistingMap - preferredAccount recordingTrackId reportSpeed selectedTrackId @@ -47,7 +46,7 @@ limitations under the License. sendToFusionTables sendToMaps sensorType - shareUrlOnly + sharingAccount showCheckUnitsDialog showWelcomeDialog splitFrequency diff --git a/MyTracks/res/values/strings.xml b/MyTracks/res/values/strings.xml index 312f6acfd..e1d885e3e 100644 --- a/MyTracks/res/values/strings.xml +++ b/MyTracks/res/values/strings.xml @@ -377,8 +377,8 @@ limitations under the License. Use My Tracks while you run, bike, hike, or do anything else outdoors, and it will use the GPS sensor in your phone to record the path you took. It will also gather useful statistics such as time, speed, distance, and elevation. You can review all of this data live, or you can save it - for use later. While you\'re out, you can mark relevant waypoints, and can ask to hear automatic - voice announcements about your progress.\n + for use later. While you\'re out, you can insert markers, have split markers inserted + automatically, and can ask to hear periodic voice announcements of your progress.\n \n My Tracks can record data from external sensors:\n - Zephyr Technology Consumer HxM Bluetooth heart rate monitor\n @@ -630,6 +630,12 @@ limitations under the License. translation_description="The text label for entering a description."> Description + + Description: %1$s + Error @@ -638,6 +644,12 @@ limitations under the License. translation_description="The text label for entering a name."> Name + + Name: %1$s + OK @@ -654,7 +666,7 @@ limitations under the License. translation_description="The title on an alert dialog indicating success."> Success - + How precise are the recorded tracks? + + Markers are used to annotate a location. + + + What are markers? + My Tracks allows you to record GPS tracks and visualize your hiking, running, biking or any @@ -793,6 +813,15 @@ limitations under the License. translation_description="In the 'Help' page, the question on share visibility."> Who can see the tracks I send to Google Maps and Google Fusion Tables? + + The split markers are used to segment a track to calculate statistics for each segment. Split + markers are inserted by setting the split frequency in the menu. + + + What are split markers? + Tracks on Google Maps and Google Fusion Tables are limited to certain sizes. @@ -802,26 +831,14 @@ limitations under the License. Why do very long tracks split into multiple segments upon sending them to Google Maps and Google Fusion Tables? - - Statistics markers are used to segment a track to calculate statistics for each segment. For - example, let\'s say you are recording a bike ride up a hill, you can insert a statistics marker - at the bottom of the hill and another at the top. - - - What are statistics markers? - - - Waypoint markers are used to annotate a location. - - - What are waypoint markers? - + + Application + Marker @@ -839,14 +856,7 @@ limitations under the License. Track - - - Import error for file %1$s. - + 0 GPX files - - No GPX file found in %1$s. The SD card may be unreadable or the directory may not contain any - GPX file. - - - Importing all tracks... - - - My Tracks: Imported %1$d of %2$s from %3$s. - The marker will be permanently deleted from the phone. - - Name: %1$s - - - Description: %1$s - Marker type: %1$s - + - Since last Statistics marker: - + indicating that the data below are since the last split marker."> + Since last split marker: + + examples."> Marker type (e.g. building, pothole...) Marker type - + You don\'t have any markers. - - Statistics %1$d - Marker %1$d - + + Split %1$d + + @@ -1098,32 +1074,24 @@ limitations under the License. translation_description="In the menu, to share a track."> Share - - %1$s file - - - Fusion Table URL - - - Map URL - + translation_description="In the menu, to show a track or a marker on the map."> Show on map + + Split frequency + Stop recording + + Voice frequency + - - - Unable to save. - - - Saving all tracks... - - - Save finished. - - + translation_description="When importing/saving to the SD card, the message indicating that the + operation was canceled."> The operation was canceled. - - Unable to create a directory on the SD card. - - No external storage was found. Make sure that a SD card is inserted and that your phone is not - mounted to a computer. + translation_description="When importing/saving to the SD card, the error message indicating that + no SD card is found."> + No SD card is found. - - Unable to read from a file. + + Unable to import from SD card. - - Unable to write to a file. + + No file found in %1$s. + + + Importing from SD card... - - Saving to the SD card... + + Finished importing from SD card. - - Finished reading from the SD card. + + Imported %1$d of %2$s from %3$s. - - Finished writing to the SD card. + + Unable to save to SD card. + + Unable to create a directory on SD card. + + + You have no track to save to SD card. + + + Saving to SD card... + + + Finished saving to SD card. + Sending to %1$s... - - Share track URL - @@ -1500,13 +1469,13 @@ limitations under the License. translation_description="In the 'Chart' settings, the option to display the x axis by distance."> By distance - + By time X axis @@ -1573,7 +1542,7 @@ limitations under the License. track recording."> Not available while recording a track. - + Smallest time interval between two recordings of your position. - - Marker - - - Time/distance after which a new marker will be inserted. - Default track name - - Voice - - - Time/distance between two voice announcements. - - Revert all your settings to the default values. - + Unpair SRM ANT+ bridge - + Sharing + + Switch account + + + Switch account used when sending a track to Google. + Make new maps created in Google Maps public. - - Share only URL - - - Include descriptive text when sharing a URL with friends. - - - Remove any descriptive text when sharing a URL with friends. + + + Time/distance between two split markers @@ -1986,7 +1924,7 @@ limitations under the License. Time measurement Imperial (mi, ft) @@ -1994,34 +1932,53 @@ limitations under the License. translation_description="In the 'Stats' settings, the option to use metric units, with examples."> Metric (km, m) - + Preferred units - - - I think you might be interested in this track.\n\nTo view this track use Google Earth or other - mapping software. + + + Time/distance between two voice announcements + + - Share track using: + translation_description="When sharing a track with friends, the title on the picker to ask + the user to select an application."> + Select an application + + + Share track file + + + I think you might be interested in this track.\n\nTo view this track, use Google Earth or other + mapping software.\n\n%1$s + + + Share track URL + + + I think you might be interested in this track:\n\n%1$s\n\n%2$s I would like to share a track with you - - I think you might be interested in this track:\n\n%1$s - Stats - + Recording... - + @@ -2361,10 +2318,10 @@ limitations under the License. - %1$d %% - + %1$d %% + %1$s \u00B0 - + Use My Tracks while you run, bike, hike, or do anything outdoor to record your path. While - recording, you can visualize your track and watch live statistics. You can also add - markers, have markers inserted periodically, or hear automatic voice announcements of - your progress. For recorded tracks, you can play them on Google Earth, share with friends, or - upload to Google Maps, Google Fusion Tables, or Google Docs. + recording, you can visualize your track and watch live statistics. You can also add markers, + have split markers inserted periodically, or hear periodic announcements of your progress. + For recorded tracks, you can play them on Google Earth, share with friends, or upload to Google + Maps, Google Fusion Tables, or Google Docs. diff --git a/MyTracks/res/values/styles.xml b/MyTracks/res/values/styles.xml index abf407a1b..cd6dae0d8 100644 --- a/MyTracks/res/values/styles.xml +++ b/MyTracks/res/values/styles.xml @@ -31,6 +31,17 @@ limitations under the License. fill_parent horizontal + + + + - - - - \ No newline at end of file diff --git a/MyTracks/res/xml/recording_settings.xml b/MyTracks/res/xml/recording_settings.xml index b79455ec4..fe3f5cff3 100644 --- a/MyTracks/res/xml/recording_settings.xml +++ b/MyTracks/res/xml/recording_settings.xml @@ -16,18 +16,6 @@ limitations under the License. --> - - + - { - - private SaveAllActivity saveAllActivity; - 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 saveAllActivity the activity currently associated with this AsyncTask - * @param trackFileFormat the track file format - */ - public SaveAllAsyncTask(SaveAllActivity saveAllActivity, TrackFileFormat trackFileFormat) { - this.saveAllActivity = saveAllActivity; - this.trackFileFormat = trackFileFormat; - context = saveAllActivity.getApplicationContext(); - myTracksProviderUtils = MyTracksProviderUtils.Factory.get(saveAllActivity); - - // Get the wake lock if not recording - if (PreferencesUtils.getLong(saveAllActivity, R.string.recording_track_id_key) - == PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) { - wakeLock = SystemUtils.acquireWakeLock(saveAllActivity, wakeLock); - } - success = false; - completed = false; - messageId = R.string.save_all_error; - } - - /** - * Sets the current {@link SaveAllActivity} associated with this AyncTask. - * - * @param saveAllActivity the current {@link SaveAllActivity}, can be null - */ - public void setActivity(SaveAllActivity saveAllActivity) { - this.saveAllActivity = saveAllActivity; - if (completed && saveAllActivity != null) { - saveAllActivity.onAsyncTaskCompleted(success, messageId); - } - } - - @Override - protected void onPreExecute() { - if (saveAllActivity != null) { - saveAllActivity.showProgressDialog(); - } - } - - @Override - protected Boolean doInBackground(Void... params) { - Cursor cursor = null; - try { - cursor = myTracksProviderUtils.getTracksCursor(null, null, TracksColumns._ID); - if (cursor == null) { - messageId = R.string.save_all_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.save_all_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 (saveAllActivity != null) { - saveAllActivity.setProgressDialogValue(values[0], values[1]); - } - } - - @Override - protected void onPostExecute(Boolean result) { - success = result; - completed = true; - if (saveAllActivity != null) { - saveAllActivity.onAsyncTaskCompleted(success, messageId); - } - } - - @Override - protected void onCancelled() { - if (trackWriter != null) { - trackWriter.stopWriteTrack(); - } - } -} diff --git a/MyTracks/src/com/google/android/apps/mytracks/SearchListActivity.java b/MyTracks/src/com/google/android/apps/mytracks/SearchListActivity.java index 7a0ebed17..4863c3195 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/SearchListActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/SearchListActivity.java @@ -187,8 +187,8 @@ public class SearchListActivity extends AbstractMyTracksActivity implements Dele } }; listView.setAdapter(arrayAdapter); - ApiAdapterFactory.getApiAdapter().configureListViewContextualMenu(this, listView, - R.menu.list_context_menu, R.id.list_item_name, contextualActionModeCallback); + ApiAdapterFactory.getApiAdapter() + .configureListViewContextualMenu(this, listView, contextualActionModeCallback); handleIntent(getIntent()); } diff --git a/MyTracks/src/com/google/android/apps/mytracks/SensorStateActivity.java b/MyTracks/src/com/google/android/apps/mytracks/SensorStateActivity.java index 001b8150e..339f81180 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/SensorStateActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/SensorStateActivity.java @@ -233,8 +233,7 @@ public class SensorStateActivity extends AbstractMyTracksActivity { String value; if (sensorDataSet.hasPower() && sensorDataSet.getPower().hasValue() && sensorDataSet.getPower().getState() == Sensor.SensorState.SENDING) { - String format = getString(R.string.sensor_state_power_value); - value = String.format(format, sensorDataSet.getPower().getValue()); + value = getString(R.string.sensor_state_power_value, sensorDataSet.getPower().getValue()); } else { value = SensorUtils.getStateAsString( sensorDataSet.hasPower() ? sensorDataSet.getPower().getState() : Sensor.SensorState.NONE, @@ -252,8 +251,7 @@ public class SensorStateActivity extends AbstractMyTracksActivity { String value; if (sensorDataSet.hasCadence() && sensorDataSet.getCadence().hasValue() && sensorDataSet.getCadence().getState() == Sensor.SensorState.SENDING) { - String format = getString(R.string.sensor_state_cadence_value); - value = String.format(format, sensorDataSet.getCadence().getValue()); + value = getString(R.string.sensor_state_cadence_value, sensorDataSet.getCadence().getValue()); } else { value = SensorUtils.getStateAsString( sensorDataSet.hasCadence() ? sensorDataSet.getCadence().getState() @@ -271,8 +269,8 @@ public class SensorStateActivity extends AbstractMyTracksActivity { String value; if (sensorDataSet.hasHeartRate() && sensorDataSet.getHeartRate().hasValue() && sensorDataSet.getHeartRate().getState() == Sensor.SensorState.SENDING) { - String format = getString(R.string.sensor_state_heart_rate_value); - value = String.format(format, sensorDataSet.getHeartRate().getValue()); + value = getString( + R.string.sensor_state_heart_rate_value, sensorDataSet.getHeartRate().getValue()); } else { value = SensorUtils.getStateAsString( sensorDataSet.hasHeartRate() ? sensorDataSet.getHeartRate().getState() diff --git a/MyTracks/src/com/google/android/apps/mytracks/TrackDetailActivity.java b/MyTracks/src/com/google/android/apps/mytracks/TrackDetailActivity.java index e630547c7..3cfb8963c 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/TrackDetailActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/TrackDetailActivity.java @@ -22,15 +22,17 @@ import com.google.android.apps.mytracks.content.TrackDataHub; import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.content.WaypointCreationRequest; import com.google.android.apps.mytracks.fragments.ChartFragment; +import com.google.android.apps.mytracks.fragments.ChooseActivityDialogFragment; +import com.google.android.apps.mytracks.fragments.ChooseUploadServiceDialogFragment; import com.google.android.apps.mytracks.fragments.DeleteOneTrackDialogFragment; import com.google.android.apps.mytracks.fragments.DeleteOneTrackDialogFragment.DeleteOneTrackCaller; +import com.google.android.apps.mytracks.fragments.FrequencyDialogFragment; import com.google.android.apps.mytracks.fragments.InstallEarthDialogFragment; import com.google.android.apps.mytracks.fragments.MapFragment; import com.google.android.apps.mytracks.fragments.StatsFragment; import com.google.android.apps.mytracks.io.file.SaveActivity; import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat; import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest; -import com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity; import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection; import com.google.android.apps.mytracks.settings.SettingsActivity; import com.google.android.apps.mytracks.util.AnalyticsUtils; @@ -83,6 +85,8 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del private MenuItem insertMarkerMenuItem; private MenuItem playMenuItem; private MenuItem shareMenuItem; + private MenuItem voiceFrequencyMenuItem; + private MenuItem splitFrequencyMenuItem; private MenuItem sendGoogleMenuItem; private MenuItem saveMenuItem; @@ -209,19 +213,12 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del menu.findItem(R.id.track_detail_save_tcx) .setTitle(getString(R.string.menu_save_format, fileTypes[3])); - menu.findItem(R.id.track_detail_share_gpx) - .setTitle(getString(R.string.menu_share_file, fileTypes[0])); - menu.findItem(R.id.track_detail_share_kml) - .setTitle(getString(R.string.menu_share_file, fileTypes[1])); - menu.findItem(R.id.track_detail_share_csv) - .setTitle(getString(R.string.menu_share_file, fileTypes[2])); - menu.findItem(R.id.track_detail_share_tcx) - .setTitle(getString(R.string.menu_share_file, fileTypes[3])); - stopRecordingMenuItem = menu.findItem(R.id.track_detail_stop_recording); insertMarkerMenuItem = menu.findItem(R.id.track_detail_insert_marker); playMenuItem = menu.findItem(R.id.track_detail_play); shareMenuItem = menu.findItem(R.id.track_detail_share); + voiceFrequencyMenuItem = menu.findItem(R.id.track_detail_voice_frequency); + splitFrequencyMenuItem = menu.findItem(R.id.track_detail_split_frequency); sendGoogleMenuItem = menu.findItem(R.id.track_detail_send_google); saveMenuItem = menu.findItem(R.id.track_detail_save); @@ -271,49 +268,42 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del getSupportFragmentManager(), InstallEarthDialogFragment.INSTALL_EARTH_DIALOG_TAG); } return true; - case R.id.track_detail_share_map_url: - intent = IntentUtils.newIntent(this, UploadServiceChooserActivity.class) - .putExtra(SendRequest.SEND_REQUEST_KEY, new SendRequest(trackId, true, false, false)); - startActivity(intent); - return true; - case R.id.track_detail_share_fusion_table_url: - intent = IntentUtils.newIntent(this, UploadServiceChooserActivity.class) - .putExtra(SendRequest.SEND_REQUEST_KEY, new SendRequest(trackId, false, true, false)); - startActivity(intent); - return true; - case R.id.track_detail_share_gpx: - startSaveActivity(TrackFileFormat.GPX, true); - return true; - case R.id.track_detail_share_kml: - startSaveActivity(TrackFileFormat.KML, true); - return true; - case R.id.track_detail_share_csv: - startSaveActivity(TrackFileFormat.CSV, true); - return true; - case R.id.track_detail_share_tcx: - startSaveActivity(TrackFileFormat.TCX, true); + case R.id.track_detail_share: + ChooseActivityDialogFragment.newInstance(trackId, null).show( + getSupportFragmentManager(), ChooseActivityDialogFragment.CHOOSE_ACTIVITY_DIALOG_TAG); return true; case R.id.track_detail_markers: intent = IntentUtils.newIntent(this, MarkerListActivity.class) .putExtra(MarkerListActivity.EXTRA_TRACK_ID, trackId); startActivity(intent); return true; + case R.id.track_detail_voice_frequency: + FrequencyDialogFragment.newInstance(R.string.announcement_frequency_key, + PreferencesUtils.ANNOUNCEMENT_FREQUENCY_DEFAULT, + R.string.settings_voice_frequency_title) + .show(getSupportFragmentManager(), FrequencyDialogFragment.FREQUENCY_DIALOG_TAG); + return true; + case R.id.track_detail_split_frequency: + FrequencyDialogFragment.newInstance(R.string.split_frequency_key, + PreferencesUtils.SPLIT_FREQUENCY_DEFAULT, R.string.settings_split_frequency_title) + .show(getSupportFragmentManager(), FrequencyDialogFragment.FREQUENCY_DIALOG_TAG); + return true; case R.id.track_detail_send_google: - intent = IntentUtils.newIntent(this, UploadServiceChooserActivity.class) - .putExtra(SendRequest.SEND_REQUEST_KEY, new SendRequest(trackId, true, true, true)); - startActivity(intent); + ChooseUploadServiceDialogFragment.newInstance(new SendRequest(trackId)).show( + getSupportFragmentManager(), + ChooseUploadServiceDialogFragment.CHOOSE_UPLOAD_SERVICE_DIALOG_TAG); return true; case R.id.track_detail_save_gpx: - startSaveActivity(TrackFileFormat.GPX, false); + startSaveActivity(TrackFileFormat.GPX); return true; case R.id.track_detail_save_kml: - startSaveActivity(TrackFileFormat.KML, false); + startSaveActivity(TrackFileFormat.KML); return true; case R.id.track_detail_save_csv: - startSaveActivity(TrackFileFormat.CSV, false); + startSaveActivity(TrackFileFormat.CSV); return true; case R.id.track_detail_save_tcx: - startSaveActivity(TrackFileFormat.TCX, false); + startSaveActivity(TrackFileFormat.TCX); return true; case R.id.track_detail_edit: intent = IntentUtils.newIntent(this, TrackEditActivity.class) @@ -446,6 +436,12 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del if (shareMenuItem != null) { shareMenuItem.setVisible(!isRecording); } + if (voiceFrequencyMenuItem != null) { + voiceFrequencyMenuItem.setVisible(isRecording); + } + if (splitFrequencyMenuItem != null) { + splitFrequencyMenuItem.setVisible(isRecording); + } if (sendGoogleMenuItem != null) { sendGoogleMenuItem.setVisible(!isRecording); } @@ -458,13 +454,11 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del * Starts the {@link SaveActivity} to save a track. * * @param trackFileFormat the track file format - * @param shareTrack true to share the track after saving */ - private void startSaveActivity(TrackFileFormat trackFileFormat, boolean shareTrack) { + private void startSaveActivity(TrackFileFormat trackFileFormat) { Intent intent = IntentUtils.newIntent(this, SaveActivity.class) .putExtra(SaveActivity.EXTRA_TRACK_ID, trackId) - .putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) trackFileFormat) - .putExtra(SaveActivity.EXTRA_SHARE_TRACK, shareTrack); + .putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) trackFileFormat); startActivity(intent); } diff --git a/MyTracks/src/com/google/android/apps/mytracks/TrackEditActivity.java b/MyTracks/src/com/google/android/apps/mytracks/TrackEditActivity.java index 6e7b7a5f2..41e36c943 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/TrackEditActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/TrackEditActivity.java @@ -64,7 +64,7 @@ public class TrackEditActivity extends AbstractMyTracksActivity { myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this); track = myTracksProviderUtils.getTrack(trackId); if (track == null) { - Log.e(TAG, "no track"); + Log.e(TAG, "No track for " + trackId); finish(); return; } diff --git a/MyTracks/src/com/google/android/apps/mytracks/TrackListActivity.java b/MyTracks/src/com/google/android/apps/mytracks/TrackListActivity.java index ea4352cb0..e38657f64 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/TrackListActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/TrackListActivity.java @@ -23,6 +23,7 @@ import com.google.android.apps.mytracks.fragments.DeleteOneTrackDialogFragment; import com.google.android.apps.mytracks.fragments.DeleteOneTrackDialogFragment.DeleteOneTrackCaller; import com.google.android.apps.mytracks.fragments.EulaDialogFragment; import com.google.android.apps.mytracks.fragments.WelcomeDialogFragment; +import com.google.android.apps.mytracks.io.file.SaveActivity; import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat; import com.google.android.apps.mytracks.services.ITrackRecordingService; import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection; @@ -240,9 +241,8 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac } }; listView.setAdapter(resourceCursorAdapter); - ApiAdapterFactory.getApiAdapter().configureListViewContextualMenu( - this, listView, R.menu.list_context_menu, R.id.list_item_name, - contextualActionModeCallback); + ApiAdapterFactory.getApiAdapter() + .configureListViewContextualMenu(this, listView, contextualActionModeCallback); getSupportLoaderManager().initLoader(0, null, new LoaderCallbacks() { @Override @@ -399,24 +399,16 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac startActivity(intent); return true; case R.id.track_list_save_all_gpx: - intent = IntentUtils.newIntent(this, SaveAllActivity.class) - .putExtra(SaveAllActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.GPX); - startActivity(intent); + startSaveActivity(TrackFileFormat.GPX); return true; case R.id.track_list_save_all_kml: - intent = IntentUtils.newIntent(this, SaveAllActivity.class) - .putExtra(SaveAllActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.KML); - startActivity(intent); + startSaveActivity(TrackFileFormat.KML); return true; case R.id.track_list_save_all_csv: - intent = IntentUtils.newIntent(this, SaveAllActivity.class) - .putExtra(SaveAllActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.CSV); - startActivity(intent); + startSaveActivity(TrackFileFormat.CSV); return true; case R.id.track_list_save_all_tcx: - intent = IntentUtils.newIntent(this, SaveAllActivity.class) - .putExtra(SaveAllActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.TCX); - startActivity(intent); + startSaveActivity(TrackFileFormat.TCX); return true; case R.id.track_list_delete_all: new DeleteAllTrackDialogFragment().show( @@ -439,6 +431,17 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac } } + /** + * Starts the {@link SaveActivity} to save all tracks. + * + * @param trackFileFormat the track file format + */ + private void startSaveActivity(TrackFileFormat trackFileFormat) { + Intent intent = IntentUtils.newIntent(this, SaveActivity.class) + .putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) trackFileFormat); + startActivity(intent); + } + @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); diff --git a/MyTracks/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImpl.java b/MyTracks/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImpl.java index 86ef70e25..0263800d1 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImpl.java +++ b/MyTracks/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImpl.java @@ -36,7 +36,9 @@ import java.util.Vector; public class DescriptionGeneratorImpl implements DescriptionGenerator { private static final String HTML_LINE_BREAK = "
"; + private static final String HTML_PARAGRAPH_SEPARATOR = "

"; private static final String TEXT_LINE_BREAK = "\n"; + private static final String TEXT_PARAGRAPH_SEPARATOR = "\n\n"; private Context context; @@ -46,26 +48,26 @@ public class DescriptionGeneratorImpl implements DescriptionGenerator { @Override public String generateTrackDescription( - Track track, Vector distances, Vector elevations) { + Track track, Vector distances, Vector elevations, boolean html) { + String paragraphSeparator = html ? HTML_PARAGRAPH_SEPARATOR : TEXT_PARAGRAPH_SEPARATOR; + String lineBreak = html ? HTML_LINE_BREAK : TEXT_LINE_BREAK; StringBuilder builder = new StringBuilder(); // Created by - String url = context.getString(R.string.my_tracks_web_url); - builder.append(context.getString( - R.string.send_google_by_my_tracks, "", "")); - builder.append("

"); + String beginAnchor = html + ? "" + : ""; + String endAnchor = html ? "" : ""; + builder.append(context.getString(R.string.send_google_by_my_tracks, beginAnchor, endAnchor)); + builder.append(paragraphSeparator); - builder.append(generateTripStatisticsDescription(track.getStatistics(), true)); - - // Activity type - String trackCategory = track.getCategory(); - String category = trackCategory != null && trackCategory.length() > 0 ? trackCategory - : context.getString(R.string.value_unknown); - builder.append(context.getString(R.string.description_activity_type, category)); - builder.append(HTML_LINE_BREAK); + writeString(track.getName(), builder, R.string.generic_name_line, lineBreak); + writeString(track.getCategory(), builder, R.string.description_activity_type, lineBreak); + writeString(track.getDescription(), builder, R.string.generic_description_line, lineBreak); + builder.append(generateTripStatisticsDescription(track.getStatistics(), html)); // Elevation chart - if (distances != null && elevations != null) { + if (html && distances != null && elevations != null) { builder.append(""); builder.append(HTML_LINE_BREAK); @@ -78,6 +80,22 @@ public class DescriptionGeneratorImpl implements DescriptionGenerator { return generateTripStatisticsDescription(waypoint.getStatistics(), false); } + /** + * Writes a string to a string builder. + * + * @param text the string + * @param builder the string builder + * @param resId the resource id containing one string placeholder + * @param lineBreak the line break + */ + private void writeString(String text, StringBuilder builder, int resId, String lineBreak) { + if (text == null || text.length() == 0) { + text = context.getString(R.string.value_unknown); + } + builder.append(context.getString(resId, text)); + builder.append(lineBreak); + } + /** * Generates a description for a {@link TripStatistics}. * diff --git a/MyTracks/src/com/google/android/apps/mytracks/fragments/ChartFragment.java b/MyTracks/src/com/google/android/apps/mytracks/fragments/ChartFragment.java index 2424a37ce..9a7f87b8d 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/fragments/ChartFragment.java +++ b/MyTracks/src/com/google/android/apps/mytracks/fragments/ChartFragment.java @@ -132,11 +132,11 @@ public class ChartFragment extends Fragment implements TrackDataListener { return view; } + @SuppressWarnings("deprecation") @Override public void onStart() { super.onStart(); ViewGroup layout = (ViewGroup) getActivity().findViewById(R.id.chart_view_layout); - @SuppressWarnings("deprecation") LayoutParams layoutParams = new LayoutParams( LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); layout.addView(chartView, layoutParams); diff --git a/MyTracks/src/com/google/android/apps/mytracks/fragments/ChooseActivityDialogFragment.java b/MyTracks/src/com/google/android/apps/mytracks/fragments/ChooseActivityDialogFragment.java new file mode 100644 index 000000000..0224ea61c --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/fragments/ChooseActivityDialogFragment.java @@ -0,0 +1,260 @@ +/* + * 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.fragments; + +import com.google.android.apps.mytracks.io.sendtogoogle.AccountChooserActivity; +import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest; +import com.google.android.apps.mytracks.util.IntentUtils; +import com.google.android.maps.mytracks.R; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.ShareCompat; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; + +/** + * A DialogFragment to choose an activity. + * + * @author Jimmy Shih + */ +public class ChooseActivityDialogFragment extends DialogFragment { + + public static final String CHOOSE_ACTIVITY_DIALOG_TAG = "chooseActivityDialog"; + + private static final String KEY_TRACK_ID = "trackId"; + private static final String KEY_TRACK_URL = "trackUrl"; + + private PackageManager packageManager; + + public static ChooseActivityDialogFragment newInstance(long trackId, String trackUrl) { + Bundle bundle = new Bundle(); + bundle.putLong(KEY_TRACK_ID, trackId); + bundle.putString(KEY_TRACK_URL, trackUrl); + + ChooseActivityDialogFragment chooseActivityDialogFragment = new ChooseActivityDialogFragment(); + chooseActivityDialogFragment.setArguments(bundle); + return chooseActivityDialogFragment; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + packageManager = getActivity().getPackageManager(); + List displayInfos = getDisplayInfos(); + + ArrayAdapter arrayAdapter = new ArrayAdapter(getActivity(), + R.layout.choose_activity_list_item, R.id.choose_activity_list_item_text1, displayInfos) { + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view; + if (convertView == null) { + view = getActivity() + .getLayoutInflater().inflate(R.layout.choose_activity_list_item, parent, false); + } else { + view = convertView; + } + DisplayInfo displayInfo = getItem(position); + TextView text1 = (TextView) view.findViewById(R.id.choose_activity_list_item_text1); + TextView text2 = (TextView) view.findViewById(R.id.choose_activity_list_item_text2); + ImageView icon = (ImageView) view.findViewById(R.id.choose_activity_list_item_icon); + text1.setText(displayInfo.primaryLabel); + if (displayInfo.secondaryLabel != null) { + text2.setVisibility(View.VISIBLE); + text2.setText(displayInfo.secondaryLabel); + } else { + text2.setVisibility(View.GONE); + } + icon.setImageDrawable(displayInfo.icon); + return view; + } + }; + return new AlertDialog.Builder(getActivity()) + .setSingleChoiceItems(arrayAdapter, 0, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + AlertDialog alertDialog = (AlertDialog) dialog; + DisplayInfo displayInfo = (DisplayInfo) alertDialog.getListView() + .getItemAtPosition(which); + ActivityInfo activityInfo = displayInfo.resolveInfo.activityInfo; + String packageName = activityInfo.applicationInfo.packageName; + String className = activityInfo.name; + + long trackId = getArguments().getLong(KEY_TRACK_ID); + String trackUrl = getArguments().getString(KEY_TRACK_URL); + if (trackUrl == null) { + SendRequest sendRequest = new SendRequest(trackId); + sendRequest.setSendMaps(true); + sendRequest.setNewMap(true); + sendRequest.setSharingAppPackageName(packageName); + sendRequest.setSharingAppClassName(className); + Intent intent = IntentUtils.newIntent(getActivity(), AccountChooserActivity.class) + .putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest); + startActivity(intent); + dismiss(); + } else { + Intent intent = IntentUtils.newShareUrlIntent( + getActivity(), trackId, trackUrl, packageName, className); + startActivity(intent); + getActivity().finish(); + } + } + }) + .setTitle(R.string.share_track_picker_title) + .create(); + } + + /** + * Gets the display info. + */ + private List getDisplayInfos() { + List displayInfos = new ArrayList(); + Intent intent = ShareCompat.IntentBuilder.from(getActivity()) + .setType(IntentUtils.TEXT_PLAIN_TYPE).getIntent(); + List resolveInfos = packageManager.queryIntentActivities( + intent, PackageManager.MATCH_DEFAULT_ONLY); + if (resolveInfos != null && resolveInfos.size() > 0) { + int size = resolveInfos.size(); + ResolveInfo firstResolveInfo = resolveInfos.get(0); + for (int i = 1; i < size; i++) { + ResolveInfo resolveInfo = resolveInfos.get(i); + if (firstResolveInfo.priority != resolveInfo.priority + || firstResolveInfo.isDefault != resolveInfo.isDefault) { + while (i < size) { + resolveInfos.remove(i); + size--; + } + } + } + if (size > 1) { + ResolveInfo.DisplayNameComparator displayNameComparator = new ResolveInfo.DisplayNameComparator( + packageManager); + Collections.sort(resolveInfos, displayNameComparator); + } + + firstResolveInfo = resolveInfos.get(0); + int start = 0; + CharSequence firstLabel = firstResolveInfo.loadLabel(packageManager); + for (int i = 1; i < size; i++) { + if (firstLabel == null) { + firstLabel = firstResolveInfo.activityInfo.packageName; + } + ResolveInfo resolveInfo = resolveInfos.get(i); + CharSequence label = resolveInfo.loadLabel(packageManager); + if (label == null) { + label = resolveInfo.activityInfo.packageName; + } + if (label.equals(firstLabel)) { + continue; + } + processGroup(resolveInfos, displayInfos, start, i - 1); + firstResolveInfo = resolveInfo; + firstLabel = label; + start = i; + } + // Process last group + processGroup(resolveInfos, displayInfos, start, size - 1); + } + return displayInfos; + } + + /** + * Contains display info. + * + * @author Jimmy Shih + */ + private final class DisplayInfo { + private ResolveInfo resolveInfo; + private CharSequence primaryLabel; + private CharSequence secondaryLabel; + private Drawable icon; + + public DisplayInfo(ResolveInfo resolveInfo, CharSequence primaryLabel, + CharSequence secondaryLabel, Drawable icon) { + this.resolveInfo = resolveInfo; + this.primaryLabel = primaryLabel; + this.secondaryLabel = secondaryLabel; + this.icon = icon; + } + } + + /** + * Processes a group of items with the same label. + * + * @param resolveInfos list of resolve infos + * @param displayInfos list of display infos + * @param start start index + * @param end end index + */ + private void processGroup( + List resolveInfos, List displayInfos, int start, int end) { + ResolveInfo startResolveInfo = resolveInfos.get(start); + CharSequence primaryLabel = startResolveInfo.loadLabel(packageManager); + Drawable icon = startResolveInfo.loadIcon(packageManager); + + int num = end - start + 1; + if (num == 1) { + // Only one, set the secondary label to null + displayInfos.add(new DisplayInfo(startResolveInfo, primaryLabel, null, icon)); + } else { + // Decide package name or application name for the secondary label + boolean usePackageName = false; + CharSequence appName = startResolveInfo.activityInfo.applicationInfo.loadLabel( + packageManager); + if (appName == null) { + usePackageName = true; + } else { + // Use HashSet to track duplicates + HashSet duplicates = new HashSet(); + duplicates.add(appName); + for (int i = start + 1; i <= end; i++) { + ResolveInfo resolveInfo = resolveInfos.get(i); + CharSequence name = resolveInfo.activityInfo.applicationInfo.loadLabel(packageManager); + if ((name == null) || (duplicates.contains(name))) { + usePackageName = true; + break; + } else { + duplicates.add(name); + } + } + // Clear HashSet for later use + duplicates.clear(); + } + for (int i = start; i <= end; i++) { + ResolveInfo resolveInfo = resolveInfos.get(i); + CharSequence secondaryLabel = usePackageName ? resolveInfo.activityInfo.packageName + : resolveInfo.activityInfo.applicationInfo.loadLabel(packageManager); + displayInfos.add(new DisplayInfo(resolveInfo, primaryLabel, secondaryLabel, icon)); + } + } + } +} \ No newline at end of file diff --git a/MyTracks/src/com/google/android/apps/mytracks/fragments/ChooseUploadServiceDialogFragment.java b/MyTracks/src/com/google/android/apps/mytracks/fragments/ChooseUploadServiceDialogFragment.java new file mode 100644 index 000000000..8534e379e --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/fragments/ChooseUploadServiceDialogFragment.java @@ -0,0 +1,172 @@ +/* + * 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.fragments; + +import com.google.android.apps.mytracks.io.sendtogoogle.AccountChooserActivity; +import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest; +import com.google.android.apps.mytracks.util.AnalyticsUtils; +import com.google.android.apps.mytracks.util.IntentUtils; +import com.google.android.apps.mytracks.util.PreferencesUtils; +import com.google.android.maps.mytracks.R; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.view.View; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.RadioButton; +import android.widget.TableRow; +import android.widget.Toast; + +import java.util.ArrayList; + +/** + * A DialogFragment to choose upload service. + * + * @author Jimmy Shih + */ +public class ChooseUploadServiceDialogFragment extends DialogFragment { + + public static final String CHOOSE_UPLOAD_SERVICE_DIALOG_TAG = "chooseUploadService"; + + private static final String KEY_SEND_REQUEST = "sendRequest"; + + public static ChooseUploadServiceDialogFragment newInstance(SendRequest sendRequest) { + Bundle bundle = new Bundle(); + bundle.putParcelable(KEY_SEND_REQUEST, sendRequest); + + ChooseUploadServiceDialogFragment chooseUploadServiceDialogFragment = + new ChooseUploadServiceDialogFragment(); + chooseUploadServiceDialogFragment.setArguments(bundle); + return chooseUploadServiceDialogFragment; + } + + private SendRequest sendRequest; + + private CheckBox mapsCheckBox; + private CheckBox fusionTablesCheckBox; + private CheckBox docsCheckBox; + + private TableRow mapsOptionTableRow; + private RadioButton existingMapRadioButton; + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + sendRequest = getArguments().getParcelable(KEY_SEND_REQUEST); + View view = getActivity().getLayoutInflater().inflate(R.layout.choose_upload_service, null); + + mapsCheckBox = (CheckBox) view.findViewById(R.id.choose_upload_service_maps); + fusionTablesCheckBox = (CheckBox) view.findViewById(R.id.choose_upload_service_fusion_tables); + docsCheckBox = (CheckBox) view.findViewById(R.id.choose_upload_service_docs); + + mapsCheckBox.setChecked(PreferencesUtils.getBoolean( + getActivity(), R.string.send_to_maps_key, PreferencesUtils.SEND_TO_MAPS_DEFAULT)); + fusionTablesCheckBox.setChecked(PreferencesUtils.getBoolean( + getActivity(), R.string.send_to_fusion_tables_key, + PreferencesUtils.SEND_TO_FUSION_TABLES_DEFAULT)); + docsCheckBox.setChecked(PreferencesUtils.getBoolean( + getActivity(), R.string.send_to_docs_key, PreferencesUtils.SEND_TO_DOCS_DEFAULT)); + + mapsCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() { + public void onCheckedChanged(CompoundButton button, boolean checked) { + updateMapsOption(); + } + }); + + mapsOptionTableRow = (TableRow) view.findViewById(R.id.choose_upload_service_maps_options); + RadioButton newMapRadioButton = (RadioButton) view.findViewById( + R.id.choose_upload_service_new_map); + existingMapRadioButton = (RadioButton) view.findViewById( + R.id.choose_upload_service_existing_map); + + updateMapsOption(); + if (PreferencesUtils.getBoolean(getActivity(), R.string.pick_existing_map_key, + PreferencesUtils.PICK_EXISTING_MAP_DEFAULT)) { + existingMapRadioButton.setChecked(true); + } else { + newMapRadioButton.setChecked(true); + } + + return new AlertDialog.Builder(getActivity()).setNegativeButton(R.string.generic_cancel, null) + .setPositiveButton(R.string.send_google_send_now, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + PreferencesUtils.setBoolean( + getActivity(), R.string.pick_existing_map_key, existingMapRadioButton.isChecked()); + PreferencesUtils.setBoolean( + getActivity(), R.string.send_to_maps_key, mapsCheckBox.isChecked()); + PreferencesUtils.setBoolean(getActivity(), R.string.send_to_fusion_tables_key, + fusionTablesCheckBox.isChecked()); + PreferencesUtils.setBoolean( + getActivity(), R.string.send_to_docs_key, docsCheckBox.isChecked()); + if (mapsCheckBox.isChecked() || fusionTablesCheckBox.isChecked() + || docsCheckBox.isChecked()) { + startNextActivity(); + } else { + Toast.makeText( + getActivity(), R.string.send_google_no_service_selected, Toast.LENGTH_LONG) + .show(); + } + } + }) + .setTitle(R.string.send_google_title) + .setView(view) + .create(); + } + + /** + * Updates map option. + */ + private void updateMapsOption() { + mapsOptionTableRow.setVisibility(mapsCheckBox.isChecked() ? View.VISIBLE : View.GONE); + } + + /** + * Starts the next activity, {@link AccountChooserActivity}. + */ + private void startNextActivity() { + sendStats(); + sendRequest.setSendMaps(mapsCheckBox.isChecked()); + sendRequest.setSendFusionTables(fusionTablesCheckBox.isChecked()); + sendRequest.setSendDocs(docsCheckBox.isChecked()); + sendRequest.setNewMap(!existingMapRadioButton.isChecked()); + Intent intent = IntentUtils.newIntent(getActivity(), AccountChooserActivity.class) + .putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest); + startActivity(intent); + } + + /** + * Sends stats to Google Analytics. + */ + private void sendStats() { + ArrayList pages = new ArrayList(); + if (sendRequest.isSendMaps()) { + pages.add("/send/maps"); + } + if (sendRequest.isSendFusionTables()) { + pages.add("/send/fusion_tables"); + } + if (sendRequest.isSendDocs()) { + pages.add("/send/docs"); + } + AnalyticsUtils.sendPageViews(getActivity(), pages.toArray(new String[pages.size()])); + } +} diff --git a/MyTracks/src/com/google/android/apps/mytracks/fragments/FrequencyDialogFragment.java b/MyTracks/src/com/google/android/apps/mytracks/fragments/FrequencyDialogFragment.java new file mode 100644 index 000000000..ea8cdf099 --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/fragments/FrequencyDialogFragment.java @@ -0,0 +1,118 @@ +/* + * 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.fragments; + +import com.google.android.apps.mytracks.util.PreferencesUtils; +import com.google.android.maps.mytracks.R; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; + +/** + * A DialogFragment to configure frequency. + * + * @author Jimmy Shih + */ +public class FrequencyDialogFragment extends DialogFragment { + + public static final String FREQUENCY_DIALOG_TAG = "frequencyDialog"; + + private static final String KEY_PREFERENCE_ID = "preferenceId"; + private static final String KEY_DEFAULT_VALUE = "defaultValue"; + private static final String KEY_TITLE_ID = "titleId"; + + public static FrequencyDialogFragment newInstance( + int preferenceId, int defaultValue, int titleId) { + Bundle bundle = new Bundle(); + bundle.putInt(KEY_PREFERENCE_ID, preferenceId); + bundle.putInt(KEY_DEFAULT_VALUE, defaultValue); + bundle.putInt(KEY_TITLE_ID, titleId); + + FrequencyDialogFragment frequencyDialogFragment = new FrequencyDialogFragment(); + frequencyDialogFragment.setArguments(bundle); + return frequencyDialogFragment; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final int preferenceId = getArguments().getInt(KEY_PREFERENCE_ID); + int defaultValue = getArguments().getInt(KEY_DEFAULT_VALUE); + int titleId = getArguments().getInt(KEY_TITLE_ID); + int frequencyValue = PreferencesUtils.getInt(getActivity(), preferenceId, defaultValue); + + return new AlertDialog.Builder(getActivity()) + .setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + int listIndex = ((AlertDialog) dialog).getListView().getCheckedItemPosition(); + PreferencesUtils.setInt(getActivity(), preferenceId, getFrequencyValue(listIndex)); + } + }) + .setSingleChoiceItems(getFrequencyDisplayOptions(), getListIndex(frequencyValue), null) + .setTitle(titleId) + .create(); + } + + /** + * Gets the frequency display options. + */ + private String[] getFrequencyDisplayOptions() { + boolean metricUnits = PreferencesUtils.getBoolean( + getActivity(), R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT); + String[] values = getResources().getStringArray(R.array.frequency_values); + String[] options = new String[values.length]; + for (int i = 0; i < values.length; i++) { + int value = Integer.parseInt(values[i]); + if (value == PreferencesUtils.FREQUENCY_OFF) { + options[i] = getString(R.string.value_off); + } else if (value < 0) { + options[i] = getString(metricUnits ? R.string.value_integer_kilometer + : R.string.value_integer_mile, Math.abs(value)); + } else { + options[i] = getString(R.string.value_integer_minute, value); + } + } + return options; + } + + /** + * Gets the list index for a frequency value. Returns 0 if the value is not on + * the list. + */ + private int getListIndex(int frequencyValue) { + String[] values = getResources().getStringArray(R.array.frequency_values); + for (int i = 0; i < values.length; i++) { + if (frequencyValue == Integer.parseInt(values[i])) { + return i; + } + } + return 0; + } + + /** + * Gets the frequency value from a list index. + * + * @param listIndex the list index + */ + private int getFrequencyValue(int listIndex) { + String[] values = getResources().getStringArray(R.array.frequency_values); + return Integer.parseInt(values[listIndex]); + } +} \ No newline at end of file diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupAsyncTask.java index fd0675640..c9a104cac 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupAsyncTask.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupAsyncTask.java @@ -56,7 +56,7 @@ public class BackupAsyncTask extends AsyncTask { this.externalFileBackup = new ExternalFileBackup(backupActivity); success = false; completed = false; - messageId = R.string.sd_card_error_write_file; + messageId = R.string.sd_card_save_error; } /** @@ -86,13 +86,13 @@ public class BackupAsyncTask extends AsyncTask { } if (!externalFileBackup.isBackupsDirectoryAvailable(true)) { - messageId = R.string.sd_card_error_create_dir; + messageId = R.string.sd_card_save_error_create_dir; return false; } try { externalFileBackup.writeToDefaultFile(); - messageId = R.string.sd_card_success_write_file; + messageId = R.string.sd_card_save_success; return true; } catch (IOException e) { Log.d(TAG, "IO exception", e); diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/backup/DatabaseImporter.java b/MyTracks/src/com/google/android/apps/mytracks/io/backup/DatabaseImporter.java index 21a8e7ccb..949963d5f 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/backup/DatabaseImporter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/backup/DatabaseImporter.java @@ -23,6 +23,7 @@ import android.net.Uri; import java.io.DataInputStream; import java.io.IOException; +import java.util.Locale; /** * Database importer which reads values written by {@link DatabaseDumper}. @@ -179,7 +180,7 @@ public class DatabaseImporter { byte[] blob = new byte[blobLength]; int readBytes = reader.read(blob, 0, blobLength); if (readBytes != blobLength) { - throw new IOException(String.format( + throw new IOException(String.format(Locale.US, "Short read on column %s; expected %d bytes, read %d", name, blobLength, readBytes)); } diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/backup/RestoreAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/io/backup/RestoreAsyncTask.java index 009c0d44f..b9e8efbfc 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/backup/RestoreAsyncTask.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/backup/RestoreAsyncTask.java @@ -59,7 +59,7 @@ public class RestoreAsyncTask extends AsyncTask { this.externalFileBackup = new ExternalFileBackup(restoreActivity); success = false; completed = false; - messageId = R.string.sd_card_error_read_file; + messageId = R.string.sd_card_import_error; } /** @@ -85,7 +85,7 @@ public class RestoreAsyncTask extends AsyncTask { protected Boolean doInBackground(Void... params) { try { externalFileBackup.restoreFromDate(date); - messageId = R.string.sd_card_success_read_file; + messageId = R.string.sd_card_import_success; return true; } catch (IOException e) { Log.d(TAG, "IO exception", e); diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/docs/SendDocsAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/io/docs/SendDocsAsyncTask.java index dad8e3aea..042b3b09c 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/docs/SendDocsAsyncTask.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/docs/SendDocsAsyncTask.java @@ -119,7 +119,7 @@ public class SendDocsAsyncTask extends AbstractSendAsyncTask { Track track = myTracksProviderUtils.getTrack(trackId); if (track == null) { - Log.d(TAG, "Track is null"); + Log.d(TAG, "No track for " + trackId); return false; } diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/docs/SendDocsUtils.java b/MyTracks/src/com/google/android/apps/mytracks/io/docs/SendDocsUtils.java index 922df8185..568c48002 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/docs/SendDocsUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/docs/SendDocsUtils.java @@ -106,7 +106,7 @@ public class SendDocsUtils { throws IOException, ParseException, HttpException { GDataParser gDataParser = null; try { - String uri = String.format(GET_SPREADSHEET_BY_TITLE_URI, URLEncoder.encode(title)); + String uri = String.format(Locale.US, GET_SPREADSHEET_BY_TITLE_URI, URLEncoder.encode(title)); gDataParser = documentsClient.getParserForFeed(Entry.class, uri, authToken); gDataParser.init(); @@ -222,7 +222,7 @@ public class SendDocsUtils { throws IOException, AuthenticationException, ParseException { GDataParser gDataParser = null; try { - String uri = String.format(GET_WORKSHEETS_URI, spreadsheetId); + String uri = String.format(Locale.US, GET_WORKSHEETS_URI, spreadsheetId); gDataParser = spreadsheetClient.getParserForWorksheetsFeed(uri, authToken); gDataParser.init(); if (!gDataParser.hasMoreData()) { @@ -269,7 +269,7 @@ public class SendDocsUtils { public static void addTrackInfo( Track track, String spreadsheetId, String worksheetId, String authToken, Context context) throws IOException { - String worksheetUri = String.format(GET_WORKSHEET_URI, spreadsheetId, worksheetId); + String worksheetUri = String.format(Locale.US, GET_WORKSHEET_URI, spreadsheetId, worksheetId); boolean metricUnits = PreferencesUtils.getBoolean( context, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT); addRow(worksheetUri, getRowContent(track, metricUnits, context), authToken); @@ -312,8 +312,8 @@ public class SendDocsUtils { appendTag(builder, "elevationunit", elevationUnit); if (track.getMapId().length() > 0) { - appendTag(builder, "map", - String.format("%s?msa=0&msid=%s", Constants.MAPSHOP_BASE_URL, track.getMapId())); + appendTag(builder, "map", String.format( + Locale.US, "%s?msa=0&msid=%s", Constants.MAPSHOP_BASE_URL, track.getMapId())); } builder.append(""); diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/KmlTrackWriter.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/KmlTrackWriter.java index 1b8cfcb8e..dff35b1f6 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/KmlTrackWriter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/KmlTrackWriter.java @@ -197,7 +197,7 @@ public class KmlTrackWriter implements TrackFormatWriter { printWriter.println(""); printWriter.println(""); String name = context.getString(R.string.marker_label_end, track.getName()); - String description = descriptionGenerator.generateTrackDescription(track, null, null); + String description = descriptionGenerator.generateTrackDescription(track, null, null, false); writePlacemark(name, description, END_STYLE, lastLocation); } } diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveActivity.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveActivity.java index 66808954c..46cf90e12 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveActivity.java @@ -16,10 +16,9 @@ package com.google.android.apps.mytracks.io.file; -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.DialogUtils; -import com.google.android.apps.mytracks.util.FileUtils; +import com.google.android.apps.mytracks.util.IntentUtils; import com.google.android.maps.mytracks.R; import android.app.Activity; @@ -30,21 +29,19 @@ import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.util.Log; import java.io.File; /** - * Activity for saving a track to the SD card, and optionally share or play the - * track. - * + * An activity for saving tracks to the SD card. If saving a specific track, + * option to save it to a temp directory and play the track afterward. + * * @author Rodrigo Damazio */ public class SaveActivity extends Activity { - public static final String EXTRA_TRACK_ID = "track_id"; public static final String EXTRA_TRACK_FILE_FORMAT = "track_file_format"; - public static final String EXTRA_SHARE_TRACK = "share_track"; + public static final String EXTRA_TRACK_ID = "track_id"; public static final String EXTRA_PLAY_TRACK = "play_track"; public static final String GOOGLE_EARTH_KML_MIME_TYPE = "application/vnd.google-earth.kml+xml"; @@ -55,14 +52,11 @@ public class SaveActivity extends Activity { GOOGLE_EARTH_TOUR_FEATURE_ID = "com.google.earth.EXTRA.tour_feature_id"; private static final String GOOGLE_EARTH_CLASS = "com.google.earth.EarthActivity"; - private static final String TAG = SaveActivity.class.getSimpleName(); - private static final int DIALOG_PROGRESS_ID = 0; private static final int DIALOG_RESULT_ID = 1; - private long trackId; private TrackFileFormat trackFileFormat; - private boolean shareTrack; + private long trackId; private boolean playTrack; private SaveAsyncTask saveAsyncTask; @@ -74,23 +68,16 @@ public class SaveActivity extends Activity { // message id from the AsyncTask private int messageId; - // path of the saved file - private String filePath; + // saved file path from the AsyncTask + private String savedPath; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = getIntent(); - trackId = intent.getLongExtra(EXTRA_TRACK_ID, -1L); - if (trackId < 0) { - Log.d(TAG, "Invalid track id"); - finish(); - return; - } - trackFileFormat = intent.getParcelableExtra(EXTRA_TRACK_FILE_FORMAT); - shareTrack = intent.getBooleanExtra(EXTRA_SHARE_TRACK, false); + trackId = intent.getLongExtra(EXTRA_TRACK_ID, -1L); playTrack = intent.getBooleanExtra(EXTRA_PLAY_TRACK, false); Object retained = getLastNonConfigurationInstance(); @@ -98,20 +85,7 @@ public class SaveActivity extends Activity { saveAsyncTask = (SaveAsyncTask) retained; saveAsyncTask.setActivity(this); } else { - TrackWriter trackWriter = TrackWriterFactory.newWriter( - this, MyTracksProviderUtils.Factory.get(this), trackId, trackFileFormat); - if (trackWriter == null) { - Log.e(TAG, "Track writer is null"); - finish(); - return; - } - if (shareTrack || playTrack) { - // Save to the temp directory - String dirName = FileUtils.buildExternalDirectoryPath( - trackFileFormat.getExtension(), "tmp"); - trackWriter.setDirectory(new File(dirName)); - } - saveAsyncTask = new SaveAsyncTask(this, trackWriter); + saveAsyncTask = new SaveAsyncTask(this, trackFileFormat, trackId, playTrack); saveAsyncTask.execute(); } } @@ -127,7 +101,7 @@ public class SaveActivity extends Activity { switch (id) { case DIALOG_PROGRESS_ID: progressDialog = DialogUtils.createHorizontalProgressDialog( - this, R.string.sd_card_progress_message, new DialogInterface.OnCancelListener() { + this, R.string.sd_card_save_progress_message, new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { saveAsyncTask.cancel(true); @@ -136,7 +110,7 @@ public class SaveActivity extends Activity { }); return progressDialog; case DIALOG_RESULT_ID: - return new AlertDialog.Builder(this) + AlertDialog.Builder builder = new AlertDialog.Builder(this) .setCancelable(true) .setIcon(success ? android.R.drawable.ic_dialog_info : android.R.drawable.ic_dialog_alert) @@ -155,8 +129,22 @@ public class SaveActivity extends Activity { onPostResultDialog(); } }) - .setTitle(success ? R.string.generic_success_title : R.string.generic_error_title) - .create(); + .setTitle(success ? R.string.generic_success_title : R.string.generic_error_title); + + if (success && trackId != -1L && !playTrack) { + builder.setNegativeButton( + R.string.share_track_share_file, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Intent intent = IntentUtils.newShareFileIntent( + SaveActivity.this, trackId, savedPath, trackFileFormat); + startActivity( + Intent.createChooser(intent, getString(R.string.share_track_picker_title))); + finish(); + } + }); + } + return builder.create(); default: return null; } @@ -167,12 +155,12 @@ public class SaveActivity extends Activity { * * @param isSuccess true if the AsyncTask is successful * @param aMessageId the id of the AsyncTask message - * @param aPath the path of the saved file + * @param aSavedPath the path of the saved file */ - public void onAsyncTaskCompleted(boolean isSuccess, int aMessageId, String aPath) { + public void onAsyncTaskCompleted(boolean isSuccess, int aMessageId, String aSavedPath) { this.success = isSuccess; this.messageId = aMessageId; - this.filePath = aPath; + this.savedPath = aSavedPath; removeDialog(DIALOG_PROGRESS_ID); showDialog(DIALOG_RESULT_ID); } @@ -202,23 +190,13 @@ public class SaveActivity extends Activity { * To be invoked after showing the result dialog. */ private void onPostResultDialog() { - if (success) { - if (shareTrack) { - Intent intent = new Intent(Intent.ACTION_SEND) - .putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(filePath))) - .putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_track_subject)) - .putExtra(Intent.EXTRA_TEXT, getString(R.string.share_track_file_body_format)) - .putExtra(getString(R.string.track_id_broadcast_extra), trackId) - .setType(trackFileFormat.getMimeType()); - startActivity(Intent.createChooser(intent, getString(R.string.share_track_picker_title))); - } else if (playTrack) { - Intent intent = new Intent() - .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK) - .putExtra(GOOGLE_EARTH_TOUR_FEATURE_ID, KmlTrackWriter.TOUR_FEATURE_ID) - .setClassName(GOOGLE_EARTH_PACKAGE, GOOGLE_EARTH_CLASS) - .setDataAndType(Uri.fromFile(new File(filePath)), GOOGLE_EARTH_KML_MIME_TYPE); - startActivity(intent); - } + if (success && playTrack) { + Intent intent = new Intent() + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK) + .putExtra(GOOGLE_EARTH_TOUR_FEATURE_ID, KmlTrackWriter.TOUR_FEATURE_ID) + .setClassName(GOOGLE_EARTH_PACKAGE, GOOGLE_EARTH_CLASS) + .setDataAndType(Uri.fromFile(new File(savedPath)), GOOGLE_EARTH_KML_MIME_TYPE); + startActivity(intent); } finish(); } diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveAsyncTask.java index 2c5aa929a..36e0ec6d3 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveAsyncTask.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveAsyncTask.java @@ -16,48 +16,93 @@ package com.google.android.apps.mytracks.io.file; +import com.google.android.apps.mytracks.content.MyTracksProviderUtils; +import com.google.android.apps.mytracks.content.TracksColumns; +import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat; +import com.google.android.apps.mytracks.util.FileUtils; +import com.google.android.apps.mytracks.util.PreferencesUtils; +import com.google.android.apps.mytracks.util.SystemUtils; +import com.google.android.maps.mytracks.R; + +import android.content.Context; +import android.database.Cursor; import android.os.AsyncTask; +import android.os.PowerManager.WakeLock; +import android.util.Log; + +import java.io.File; /** - * Async Task to save a track to the SD card. - * + * Async Task to save tracks to the SD card. + * * @author Jimmy Shih */ public class SaveAsyncTask extends AsyncTask { + private static final String TAG = SaveAsyncTask.class.getSimpleName(); + private SaveActivity saveActivity; - private final TrackWriter trackWriter; - + private final TrackFileFormat trackFileFormat; + private final long trackId; + private final boolean useTempDir; + + 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; + + // saved file path to return to the activity + private String savedPath; + /** * Creates an AsyncTask. - * - * @param saveActivity the {@link SaveActivity} currently associated with this - * AsyncTask - * @param trackWriter the track writer + * + * @param saveActivity the activity currently associated with this task. + * @param trackFileFormat the track format + * @param trackId the track id + * @param useTempDir true to use the temp directory */ - public SaveAsyncTask(SaveActivity saveActivity, TrackWriter trackWriter) { + public SaveAsyncTask(SaveActivity saveActivity, TrackFileFormat trackFileFormat, long trackId, + boolean useTempDir) { this.saveActivity = saveActivity; - this.trackWriter = trackWriter; + this.trackFileFormat = trackFileFormat; + this.trackId = trackId; + this.useTempDir = useTempDir; + context = saveActivity.getApplicationContext(); + + myTracksProviderUtils = MyTracksProviderUtils.Factory.get(saveActivity); + + // Get the wake lock if not recording + if (PreferencesUtils.getLong(saveActivity, R.string.recording_track_id_key) + == PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) { + wakeLock = SystemUtils.acquireWakeLock(saveActivity, wakeLock); + } + + trackWriter = null; success = false; completed = false; + messageId = R.string.sd_card_save_error; + savedPath = null; } /** - * Sets the current {@link SaveActivity} associated with this AyncTask. - * - * @param saveActivity the current {@link SaveActivity}, can be null + * Sets the current activity associated with this AyncTask. + * + * @param saveActivity the current activity, can be null */ public void setActivity(SaveActivity saveActivity) { this.saveActivity = saveActivity; if (completed && saveActivity != null) { - saveActivity.onAsyncTaskCompleted( - success, trackWriter.getErrorMessage(), trackWriter.getAbsolutePath()); + saveActivity.onAsyncTaskCompleted(success, messageId, savedPath); } } @@ -69,20 +114,85 @@ public class SaveAsyncTask extends AsyncTask { } @Override - protected Boolean doInBackground(Void... params) { + protected Boolean doInBackground(Void... params) { + try { + if (trackId != -1L) { + return saveOneTrack(trackId, true); + } else { + return saveAllTracks(); + } + } finally { + // Release the wake lock if obtained + if (wakeLock != null && wakeLock.isHeld()) { + wakeLock.release(); + } + } + } + + /** + * Saves one track. + * + * @param id the track id + * @param updateSavingProgress true to update the saving progress + */ + private Boolean saveOneTrack(long id, final boolean updateSavingProgress) { + trackWriter = TrackWriterFactory.newWriter( + context, myTracksProviderUtils, id, trackFileFormat); + if (trackWriter == null) { + Log.e(TAG, "Track writer is null"); + return false; + } + if (useTempDir) { + String dirName = FileUtils.buildExternalDirectoryPath(trackFileFormat.getExtension(), "tmp"); + trackWriter.setDirectory(new File(dirName)); + } trackWriter.setOnWriteListener(new TrackWriter.OnWriteListener() { - @Override + @Override public void onWrite(int number, int max) { // Update the progress dialog once every 500 points - if (number % 500 == 0) { + if (updateSavingProgress && number % 500 == 0) { publishProgress(number, max); } } }); trackWriter.writeTrack(); + messageId = trackWriter.getErrorMessage(); + savedPath = trackWriter.getAbsolutePath(); return trackWriter.wasSuccess(); } + /** + * Saves all the tracks. + */ + private Boolean saveAllTracks() { + Cursor cursor = null; + try { + cursor = myTracksProviderUtils.getTracksCursor(null, null, TracksColumns._ID); + if (cursor == null) { + messageId = R.string.sd_card_save_error_no_track; + return false; + } + 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); + if (!saveOneTrack(id, false)) { + return false; + } + publishProgress(i + 1, count); + } + messageId = R.string.sd_card_save_success; + return true; + } finally { + if (cursor != null) { + cursor.close(); + } + } + } @Override protected void onProgressUpdate(Integer... values) { if (saveActivity != null) { @@ -95,13 +205,14 @@ public class SaveAsyncTask extends AsyncTask { success = result; completed = true; if (saveActivity != null) { - saveActivity.onAsyncTaskCompleted( - success, trackWriter.getErrorMessage(), trackWriter.getAbsolutePath()); + saveActivity.onAsyncTaskCompleted(success, messageId, savedPath); } } @Override protected void onCancelled() { - trackWriter.stopWriteTrack(); + if (trackWriter != null) { + trackWriter.stopWriteTrack(); + } } } diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterFactory.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterFactory.java index 37ea46b96..91536b3e0 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterFactory.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterFactory.java @@ -118,7 +118,7 @@ public class TrackWriterFactory { long trackId, TrackFileFormat format) { Track track = providerUtils.getTrack(trackId); if (track == null) { - Log.w(TAG, "Trying to create a writer for an invalid track, id=" + trackId); + Log.d(TAG, "No track for " + trackId); return null; } diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterImpl.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterImpl.java index 977ea8692..8fbf20975 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterImpl.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriterImpl.java @@ -53,7 +53,7 @@ class TrackWriterImpl implements TrackWriter { private final Track track; private final TrackFormatWriter writer; private boolean success = false; - private int errorMessage = -1; + private int errorMessage = R.string.sd_card_save_error; private File directory = null; private File file = null; private OnWriteListener onWriteListener; @@ -105,7 +105,7 @@ class TrackWriterImpl implements TrackWriter { private void doWriteTrack() { // Open the input and output success = false; - errorMessage = R.string.sd_card_error_write_file; + errorMessage = R.string.sd_card_save_error; if (track != null) { if (openFile()) { try { @@ -186,7 +186,7 @@ class TrackWriterImpl implements TrackWriter { writer.prepare(track, newOutputStream(fileName)); } catch (FileNotFoundException e) { Log.e(Constants.TAG, "Failed to open output file.", e); - errorMessage = R.string.sd_card_error_write_file; + errorMessage = R.string.sd_card_save_error; return false; } return true; @@ -209,7 +209,7 @@ class TrackWriterImpl implements TrackWriter { } if (!FileUtils.ensureDirectoryExists(directory)) { Log.i(Constants.TAG, "Could not create export directory."); - errorMessage = R.string.sd_card_error_create_dir; + errorMessage = R.string.sd_card_save_error_create_dir; return false; } @@ -283,7 +283,7 @@ class TrackWriterImpl implements TrackWriter { writer.close(); success = true; Log.d(Constants.TAG, "Done writing track."); - errorMessage = R.string.sd_card_success_write_file; + errorMessage = R.string.sd_card_save_success; } private void writeLocations() throws InterruptedException { diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/fusiontables/SendFusionTablesAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/io/fusiontables/SendFusionTablesAsyncTask.java index b93493ca8..7795fe3ee 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/fusiontables/SendFusionTablesAsyncTask.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/fusiontables/SendFusionTablesAsyncTask.java @@ -105,12 +105,12 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { @Override protected void saveResult() { Track track = myTracksProviderUtils.getTrack(trackId); - if (track != null) { - track.setTableId(tableId); - myTracksProviderUtils.updateTrack(track); - } else { - Log.d(TAG, "No track"); + if (track == null) { + Log.d(TAG, "No track for " + trackId); + return; } + track.setTableId(tableId); + myTracksProviderUtils.updateTrack(track); } @Override @@ -136,7 +136,7 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { Track track = myTracksProviderUtils.getTrack(trackId); if (track == null) { - Log.d(TAG, "Track is null"); + Log.d(TAG, "No track for " + trackId); return false; } @@ -277,7 +277,8 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask { elevations.add(elevationBuffer.getAverage()); DescriptionGenerator descriptionGenerator = new DescriptionGeneratorImpl(context); track.setDescription("

" + track.getDescription() + "

" - + descriptionGenerator.generateTrackDescription(track, distances, elevations) + "

"); + + descriptionGenerator.generateTrackDescription(track, distances, elevations, true) + + "

"); String name = context.getString(R.string.marker_label_end, track.getName()); if (!createNewPoint(name, track.getDescription(), lastLocation, MARKER_TYPE_END)) { Log.d(TAG, "Unable to create the end marker"); diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/gdata/maps/MapsClient.java b/MyTracks/src/com/google/android/apps/mytracks/io/gdata/maps/MapsClient.java index 3a87ac21c..993d21f84 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/gdata/maps/MapsClient.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/gdata/maps/MapsClient.java @@ -7,6 +7,8 @@ import com.google.wireless.gdata.client.GDataServiceClient; import android.util.Log; +import java.util.Locale; + /** * Client to talk to Google Maps via GData. */ @@ -93,9 +95,8 @@ public class MapsClient extends GDataServiceClient { public static String getVersionFeed(String versionUserId, String versionClient, String currentVersion) { - return String.format(MAPS_VERSION_FEED_PATH_FORMAT, - MAPS_BASE_FEED_URL, versionUserId, - versionClient, currentVersion); + return String.format(Locale.US, MAPS_VERSION_FEED_PATH_FORMAT, MAPS_BASE_FEED_URL, + versionUserId, versionClient, currentVersion); } } diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/maps/SendMapsAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/io/maps/SendMapsAsyncTask.java index 8d952c5bb..789e03491 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/maps/SendMapsAsyncTask.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/maps/SendMapsAsyncTask.java @@ -131,14 +131,14 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { @Override protected void saveResult() { Track track = myTracksProviderUtils.getTrack(trackId); - if (track != null) { - track.setMapId(mapId); - myTracksProviderUtils.updateTrack(track); - } else { - Log.d(TAG, "No track"); + if (track == null) { + Log.d(TAG, "No track for " + trackId); + return; } + track.setMapId(mapId); + myTracksProviderUtils.updateTrack(track); } - + @Override protected boolean performTask() { // Reset the per upload states @@ -173,7 +173,7 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { // Get the track Track track = myTracksProviderUtils.getTrack(trackId); if (track == null) { - Log.d(TAG, "Track is null"); + Log.d(TAG, "No track for " + trackId); return false; } @@ -353,7 +353,8 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask { String getTrackDescription(Track track, Vector distances, Vector elevations) { DescriptionGenerator descriptionGenerator = new DescriptionGeneratorImpl(context); return "

" + track.getDescription() + "

" - + descriptionGenerator.generateTrackDescription(track, distances, elevations) + "

"; + + descriptionGenerator.generateTrackDescription(track, distances, elevations, true) + + "

"; } /** diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/AbstractSendAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/AbstractSendAsyncTask.java index 710d21c6d..11dab9c5c 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/AbstractSendAsyncTask.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/AbstractSendAsyncTask.java @@ -80,9 +80,6 @@ public abstract class AbstractSendAsyncTask extends AsyncTask 1 ) { - showDialog(DIALOG_CHOOSER_ID); - } + showDialog(DIALOG_CHOOSER_ID); } @Override @@ -162,20 +157,15 @@ public class AccountChooserActivity extends Activity { }) .setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { - Account account = accounts[selectedAccountIndex]; + int position = ((AlertDialog) dialog).getListView().getCheckedItemPosition(); + Account account = accounts[position]; PreferencesUtils.setString( - AccountChooserActivity.this, R.string.preferred_account_key, account.name); + AccountChooserActivity.this, R.string.sharing_account_key, account.name); sendRequest.setAccount(account); getPermission(MapsConstants.SERVICE_NAME, sendRequest.isSendMaps(), mapsCallback); } }) - .setSingleChoiceItems( - choices, selectedAccountIndex, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - selectedAccountIndex = which; - } - }) + .setSingleChoiceItems(choices, 0, null) .setTitle(R.string.send_google_choose_account_title) .create(); } diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendRequest.java b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendRequest.java index a5be3b24d..4dd2d0ed0 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendRequest.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/SendRequest.java @@ -31,9 +31,8 @@ public class SendRequest implements Parcelable { public static final String SEND_REQUEST_KEY = "sendRequest"; private long trackId = -1L; - private boolean showMaps = false; - private boolean showFusionTables = false; - private boolean showDocs = false; + private String sharingAppPackageName = null; + private String sharingAppClassName = null; private boolean sendMaps = false; private boolean sendFusionTables = false; private boolean sendDocs = false; @@ -48,15 +47,9 @@ public class SendRequest implements Parcelable { * Creates a new send request. * * @param trackId the track id - * @param showMaps true to show the Google Maps option - * @param showFusionTables true to show the Google Fusion Tables option - * @param showDocs true to show the Google Docs option */ - public SendRequest(long trackId, boolean showMaps, boolean showFusionTables, boolean showDocs) { + public SendRequest(long trackId) { this.trackId = trackId; - this.showMaps = showMaps; - this.showFusionTables = showFusionTables; - this.showDocs = showDocs; } /** @@ -67,31 +60,35 @@ public class SendRequest implements Parcelable { } /** - * True if showing the send to Google Maps option. + * Gets the sharing app package name. */ - public boolean isShowMaps() { - return showMaps; + public String getSharingAppPackageName() { + return sharingAppPackageName; } /** - * True if showing the send to Google Fusion Tables option. + * Sets the sharing app package name. + * + * @param sharingAppPackageName the sharing app package name */ - public boolean isShowFusionTables() { - return showFusionTables; + public void setSharingAppPackageName(String sharingAppPackageName) { + this.sharingAppPackageName = sharingAppPackageName; } /** - * True if showing the send to Google Docs option. + * Gets the sharing app class name. */ - public boolean isShowDocs() { - return showDocs; + public String getSharingAppClassName() { + return sharingAppClassName; } /** - * True if showing all the send options. + * Sets the sharing app class name. + * + * @param sharingAppClassName the sharing app class name */ - public boolean isShowAll() { - return showMaps && showFusionTables && showDocs; + public void setSharingAppClassName(String sharingAppClassName) { + this.sharingAppClassName = sharingAppClassName; } /** @@ -245,9 +242,8 @@ public class SendRequest implements Parcelable { private SendRequest(Parcel in) { trackId = in.readLong(); - showMaps = in.readByte() == 1; - showFusionTables = in.readByte() == 1; - showDocs = in.readByte() == 1; + sharingAppPackageName = in.readString(); + sharingAppClassName = in.readString(); sendMaps = in.readByte() == 1; sendFusionTables = in.readByte() == 1; sendDocs = in.readByte() == 1; @@ -267,9 +263,8 @@ public class SendRequest implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { out.writeLong(trackId); - out.writeByte((byte) (showMaps ? 1 : 0)); - out.writeByte((byte) (showFusionTables ? 1 : 0)); - out.writeByte((byte) (showDocs ? 1 : 0)); + out.writeString(sharingAppPackageName); + out.writeString(sharingAppClassName); out.writeByte((byte) (sendMaps ? 1 : 0)); out.writeByte((byte) (sendFusionTables ? 1 : 0)); out.writeByte((byte) (sendDocs ? 1 : 0)); diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadResultActivity.java b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadResultActivity.java index bb523282b..01369bb09 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadResultActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadResultActivity.java @@ -17,18 +17,20 @@ package com.google.android.apps.mytracks.io.sendtogoogle; import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.Track; +import com.google.android.apps.mytracks.fragments.ChooseActivityDialogFragment; import com.google.android.apps.mytracks.io.fusiontables.SendFusionTablesUtils; import com.google.android.apps.mytracks.io.maps.SendMapsUtils; -import com.google.android.apps.mytracks.util.PreferencesUtils; +import com.google.android.apps.mytracks.util.IntentUtils; import com.google.android.maps.mytracks.R; import com.google.common.annotations.VisibleForTesting; -import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; +import android.support.v4.app.FragmentActivity; +import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; @@ -36,45 +38,45 @@ import android.widget.TextView; /** * A dialog to show the result of uploading to Google services. - * + * * @author Jimmy Shih */ -public class UploadResultActivity extends Activity { +public class UploadResultActivity extends FragmentActivity { - private static final String TEXT_PLAIN_TYPE = "text/plain"; + private static final String TAG = UploadResultActivity.class.getSimpleName(); private static final int DIALOG_RESULT_ID = 0; private SendRequest sendRequest; - private Track track; private String shareUrl; private Dialog resultDialog; - + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); sendRequest = getIntent().getParcelableExtra(SendRequest.SEND_REQUEST_KEY); - track = null; shareUrl = null; + + Track track = MyTracksProviderUtils.Factory.get(this).getTrack(sendRequest.getTrackId()); + if (track == null) { + Log.d(TAG, "No track for " + sendRequest.getTrackId()); + finish(); + return; + } if (sendRequest.isSendMaps() && sendRequest.isMapsSuccess()) { - shareUrl = SendMapsUtils.getMapUrl(getTrack()); + shareUrl = SendMapsUtils.getMapUrl(track); + if (sendRequest.getSharingAppPackageName() != null) { + Intent intent = IntentUtils.newShareUrlIntent(this, sendRequest.getTrackId(), shareUrl, + sendRequest.getSharingAppPackageName(), sendRequest.getSharingAppClassName()); + startActivity(intent); + finish(); + return; + } } if (shareUrl == null && sendRequest.isSendFusionTables() && sendRequest.isFusionTablesSuccess()) { - shareUrl = SendFusionTablesUtils.getMapUrl(getTrack()); + shareUrl = SendFusionTablesUtils.getMapUrl(track); } - } - - private Track getTrack() { - if (track == null) { - track = MyTracksProviderUtils.Factory.get(this).getTrack(sendRequest.getTrackId()); - } - return track; - } - - @Override - protected void onResume() { - super.onResume(); showDialog(DIALOG_RESULT_ID); } @@ -82,7 +84,7 @@ public class UploadResultActivity extends Activity { protected Dialog onCreateDialog(int id) { if (id != DIALOG_RESULT_ID) { return null; - } + } View view = getLayoutInflater().inflate(R.layout.upload_result, null); LinearLayout mapsResult = (LinearLayout) view.findViewById(R.id.upload_result_maps_result); @@ -139,31 +141,29 @@ public class UploadResultActivity extends Activity { .setCancelable(true) .setIcon(hasError ? android.R.drawable.ic_dialog_alert : android.R.drawable.ic_dialog_info) .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override + @Override public void onCancel(DialogInterface dialog) { finish(); } }) .setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() { - @Override + @Override public void onClick(DialogInterface dialog, int which) { - if (!sendRequest.isShowAll() && shareUrl != null) { - startShareUrlActivity(shareUrl); - } finish(); } }) .setTitle(hasError ? R.string.generic_error_title : R.string.generic_success_title) .setView(view); - // Add a Share URL button if showing all the options and a shareUrl exists - if (sendRequest.isShowAll() && shareUrl != null) { + // Add a Share URL button if shareUrl exists + if (shareUrl != null) { builder.setNegativeButton( - R.string.send_google_result_share_url, new DialogInterface.OnClickListener() { - @Override + R.string.share_track_share_url, new DialogInterface.OnClickListener() { + @Override public void onClick(DialogInterface dialog, int which) { - startShareUrlActivity(shareUrl); - finish(); + ChooseActivityDialogFragment.newInstance(sendRequest.getTrackId(), shareUrl).show( + getSupportFragmentManager(), + ChooseActivityDialogFragment.CHOOSE_ACTIVITY_DIALOG_TAG); } }); } @@ -171,22 +171,6 @@ public class UploadResultActivity extends Activity { return resultDialog; } - /** - * Starts an activity to share the url. - * - * @param url the url - */ - private void startShareUrlActivity(String url) { - boolean shareUrlOnly = PreferencesUtils.getBoolean( - this, R.string.share_url_only_key, PreferencesUtils.SHARE_URL_ONLY_DEFAULT); - Intent intent = new Intent(Intent.ACTION_SEND) - .setType(TEXT_PLAIN_TYPE) - .putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_track_subject)) - .putExtra(Intent.EXTRA_TEXT, - shareUrlOnly ? url : getString(R.string.share_track_url_body_format, url)); - startActivity(Intent.createChooser(intent, getString(R.string.share_track_picker_title))); - } - @VisibleForTesting Dialog getDialog() { return resultDialog; diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadServiceChooserActivity.java b/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadServiceChooserActivity.java deleted file mode 100644 index 80d4455db..000000000 --- a/MyTracks/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadServiceChooserActivity.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.android.apps.mytracks.io.sendtogoogle; - -import com.google.android.apps.mytracks.util.AnalyticsUtils; -import com.google.android.apps.mytracks.util.IntentUtils; -import com.google.android.apps.mytracks.util.PreferencesUtils; -import com.google.android.maps.mytracks.R; -import com.google.common.annotations.VisibleForTesting; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.view.View; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.RadioButton; -import android.widget.TableRow; -import android.widget.Toast; - -import java.util.ArrayList; - -/** - * A chooser to select the Google services to upload a track to. - * - * @author Jimmy Shih - */ -public class UploadServiceChooserActivity extends Activity { - - private static final int DIALOG_CHOOSER_ID = 0; - - private SendRequest sendRequest; - private AlertDialog alertDialog; - - private TableRow mapsTableRow; - private TableRow fusionTablesTableRow; - private TableRow docsTableRow; - - private CheckBox mapsCheckBox; - private CheckBox fusionTablesCheckBox; - private CheckBox docsCheckBox; - - private TableRow mapsOptionTableRow; - private RadioButton newMapRadioButton; - private RadioButton existingMapRadioButton; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - sendRequest = getIntent().getParcelableExtra(SendRequest.SEND_REQUEST_KEY); - } - - @Override - protected void onResume() { - super.onResume(); - showDialog(DIALOG_CHOOSER_ID); - } - - @Override - protected Dialog onCreateDialog(int id) { - if (id != DIALOG_CHOOSER_ID) { - return null; - } - View view = getLayoutInflater().inflate(R.layout.upload_service_chooser, null); - - mapsTableRow = (TableRow) view.findViewById(R.id.send_google_maps_row); - fusionTablesTableRow = (TableRow) view.findViewById(R.id.send_google_fusion_tables_row); - docsTableRow = (TableRow) view.findViewById(R.id.send_google_docs_row); - - mapsCheckBox = (CheckBox) view.findViewById(R.id.send_google_maps); - fusionTablesCheckBox = (CheckBox) view.findViewById(R.id.send_google_fusion_tables); - docsCheckBox = (CheckBox) view.findViewById(R.id.send_google_docs); - - mapsOptionTableRow = (TableRow) view.findViewById(R.id.send_google_maps_option_row); - newMapRadioButton = (RadioButton) view.findViewById(R.id.send_google_new_map); - existingMapRadioButton = (RadioButton) view.findViewById(R.id.send_google_existing_map); - - // Setup checkboxes - OnCheckedChangeListener checkBoxListener = new OnCheckedChangeListener() { - public void onCheckedChanged(CompoundButton button, boolean checked) { - updateStateBySelection(); - } - }; - mapsCheckBox.setOnCheckedChangeListener(checkBoxListener); - fusionTablesCheckBox.setOnCheckedChangeListener(checkBoxListener); - docsCheckBox.setOnCheckedChangeListener(checkBoxListener); - - // Setup initial state - initState(); - - // Update state based on sendRequest - updateStateBySendRequest(); - - // Update state based on current selection - updateStateBySelection(); - - alertDialog = new AlertDialog.Builder(this) - .setCancelable(true) - .setNegativeButton(R.string.generic_cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - finish(); - } - }) - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface d) { - finish(); - } - }) - .setPositiveButton(R.string.send_google_send_now, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - saveState(); - if (sendMaps() || sendFusionTables() || sendDocs()) { - startNextActivity(); - } else { - Toast.makeText(UploadServiceChooserActivity.this, - R.string.send_google_no_service_selected, Toast.LENGTH_LONG).show(); - finish(); - } - } - }) - .setTitle(R.string.send_google_title) - .setView(view) - .create(); - return alertDialog; - } - - /** - * Initializes the UI state based on the shared preferences. - */ - @VisibleForTesting - void initState() { - boolean pickExistingMap = PreferencesUtils.getBoolean( - this, R.string.pick_existing_map_key, PreferencesUtils.PICK_EXISTING_MAP_DEFAULT); - - newMapRadioButton.setChecked(!pickExistingMap); - existingMapRadioButton.setChecked(pickExistingMap); - - mapsCheckBox.setChecked(PreferencesUtils.getBoolean( - this, R.string.send_to_maps_key, PreferencesUtils.SEND_TO_MAPS_DEFAULT)); - fusionTablesCheckBox.setChecked(PreferencesUtils.getBoolean( - this, R.string.send_to_fusion_tables_key, PreferencesUtils.SEND_TO_FUSION_TABLES_DEFAULT)); - docsCheckBox.setChecked(PreferencesUtils.getBoolean( - this, R.string.send_to_docs_key, PreferencesUtils.SEND_TO_DOCS_DEFAULT)); - } - - /** - * Updates the UI state based on sendRequest. - */ - private void updateStateBySendRequest() { - if (!sendRequest.isShowAll()) { - if (sendRequest.isShowMaps()) { - mapsCheckBox.setChecked(true); - } else if (sendRequest.isShowFusionTables()) { - fusionTablesCheckBox.setChecked(true); - } else if (sendRequest.isShowDocs()) { - docsCheckBox.setChecked(true); - } - } - mapsTableRow.setVisibility(sendRequest.isShowMaps() ? View.VISIBLE : View.GONE); - fusionTablesTableRow.setVisibility(sendRequest.isShowFusionTables() ? View.VISIBLE : View.GONE); - docsTableRow.setVisibility(sendRequest.isShowDocs() ? View.VISIBLE : View.GONE); - } - - /** - * Updates the UI state based on the current selection. - */ - private void updateStateBySelection() { - mapsOptionTableRow.setVisibility(sendMaps() ? View.VISIBLE : View.GONE); - } - - /** - * Saves the UI state to the shared preferences. - */ - @VisibleForTesting - void saveState() { - PreferencesUtils.setBoolean( - this, R.string.pick_existing_map_key, existingMapRadioButton.isChecked()); - if (sendRequest.isShowAll()) { - PreferencesUtils.setBoolean(this, R.string.send_to_maps_key, sendMaps()); - PreferencesUtils.setBoolean(this, R.string.send_to_fusion_tables_key, sendFusionTables()); - PreferencesUtils.setBoolean(this, R.string.send_to_docs_key, sendDocs()); - } - } - - /** - * Returns true to send to Google Maps. - */ - private boolean sendMaps() { - return sendRequest.isShowMaps() && mapsCheckBox.isChecked(); - } - - /** - * Returns true to send to Google Fusion Tables. - */ - private boolean sendFusionTables() { - return sendRequest.isShowFusionTables() && fusionTablesCheckBox.isChecked(); - } - - /** - * Returns true to send to Google Docs. - */ - private boolean sendDocs() { - return sendRequest.isShowDocs() && docsCheckBox.isChecked(); - } - - /** - * Starts the next activity, {@link AccountChooserActivity}. - */ - @VisibleForTesting - protected void startNextActivity() { - sendStats(); - sendRequest.setSendMaps(sendMaps()); - sendRequest.setSendFusionTables(sendFusionTables()); - sendRequest.setSendDocs(sendDocs()); - sendRequest.setNewMap(!existingMapRadioButton.isChecked()); - Intent intent = IntentUtils.newIntent(this, AccountChooserActivity.class) - .putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest); - startActivity(intent); - finish(); - } - - /** - * Sends stats to Google Analytics. - */ - private void sendStats() { - ArrayList pages = new ArrayList(); - if (sendRequest.isSendMaps()) { - pages.add("/send/maps"); - } - if (sendRequest.isSendFusionTables()) { - pages.add("/send/fusion_tables"); - } - if (sendRequest.isSendDocs()) { - pages.add("/send/docs"); - } - AnalyticsUtils.sendPageViews(this, pages.toArray(new String[pages.size()])); - } - - @VisibleForTesting - AlertDialog getAlertDialog() { - return alertDialog; - } - - @VisibleForTesting - SendRequest getSendRequest() { - return sendRequest; - } -} diff --git a/MyTracks/src/com/google/android/apps/mytracks/maps/DynamicSpeedTrackPathDescriptor.java b/MyTracks/src/com/google/android/apps/mytracks/maps/DynamicSpeedTrackPathDescriptor.java index 84a07d5d8..13520ee78 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/maps/DynamicSpeedTrackPathDescriptor.java +++ b/MyTracks/src/com/google/android/apps/mytracks/maps/DynamicSpeedTrackPathDescriptor.java @@ -93,6 +93,10 @@ public class DynamicSpeedTrackPathDescriptor implements TrackPathDescriptor, return false; } Track track = MyTracksProviderUtils.Factory.get(context).getTrack(selectedTrackId); + if (track == null) { + Log.d(TAG, "No track for " + selectedTrackId); + return false; + } TripStatistics stats = track.getStatistics(); double newAverageMovingSpeed = (int) Math.floor( stats.getAverageMovingSpeed() * UnitConversions.MS_TO_KMH); diff --git a/MyTracks/src/com/google/android/apps/mytracks/maps/SingleColorTrackPathPainter.java b/MyTracks/src/com/google/android/apps/mytracks/maps/SingleColorTrackPathPainter.java index 7d89f488e..53e104575 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/maps/SingleColorTrackPathPainter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/maps/SingleColorTrackPathPainter.java @@ -51,7 +51,7 @@ public class SingleColorTrackPathPainter implements TrackPathPainter { @Override public void updatePath(Projection projection, Rect viewRect, int startLocationIdx, Boolean alwaysVisible, List points) { - path = new Path(); + path = newPath(); updatePath(projection, viewRect, startLocationIdx, alwaysVisible, points, path); } diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java b/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java index 61f34e52b..f0dbffa2e 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java @@ -66,6 +66,7 @@ import android.os.PowerManager.WakeLock; import android.os.Process; import android.util.Log; +import java.util.Locale; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ExecutorService; @@ -777,9 +778,9 @@ public class TrackRecordingService extends Service { return; } } else { - Log.d(TAG, String.format( - "Not recording. Distance to last recorded point (%f m) is less than" - + " %d m.", distanceToLastRecorded, minRecordingDistance)); + Log.d(TAG, String.format(Locale.US, + "Not recording. Distance to last recorded point (%f m) is less than %d m.", + distanceToLastRecorded, minRecordingDistance)); // Return here so that the location is NOT recorded as the last location. return; } @@ -997,7 +998,7 @@ public class TrackRecordingService extends Service { } else { int nextMarkerNumber = providerUtils.getNextMarkerNumber(recordingTrackId, true); name = nextMarkerNumber == -1 ? getString(R.string.marker_type_statistics) - : getString(R.string.marker_statistics_name_format, nextMarkerNumber); + : getString(R.string.marker_split_name_format, nextMarkerNumber); } waypoint.setName(name); waypoint.setStatistics(waypointStatsBuilder.getStatistics()); diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/AntSensorManager.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/AntSensorManager.java index 415bf78ef..3d8bce09b 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/AntSensorManager.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ant/AntSensorManager.java @@ -33,6 +33,8 @@ import android.content.Intent; import android.content.IntentFilter; import android.util.Log; +import java.util.Locale; + /** * This is the common superclass for ANT-based sensors. It handles tasks which * apply to the ANT framework as a whole, such as framework initialization and @@ -279,7 +281,7 @@ public abstract class AntSensorManager extends SensorManager { */ protected boolean handleMessage(byte messageId, byte[] messageData) { if (messageId == AntMesg.MESG_STARTUP_MESG_ID) { - Log.d(TAG, String.format( + Log.d(TAG, String.format(Locale.US, "Received startup message (reason %02x); initializing channel", new AntStartupMessage(messageData).getMessage())); setupAntSensorChannels(); @@ -376,7 +378,7 @@ public abstract class AntSensorManager extends SensorManager { private String messageToString(byte[] message) { StringBuilder out = new StringBuilder(); for (byte b : message) { - out.append(String.format("%s%02x", (out.length() == 0 ? "" : " "), b)); + out.append(String.format(Locale.US, "%s%02x", (out.length() == 0 ? "" : " "), b)); } return out.toString(); } diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/tasks/PeriodicTaskExecutor.java b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/PeriodicTaskExecutor.java index 4f108732d..228ca27c8 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/tasks/PeriodicTaskExecutor.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/PeriodicTaskExecutor.java @@ -35,7 +35,7 @@ public class PeriodicTaskExecutor { * A value greater than zero is a frequency in time. * A value less than zero is considered a frequency in distance. */ - private int taskFrequency = PreferencesUtils.PERIODIC_TASK_OFF; + private int taskFrequency = PreferencesUtils.FREQUENCY_OFF; /** * The next distance when the task should execute. @@ -75,7 +75,7 @@ public class PeriodicTaskExecutor { timerExecutor = null; } } - if (taskFrequency == PreferencesUtils.PERIODIC_TASK_OFF) { + if (taskFrequency == PreferencesUtils.FREQUENCY_OFF) { return; } diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerTask.java b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerTask.java index 08ae7cb76..36667ae80 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerTask.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerTask.java @@ -182,7 +182,7 @@ public class StatusAnnouncerTask implements PeriodicTask { speed = context.getResources().getQuantityString(speedId, getQuantityCount(s), s); } else { int paceId = metricUnits ? R.string.voice_pace_per_kilometer : R.string.voice_pace_per_mile; - speed = String.format(context.getString(paceId), getAnnounceTime((long) s)); + speed = context.getString(paceId, getAnnounceTime((long) s)); } int totalDistanceId = metricUnits ? R.plurals.voiceTotalDistanceKilometers diff --git a/MyTracks/src/com/google/android/apps/mytracks/settings/AbstractSettingsActivity.java b/MyTracks/src/com/google/android/apps/mytracks/settings/AbstractSettingsActivity.java index 12f315107..78b5af181 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/settings/AbstractSettingsActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/settings/AbstractSettingsActivity.java @@ -36,13 +36,13 @@ public class AbstractSettingsActivity extends PreferenceActivity { private BackupPreferencesListener backupPreferencesListener; + @SuppressWarnings("deprecation") @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM); ApiAdapterFactory.getApiAdapter().configureActionBarHomeAsUp(this); - @SuppressWarnings("deprecation") PreferenceManager preferenceManager = getPreferenceManager(); preferenceManager.setSharedPreferencesName(Constants.SETTINGS_NAME); preferenceManager.setSharedPreferencesMode(Context.MODE_PRIVATE); @@ -63,10 +63,10 @@ public class AbstractSettingsActivity extends PreferenceActivity { return true; } + @SuppressWarnings("deprecation") @Override protected void onDestroy() { super.onDestroy(); - @SuppressWarnings("deprecation") PreferenceManager preferenceManager = getPreferenceManager(); preferenceManager.getSharedPreferences() .unregisterOnSharedPreferenceChangeListener(backupPreferencesListener); diff --git a/MyTracks/src/com/google/android/apps/mytracks/settings/RecordingSettingsActivity.java b/MyTracks/src/com/google/android/apps/mytracks/settings/RecordingSettingsActivity.java index ccbea807b..656a3c0dd 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/settings/RecordingSettingsActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/settings/RecordingSettingsActivity.java @@ -39,14 +39,6 @@ public class RecordingSettingsActivity extends AbstractSettingsActivity { boolean metricUnits = PreferencesUtils.getBoolean( this, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT); - ListPreference announcementFrequencyListPreference = (ListPreference) findPreference( - getString(R.string.announcement_frequency_key)); - announcementFrequencyListPreference.setEntries(getPeriodicTaskDisplayOptions(metricUnits)); - - ListPreference splitFrequencyListPreference = (ListPreference) findPreference( - getString(R.string.split_frequency_key)); - splitFrequencyListPreference.setEntries(getPeriodicTaskDisplayOptions(metricUnits)); - ListPreference minRecordingIntervalListPreference = (ListPreference) findPreference( getString(R.string.min_recording_interval_key)); minRecordingIntervalListPreference.setEntries(getMinRecordingIntervalDisplayOptions()); @@ -70,28 +62,6 @@ public class RecordingSettingsActivity extends AbstractSettingsActivity { autoResumeTrackTimeoutListPreference.setEntries(getAutoResumeTrackTimeoutDisplayOptions()); } - /** - * Gets the periodic task display options. - * - * @param metricUnits true to display metric units - */ - private String[] getPeriodicTaskDisplayOptions(boolean metricUnits) { - String[] values = getResources().getStringArray(R.array.periodic_task_values); - String[] options = new String[values.length]; - for (int i = 0; i < values.length; i++) { - int value = Integer.parseInt(values[i]); - if (value == PreferencesUtils.PERIODIC_TASK_OFF) { - options[i] = getString(R.string.value_off); - } else if (value < 0) { - options[i] = getString(metricUnits ? R.string.value_integer_kilometer - : R.string.value_integer_mile, Math.abs(value)); - } else { - options[i] = getString(R.string.value_integer_minute, value); - } - } - return options; - } - /** * Gets the min recording interval display options. */ diff --git a/MyTracks/src/com/google/android/apps/mytracks/settings/SensorSettingsActivity.java b/MyTracks/src/com/google/android/apps/mytracks/settings/SensorSettingsActivity.java index 88f9b14e7..303de6ea9 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/settings/SensorSettingsActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/settings/SensorSettingsActivity.java @@ -120,8 +120,8 @@ public class SensorSettingsActivity extends AbstractSettingsActivity { /** * Updates the bluetooth sensor list preference. */ + @SuppressWarnings("deprecation") private void updateBluetoothSensorListPreference() { - @SuppressWarnings("deprecation") ListPreference bluetoothSensorListPreference = (ListPreference) findPreference( getString(R.string.bluetooth_sensor_key)); List entries = new ArrayList(); diff --git a/MyTracks/src/com/google/android/apps/mytracks/settings/SharingSettingsActivity.java b/MyTracks/src/com/google/android/apps/mytracks/settings/SharingSettingsActivity.java index a322ce262..eb16dead6 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/settings/SharingSettingsActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/settings/SharingSettingsActivity.java @@ -16,16 +16,23 @@ package com.google.android.apps.mytracks.settings; +import com.google.android.apps.mytracks.Constants; import com.google.android.apps.mytracks.util.DialogUtils; import com.google.android.maps.mytracks.R; +import android.accounts.Account; +import android.accounts.AccountManager; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; import android.preference.CheckBoxPreference; +import android.preference.ListPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; +import java.util.ArrayList; +import java.util.List; + /** * An activity for accessing the sharing settings. * @@ -56,6 +63,21 @@ public class SharingSettingsActivity extends AbstractSettingsActivity { } } }); + + ListPreference sharingAccountListPreference = (ListPreference) findPreference( + getString(R.string.sharing_account_key)); + List entries = new ArrayList(); + Account[] accounts = AccountManager.get(this).getAccountsByType(Constants.ACCOUNT_TYPE); + for (Account account : accounts) { + entries.add(account.name); + } + + sharingAccountListPreference.setEntries(entries.toArray(new CharSequence[entries.size()])); + sharingAccountListPreference.setEntryValues(entries.toArray( + new CharSequence[entries.size()])); + if (entries.size() == 1) { + sharingAccountListPreference.setValueIndex(0); + } } @Override diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/Api11Adapter.java b/MyTracks/src/com/google/android/apps/mytracks/util/Api11Adapter.java index 87c343190..ba382b93a 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/Api11Adapter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/Api11Adapter.java @@ -17,6 +17,7 @@ package com.google.android.apps.mytracks.util; import com.google.android.apps.mytracks.ContextualActionModeCallback; +import com.google.android.maps.mytracks.R; import android.annotation.TargetApi; import android.app.Activity; @@ -55,7 +56,6 @@ public class Api11Adapter extends Api10Adapter { @Override public void configureListViewContextualMenu(final Activity activity, ListView listView, - final int menuId, final int actionModeTitleId, final ContextualActionModeCallback contextualActionModeCallback) { listView.setOnItemLongClickListener(new OnItemLongClickListener() { ActionMode actionMode; @@ -68,7 +68,7 @@ public class Api11Adapter extends Api10Adapter { actionMode = activity.startActionMode(new ActionMode.Callback() { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { - mode.getMenuInflater().inflate(menuId, menu); + mode.getMenuInflater().inflate(R.menu.list_context_menu, menu); return true; } @Override @@ -86,7 +86,7 @@ public class Api11Adapter extends Api10Adapter { return contextualActionModeCallback.onClick(item.getItemId(), position, id); } }); - TextView textView = (TextView) view.findViewById(actionModeTitleId); + TextView textView = (TextView) view.findViewById(R.id.list_item_name); if (textView != null) { actionMode.setTitle(textView.getText()); } diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/Api7Adapter.java b/MyTracks/src/com/google/android/apps/mytracks/util/Api7Adapter.java index 79e32effb..78233be64 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/Api7Adapter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/Api7Adapter.java @@ -118,8 +118,8 @@ public class Api7Adapter implements ApiAdapter { } @Override - public void configureListViewContextualMenu(Activity activity, ListView listView, int menuId, - int actionModeTitleId, ContextualActionModeCallback contextualActionModeCallback) { + public void configureListViewContextualMenu(Activity activity, ListView listView, + ContextualActionModeCallback contextualActionModeCallback) { activity.registerForContextMenu(listView); } diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/ApiAdapter.java b/MyTracks/src/com/google/android/apps/mytracks/util/ApiAdapter.java index 18146a5e9..7eb717401 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/ApiAdapter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/ApiAdapter.java @@ -134,14 +134,11 @@ public interface ApiAdapter { * * @param activity the activity * @param listView the list view - * @param menuId the menu resource id - * @param actionModeTitleId the id of the list view item TextView to be used - * as the action mode title * @param contextualActionModeCallback the callback when an item is selected * in the contextual action mode */ - public void configureListViewContextualMenu(Activity activity, ListView listView, int menuId, - int actionModeTitleId, ContextualActionModeCallback contextualActionModeCallback); + public void configureListViewContextualMenu(Activity activity, ListView listView, + ContextualActionModeCallback contextualActionModeCallback); /** * Configures the search widget. diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/IntentUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/IntentUtils.java index e38b55cff..cefec245d 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/IntentUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/IntentUtils.java @@ -16,8 +16,18 @@ package com.google.android.apps.mytracks.util; +import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl; +import com.google.android.apps.mytracks.content.MyTracksProviderUtils; +import com.google.android.apps.mytracks.content.Track; +import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat; +import com.google.android.maps.mytracks.R; + +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.net.Uri; + +import java.io.File; /** * Utilities for creating intents. @@ -26,6 +36,9 @@ import android.content.Intent; */ public class IntentUtils { + public static final String TEXT_PLAIN_TYPE = "text/plain"; + private static final String TWITTER_PACKAGE_NAME = "com.twitter.android"; + private IntentUtils() {} /** @@ -39,4 +52,52 @@ public class IntentUtils { return new Intent(context, cls).addFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); } + + /** + * Creates an intent to share a track url with an app. + * + * @param context the context + * @param trackId the track id + * @param trackUrl the track url + * @param packageName the sharing app package name + * @param className the sharing app class name + */ + public static final Intent newShareUrlIntent( + Context context, long trackId, String trackUrl, String packageName, String className) { + Track track = MyTracksProviderUtils.Factory.get(context).getTrack(trackId); + String trackDescription = track == null ? "" + : new DescriptionGeneratorImpl(context).generateTrackDescription(track, null, null, false); + + return new Intent(Intent.ACTION_SEND) + .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) + .putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.share_track_subject)) + .putExtra(Intent.EXTRA_TEXT, TWITTER_PACKAGE_NAME.equals(packageName) + ? trackUrl + : context.getString(R.string.share_track_share_url_body, trackUrl, trackDescription)) + .setComponent(new ComponentName(packageName, className)) + .setType(TEXT_PLAIN_TYPE); + } + + /** + * Creates an intent to share a track file with an app. + * + * @param context the context + * @param trackId the track id + * @param filePath the file path + * @param trackFileFormat the track file format + */ + public static final Intent newShareFileIntent( + Context context, long trackId, String filePath, TrackFileFormat trackFileFormat) { + Track track = MyTracksProviderUtils.Factory.get(context).getTrack(trackId); + String trackDescription = track == null ? "" + : new DescriptionGeneratorImpl(context).generateTrackDescription(track, null, null, false); + + return new Intent(Intent.ACTION_SEND) + .putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(filePath))) + .putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.share_track_subject)) + .putExtra(Intent.EXTRA_TEXT, + context.getString(R.string.share_track_share_file_body, trackDescription)) + .putExtra(context.getString(R.string.track_id_broadcast_extra), trackId) + .setType(trackFileFormat.getMimeType()); + } } diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/PreferencesUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/PreferencesUtils.java index 1c64c04b3..6ee57feca 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/PreferencesUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/PreferencesUtils.java @@ -52,6 +52,7 @@ public class PreferencesUtils { public static final String DEFAULT_ACTIVITY_DEFAULT = ""; public static final boolean DEFAULT_MAP_PUBLIC_DEFAULT = true; + public static final int FREQUENCY_OFF = 0; public static final int MAX_RECORDING_DISTANCE_DEFAULT = 200; public static final boolean METRIC_UNITS_DEFAULT = true; public static final int MIN_RECORDING_DISTANCE_DEFAULT = 5; @@ -64,16 +65,14 @@ public class PreferencesUtils { public static final int MIN_REQUIRED_ACCURACY_EXCELLENT = 10; public static final int MIN_REQUIRED_ACCURACY_POOR = 5000; - public static final int PERIODIC_TASK_OFF = 0; public static final boolean PICK_EXISTING_MAP_DEFAULT = false; - public static final String PREFERRED_ACCOUNT_DEFAULT = ""; public static final long RECORDING_TRACK_ID_DEFAULT = -1L; public static final boolean REPORT_SPEED_DEFAULT = true; public static final long SELECTED_TRACK_ID_DEFAULT = -1L; public static final boolean SEND_TO_DOCS_DEFAULT = true; public static final boolean SEND_TO_FUSION_TABLES_DEFAULT = true; public static final boolean SEND_TO_MAPS_DEFAULT = true; - public static final boolean SHARE_URL_ONLY_DEFAULT = false; + public static final String SHARING_ACCOUNT_DEFAULT = ""; public static final boolean SHOW_CHECK_UNITS_DIALOG_DEFAULT = true; public static final boolean SHOW_WELCOME_DIALOG_DEFAULT = true; public static final int SPLIT_FREQUENCY_DEFAULT = 0; diff --git a/MyTracksLib/src/com/google/android/apps/mytracks/content/DescriptionGenerator.java b/MyTracksLib/src/com/google/android/apps/mytracks/content/DescriptionGenerator.java index 083354de1..7cc3cb5c0 100644 --- a/MyTracksLib/src/com/google/android/apps/mytracks/content/DescriptionGenerator.java +++ b/MyTracksLib/src/com/google/android/apps/mytracks/content/DescriptionGenerator.java @@ -31,9 +31,10 @@ public interface DescriptionGenerator { * @param track the track * @param distances a vector of distances to generate the elevation chart * @param elevations a vector of elevations to generate the elevation chart + * @param html true to output html, false to output plain text */ public String generateTrackDescription( - Track track, Vector distances, Vector elevations); + Track track, Vector distances, Vector elevations, boolean html); /** * Generate a waypoint description. diff --git a/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java b/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java index 7bcee4994..4109a6c96 100644 --- a/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java +++ b/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java @@ -911,15 +911,13 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils { String selection; String[] selectionArgs; if (minWaypointId > 0) { - selection = String.format("%s = ? AND %s >= ?", - WaypointsColumns.TRACKID, - WaypointsColumns._ID); + selection = WaypointsColumns.TRACKID + "=? AND " + WaypointsColumns._ID + ">=?"; selectionArgs = new String[] { Long.toString(trackId), Long.toString(minWaypointId) }; } else { - selection = String.format("%s=?", WaypointsColumns.TRACKID); + selection = WaypointsColumns.TRACKID + "=?"; selectionArgs = new String[] { Long.toString(trackId) }; } diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImplTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImplTest.java index 019ac51e1..b3ca5a08c 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImplTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/content/DescriptionGeneratorImplTest.java @@ -40,7 +40,7 @@ public class DescriptionGeneratorImplTest extends AndroidTestCase { /** * Tests {@link DescriptionGeneratorImpl#generateTrackDescription(Track, - * java.util.Vector, java.util.Vector)}. + * java.util.Vector, java.util.Vector, boolean)}. */ public void testGenerateTrackDescription() { Track track = new Track(); @@ -59,6 +59,9 @@ public class DescriptionGeneratorImplTest extends AndroidTestCase { track.setCategory("hiking"); String expected = "Created by" + " My Tracks on Android.

" + + "Name: -
" + + "Activity type: hiking
" + + "Description: -
" + "Total distance: 20.00 km (12.4 mi)
" + "Total time: 10:00
" + "Moving time: 05:00
" @@ -73,9 +76,8 @@ public class DescriptionGeneratorImplTest extends AndroidTestCase { + "Elevation gain: 6000 m (19685 ft)
" + "Max grade: 42 %
" + "Min grade: 11 %
" - + "Recorded: " + StringUtils.formatDateTime(getContext(), START_TIME) + "
" - + "Activity type: hiking
"; - assertEquals(expected, descriptionGenerator.generateTrackDescription(track, null, null)); + + "Recorded: " + StringUtils.formatDateTime(getContext(), START_TIME) + "
"; + assertEquals(expected, descriptionGenerator.generateTrackDescription(track, null, null, true)); } /** diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/KmlTrackWriterTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/KmlTrackWriterTest.java index 93c5a9aa2..9ebefcdbb 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/KmlTrackWriterTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/KmlTrackWriterTest.java @@ -43,7 +43,7 @@ public class KmlTrackWriterTest extends TrackFormatWriterTest { private class FakeDescriptionGenerator implements DescriptionGenerator { @Override public String generateTrackDescription( - Track aTrack, Vector distances, Vector elevations) { + Track aTrack, Vector distances, Vector elevations, boolean html) { return FULL_TRACK_DESCRIPTION; } diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/fusiontables/SendFusionTablesActivityTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/fusiontables/SendFusionTablesActivityTest.java index 09b095a5f..800053ba8 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/fusiontables/SendFusionTablesActivityTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/fusiontables/SendFusionTablesActivityTest.java @@ -34,7 +34,7 @@ public class SendFusionTablesActivityTest extends AndroidTestCase { @Override protected void setUp() throws Exception { super.setUp(); - sendRequest = new SendRequest(1L, true, false, true); + sendRequest = new SendRequest(1L); sendFusionTablesActivity = new SendFusionTablesActivity(); } diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/maps/SendMapsActivityTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/maps/SendMapsActivityTest.java index d2646609a..97f2c0982 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/maps/SendMapsActivityTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/maps/SendMapsActivityTest.java @@ -35,7 +35,7 @@ public class SendMapsActivityTest extends AndroidTestCase { @Override protected void setUp() throws Exception { super.setUp(); - sendRequest = new SendRequest(1L, true, false, true); + sendRequest = new SendRequest(1L); sendMapsActivity = new SendMapsActivity(); } diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/maps/SendMapsAsyncTaskTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/maps/SendMapsAsyncTaskTest.java index 65f4fd92c..904114791 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/maps/SendMapsAsyncTaskTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/maps/SendMapsAsyncTaskTest.java @@ -86,7 +86,7 @@ public class SendMapsAsyncTaskTest extends AndroidTestCase { prepareAndUploadPointsCounter = 0; sendMapsActivityMock = AndroidMock.createMock(SendMapsActivity.class); myTracksProviderUtilsMock = AndroidMock.createMock(MyTracksProviderUtils.class); - sendRequest = new SendRequest(TRACK_ID, false, true, false); + sendRequest = new SendRequest(TRACK_ID); AndroidMock.expect(sendMapsActivityMock.getApplicationContext()).andReturn(getContext()); } diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/sendtogoogle/SendRequestTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/sendtogoogle/SendRequestTest.java index 0ad6bfa1b..f9ff8ab5d 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/sendtogoogle/SendRequestTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/sendtogoogle/SendRequestTest.java @@ -35,7 +35,7 @@ public class SendRequestTest extends AndroidTestCase { @Override protected void setUp() throws Exception { super.setUp(); - sendRequest = new SendRequest(1, true, true, true); + sendRequest = new SendRequest(1); } /** @@ -46,44 +46,6 @@ public class SendRequestTest extends AndroidTestCase { assertEquals(1, sendRequest.getTrackId()); } - /** - * Tests the method {@link SendRequest#isShowMaps()}. The value should be set - * to true when it is initialed in setup method. - */ - public void testIsShowMaps() { - assertEquals(true, sendRequest.isShowMaps()); - } - - /** - * Tests the method {@link SendRequest#isShowFusionTables()}. The value should - * be set to true when it is initialed in setup method. - */ - public void testIsShowFusionTables() { - assertEquals(true, sendRequest.isShowFusionTables()); - } - - /** - * Tests the method {@link SendRequest#isShowDocs()}. The value should be set - * to true when it is initialed in setup method. - */ - public void testIsShowDocs() { - assertEquals(true, sendRequest.isShowDocs()); - } - - public void testIsShowAll() { - assertEquals(true, sendRequest.isShowAll()); - sendRequest = new SendRequest(1, false, true, true); - assertEquals(false, sendRequest.isShowAll()); - sendRequest = new SendRequest(1, true, false, true); - assertEquals(false, sendRequest.isShowAll()); - sendRequest = new SendRequest(1, true, true, false); - assertEquals(false, sendRequest.isShowAll()); - sendRequest = new SendRequest(1, false, true, false); - assertEquals(false, sendRequest.isShowAll()); - sendRequest = new SendRequest(1, false, false, false); - assertEquals(false, sendRequest.isShowAll()); - } - public void testIsSendMaps() { assertEquals(false, sendRequest.isSendMaps()); sendRequest.setSendMaps(true); @@ -174,120 +136,114 @@ public class SendRequestTest extends AndroidTestCase { * Tests SendRequest.CREATOR.createFromParcel when all values are true. */ public void testCreateFromParcel_true() { - Parcel sourceParcel = Parcel.obtain(); - sourceParcel.setDataPosition(0); - sourceParcel.writeLong(2); - sourceParcel.writeByte((byte) 1); - sourceParcel.writeByte((byte) 1); - sourceParcel.writeByte((byte) 1); - sourceParcel.writeByte((byte) 1); - sourceParcel.writeByte((byte) 1); - sourceParcel.writeByte((byte) 1); - sourceParcel.writeByte((byte) 1); + Parcel parcel = Parcel.obtain(); + parcel.setDataPosition(0); + parcel.writeLong(2); + parcel.writeString(""); + parcel.writeString(""); + parcel.writeByte((byte) 1); + parcel.writeByte((byte) 1); + parcel.writeByte((byte) 1); + parcel.writeByte((byte) 1); Account account = new Account(ACCOUNTNAME, ACCOUNTYPE); - sourceParcel.writeParcelable(account, 0); - sourceParcel.writeString(MAPID); - sourceParcel.writeByte((byte) 1); - sourceParcel.writeByte((byte) 1); - sourceParcel.writeByte((byte) 1); - sourceParcel.setDataPosition(0); - sendRequest = SendRequest.CREATOR.createFromParcel(sourceParcel); + parcel.writeParcelable(account, 0); + parcel.writeString(MAPID); + parcel.writeByte((byte) 1); + parcel.writeByte((byte) 1); + parcel.writeByte((byte) 1); + parcel.setDataPosition(0); + sendRequest = SendRequest.CREATOR.createFromParcel(parcel); assertEquals(2, sendRequest.getTrackId()); - assertEquals(true, sendRequest.isShowMaps()); - assertEquals(true, sendRequest.isShowFusionTables()); - assertEquals(true, sendRequest.isShowDocs()); - assertEquals(true, sendRequest.isSendMaps()); - assertEquals(true, sendRequest.isSendFusionTables()); - assertEquals(true, sendRequest.isSendDocs()); - assertEquals(true, sendRequest.isNewMap()); + assertEquals("", sendRequest.getSharingAppPackageName()); + assertEquals("", sendRequest.getSharingAppClassName()); + assertTrue(sendRequest.isSendMaps()); + assertTrue(sendRequest.isSendFusionTables()); + assertTrue(sendRequest.isSendDocs()); + assertTrue(sendRequest.isNewMap()); assertEquals(account, sendRequest.getAccount()); assertEquals(MAPID, sendRequest.getMapId()); - assertEquals(true, sendRequest.isMapsSuccess()); - assertEquals(true, sendRequest.isFusionTablesSuccess()); - assertEquals(true, sendRequest.isDocsSuccess()); + assertTrue(sendRequest.isMapsSuccess()); + assertTrue(sendRequest.isFusionTablesSuccess()); + assertTrue(sendRequest.isDocsSuccess()); } /** * Tests SendRequest.CREATOR.createFromParcel when all values are false. */ public void testCreateFromParcel_false() { - Parcel sourceParcel = Parcel.obtain(); - sourceParcel.setDataPosition(0); - sourceParcel.writeLong(4); - sourceParcel.writeByte((byte) 0); - sourceParcel.writeByte((byte) 0); - sourceParcel.writeByte((byte) 0); - sourceParcel.writeByte((byte) 0); - sourceParcel.writeByte((byte) 0); - sourceParcel.writeByte((byte) 0); - sourceParcel.writeByte((byte) 0); + Parcel parcel = Parcel.obtain(); + parcel.setDataPosition(0); + parcel.writeLong(4); + parcel.writeString(null); + parcel.writeString(null); + parcel.writeByte((byte) 0); + parcel.writeByte((byte) 0); + parcel.writeByte((byte) 0); + parcel.writeByte((byte) 0); Account account = new Account(ACCOUNTNAME, ACCOUNTYPE); - sourceParcel.writeParcelable(account, 0); - sourceParcel.writeString(MAPID); - sourceParcel.writeByte((byte) 0); - sourceParcel.writeByte((byte) 0); - sourceParcel.writeByte((byte) 0); - sourceParcel.setDataPosition(0); - sendRequest = SendRequest.CREATOR.createFromParcel(sourceParcel); + parcel.writeParcelable(account, 0); + parcel.writeString(MAPID); + parcel.writeByte((byte) 0); + parcel.writeByte((byte) 0); + parcel.writeByte((byte) 0); + parcel.setDataPosition(0); + sendRequest = SendRequest.CREATOR.createFromParcel(parcel); assertEquals(4, sendRequest.getTrackId()); - assertEquals(false, sendRequest.isShowMaps()); - assertEquals(false, sendRequest.isShowFusionTables()); - assertEquals(false, sendRequest.isShowDocs()); - assertEquals(false, sendRequest.isSendMaps()); - assertEquals(false, sendRequest.isSendFusionTables()); - assertEquals(false, sendRequest.isSendDocs()); - assertEquals(false, sendRequest.isNewMap()); + assertNull(sendRequest.getSharingAppPackageName()); + assertNull(sendRequest.getSharingAppClassName()); + assertFalse(sendRequest.isSendMaps()); + assertFalse(sendRequest.isSendFusionTables()); + assertFalse(sendRequest.isSendDocs()); + assertFalse(sendRequest.isNewMap()); assertEquals(account, sendRequest.getAccount()); assertEquals(MAPID, sendRequest.getMapId()); - assertEquals(false, sendRequest.isMapsSuccess()); - assertEquals(false, sendRequest.isFusionTablesSuccess()); - assertEquals(false, sendRequest.isDocsSuccess()); + assertFalse(sendRequest.isMapsSuccess()); + assertFalse(sendRequest.isFusionTablesSuccess()); + assertFalse(sendRequest.isDocsSuccess()); } /** - * Tests {@link SendRequest#writeToParcel(Parcel, int)} when all input values - * are true or affirmative. + * Tests {@link SendRequest#writeToParcel(Parcel, int)} with default values. */ - public void testWriteToParcel_allTrue() { - sendRequest = new SendRequest(1, false, false, false); - Parcel parcelWrite1st = Parcel.obtain(); - parcelWrite1st.setDataPosition(0); - sendRequest.writeToParcel(parcelWrite1st, 1); - parcelWrite1st.setDataPosition(0); - long trackId = parcelWrite1st.readLong(); - boolean showMaps = parcelWrite1st.readByte() == 1; - boolean showFusionTables = parcelWrite1st.readByte() == 1; - boolean showDocs = parcelWrite1st.readByte() == 1; - boolean sendMaps = parcelWrite1st.readByte() == 1; - boolean sendFusionTables = parcelWrite1st.readByte() == 1; - boolean sendDocs = parcelWrite1st.readByte() == 1; - boolean newMap = parcelWrite1st.readByte() == 1; - Parcelable account = parcelWrite1st.readParcelable(null); - String mapId = parcelWrite1st.readString(); - boolean mapsSuccess = parcelWrite1st.readByte() == 1; - boolean fusionTablesSuccess = parcelWrite1st.readByte() == 1; - boolean docsSuccess = parcelWrite1st.readByte() == 1; + public void testWriteToParcel_default() { + sendRequest = new SendRequest(1); + Parcel parcel = Parcel.obtain(); + parcel.setDataPosition(0); + sendRequest.writeToParcel(parcel, 1); + parcel.setDataPosition(0); + long trackId = parcel.readLong(); + String sharingAppPackageName = parcel.readString(); + String sharingAppClassName = parcel.readString(); + boolean sendMaps = parcel.readByte() == 1; + boolean sendFusionTables = parcel.readByte() == 1; + boolean sendDocs = parcel.readByte() == 1; + boolean newMap = parcel.readByte() == 1; + Parcelable account = parcel.readParcelable(null); + String mapId = parcel.readString(); + boolean mapsSuccess = parcel.readByte() == 1; + boolean fusionTablesSuccess = parcel.readByte() == 1; + boolean docsSuccess = parcel.readByte() == 1; assertEquals(1, trackId); - assertEquals(false, showMaps); - assertEquals(false, showFusionTables); - assertEquals(false, showDocs); - assertEquals(false, sendMaps); - assertEquals(false, sendFusionTables); - assertEquals(false, sendDocs); - assertEquals(false, newMap); - assertEquals(null, account); - assertEquals(null, mapId); - assertEquals(false, mapsSuccess); - assertEquals(false, fusionTablesSuccess); - assertEquals(false, docsSuccess); + assertNull(sharingAppPackageName); + assertNull(sharingAppClassName); + assertFalse(sendMaps); + assertFalse(sendFusionTables); + assertFalse(sendDocs); + assertFalse(newMap); + assertNull(account); + assertNull(mapId); + assertFalse(mapsSuccess); + assertFalse(fusionTablesSuccess); + assertFalse(docsSuccess); } /** - * Tests {@link SendRequest#writeToParcel(Parcel, int)} when all input values - * are false or negative. + * Tests {@link SendRequest#writeToParcel(Parcel, int)}. */ - public void testWriteToParcel_allFalse() { - sendRequest = new SendRequest(4, true, true, true); + public void testWriteToParcel() { + sendRequest = new SendRequest(4); + sendRequest.setSharingAppPackageName("package"); + sendRequest.setSharingAppClassName("class"); sendRequest.setSendMaps(true); sendRequest.setSendFusionTables(true); sendRequest.setSendDocs(true); @@ -298,36 +254,33 @@ public class SendRequestTest extends AndroidTestCase { sendRequest.setMapsSuccess(true); sendRequest.setFusionTablesSuccess(true); sendRequest.setDocsSuccess(true); - Parcel parcelWrite2nd = Parcel.obtain(); - parcelWrite2nd.setDataPosition(0); - sendRequest.writeToParcel(parcelWrite2nd, 1); - parcelWrite2nd.setDataPosition(0); - long trackId = parcelWrite2nd.readLong(); - boolean showMaps = parcelWrite2nd.readByte() == 1; - boolean showFusionTables = parcelWrite2nd.readByte() == 1; - boolean showDocs = parcelWrite2nd.readByte() == 1; - boolean sendMaps = parcelWrite2nd.readByte() == 1; - boolean sendFusionTables = parcelWrite2nd.readByte() == 1; - boolean sendDocs = parcelWrite2nd.readByte() == 1; - boolean newMap = parcelWrite2nd.readByte() == 1; - Parcelable account = parcelWrite2nd.readParcelable(null); - String mapId = parcelWrite2nd.readString(); - boolean mapsSuccess = parcelWrite2nd.readByte() == 1; - boolean fusionTablesSuccess = parcelWrite2nd.readByte() == 1; - boolean docsSuccess = parcelWrite2nd.readByte() == 1; + Parcel parcel = Parcel.obtain(); + parcel.setDataPosition(0); + sendRequest.writeToParcel(parcel, 1); + parcel.setDataPosition(0); + long trackId = parcel.readLong(); + String sharingAppPackageName = parcel.readString(); + String sharingAppClassName = parcel.readString(); + boolean sendMaps = parcel.readByte() == 1; + boolean sendFusionTables = parcel.readByte() == 1; + boolean sendDocs = parcel.readByte() == 1; + boolean newMap = parcel.readByte() == 1; + Parcelable account = parcel.readParcelable(null); + String mapId = parcel.readString(); + boolean mapsSuccess = parcel.readByte() == 1; + boolean fusionTablesSuccess = parcel.readByte() == 1; + boolean docsSuccess = parcel.readByte() == 1; assertEquals(4, trackId); - assertEquals(true, showMaps); - assertEquals(true, showFusionTables); - assertEquals(true, showDocs); - assertEquals(true, sendMaps); - assertEquals(true, sendFusionTables); - assertEquals(true, sendDocs); - assertEquals(true, newMap); + assertEquals("package", sharingAppPackageName); + assertEquals("class", sharingAppClassName); + assertTrue(sendMaps); + assertTrue(sendFusionTables); + assertTrue(sendDocs); + assertTrue(newMap); assertEquals(accountNew, account); assertEquals(MAPID, mapId); - assertEquals(true, mapsSuccess); - assertEquals(true, fusionTablesSuccess); - assertEquals(true, docsSuccess); + assertTrue(mapsSuccess); + assertTrue(fusionTablesSuccess); + assertTrue(docsSuccess); } - } diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadResultActivityTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadResultActivityTest.java index b363ad9c5..f56de3b42 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadResultActivityTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadResultActivityTest.java @@ -97,7 +97,7 @@ public class UploadResultActivityTest private void initialActivity(boolean isSendMaps, boolean isSendFusionTables, boolean isSendDocs, boolean isMapsSuccess, boolean isFusionTablesSuccess, boolean isDocsSuccess) { Intent intent = new Intent(); - SendRequest sendRequest = new SendRequest(1L, true, true, true); + SendRequest sendRequest = new SendRequest(1L); sendRequest.setSendMaps(isSendMaps); sendRequest.setSendFusionTables(isSendFusionTables); sendRequest.setSendDocs(isSendDocs); diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadServiceChooserActivityTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadServiceChooserActivityTest.java deleted file mode 100644 index ff72cfb5b..000000000 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/sendtogoogle/UploadServiceChooserActivityTest.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.android.apps.mytracks.io.sendtogoogle; - -import com.google.android.apps.mytracks.util.PreferencesUtils; -import com.google.android.maps.mytracks.R; - -import android.app.Instrumentation; -import android.content.Intent; -import android.test.ActivityInstrumentationTestCase2; -import android.widget.CheckBox; -import android.widget.RadioButton; - -/** - * Tests the {@link UploadServiceChooserActivity}. - * - * @author Youtao Liu - */ -public class UploadServiceChooserActivityTest extends - ActivityInstrumentationTestCase2 { - - private Instrumentation instrumentation; - private UploadServiceChooserActivity uploadServiceChooserActivity; - - public UploadServiceChooserActivityTest() { - super(UploadServiceChooserActivity.class); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - instrumentation = getInstrumentation(); - } - - /** - * Tests the logic to display all options. - */ - public void testOnCreateDialog_displayAll() { - // Initials activity to display all send items. - initialActivity(true, true, true); - instrumentation.waitForIdleSync(); - assertTrue(getMapsCheckBox().isShown()); - assertTrue(getFusionTablesCheckBox().isShown()); - assertTrue(getDocsCheckBox().isShown()); - - // Clicks to disable all send items. - uploadServiceChooserActivity.runOnUiThread(new Runnable() { - public void run() { - if (getMapsCheckBox().isChecked()) { - getMapsCheckBox().performClick(); - } - if (getFusionTablesCheckBox().isChecked()) { - getFusionTablesCheckBox().performClick(); - } - if (getDocsCheckBox().isChecked()) { - getDocsCheckBox().performClick(); - } - } - }); - instrumentation.waitForIdleSync(); - assertTrue(getMapsCheckBox().isShown()); - assertTrue(getFusionTablesCheckBox().isShown()); - assertTrue(getDocsCheckBox().isShown()); - - assertFalse(getNewMapRadioButton().isShown()); - assertFalse(getExistingMapRadioButton().isShown()); - } - - /** - * Tests the logic to display only the "Send to Google Maps" option. - */ - public void testOnCreateDialog_displayOne() { - // Initials activity to display all send items. - initialActivity(true, false, false); - instrumentation.waitForIdleSync(); - assertTrue(getMapsCheckBox().isShown()); - - // Clicks to enable this items. - uploadServiceChooserActivity.runOnUiThread(new Runnable() { - public void run() { - if (!getMapsCheckBox().isChecked()) { - getMapsCheckBox().performClick(); - } - } - }); - instrumentation.waitForIdleSync(); - assertTrue(getMapsCheckBox().isShown()); - assertTrue(getNewMapRadioButton().isShown()); - assertTrue(getExistingMapRadioButton().isShown()); - } - - /** - * Tests the logic to display no option. - */ - public void testOnCreateDialog_displayNone() { - initialActivity(false, false, false); - assertFalse(getMapsCheckBox().isShown()); - assertFalse(getFusionTablesCheckBox().isShown()); - assertFalse(getDocsCheckBox().isShown()); - } - - /** - * Tests the logic to initial state of check box to unchecked. This test cover - * code in method {@link UploadServiceChooserActivity#onCreateDialog(int)}, - * {@link UploadServiceChooserActivity#initState()}. - */ - public void testOnCreateDialog_initStateUnchecked() { - initialActivity(true, true, true); - // Initial all values to false in SharedPreferences. - PreferencesUtils.setBoolean(uploadServiceChooserActivity, R.string.send_to_maps_key, false); - PreferencesUtils.setBoolean( - uploadServiceChooserActivity, R.string.send_to_fusion_tables_key, false); - PreferencesUtils.setBoolean(uploadServiceChooserActivity, R.string.send_to_docs_key, false); - uploadServiceChooserActivity.runOnUiThread(new Runnable() { - public void run() { - uploadServiceChooserActivity.initState(); - } - }); - instrumentation.waitForIdleSync(); - assertFalse(getMapsCheckBox().isChecked()); - assertFalse(getFusionTablesCheckBox().isChecked()); - assertFalse(getDocsCheckBox().isChecked()); - } - - /** - * Tests the logic to initial state of check box to checked. This test cover - * code in method {@link UploadServiceChooserActivity#onCreateDialog(int)}, - * {@link UploadServiceChooserActivity#initState()}. - */ - public void testOnCreateDialog_initStateChecked() { - initialActivity(true, true, true); - // Initial all values to true in SharedPreferences. - PreferencesUtils.setBoolean(uploadServiceChooserActivity, R.string.pick_existing_map_key, true); - PreferencesUtils.setBoolean(uploadServiceChooserActivity, R.string.send_to_maps_key, true); - PreferencesUtils.setBoolean( - uploadServiceChooserActivity, R.string.send_to_fusion_tables_key, true); - PreferencesUtils.setBoolean(uploadServiceChooserActivity, R.string.send_to_docs_key, true); - uploadServiceChooserActivity.runOnUiThread(new Runnable() { - public void run() { - uploadServiceChooserActivity.initState(); - } - }); - instrumentation.waitForIdleSync(); - assertTrue(getMapsCheckBox().isChecked()); - assertTrue(getFusionTablesCheckBox().isChecked()); - assertTrue(getDocsCheckBox().isChecked()); - assertTrue(getExistingMapRadioButton().isChecked()); - - assertFalse(getNewMapRadioButton().isChecked()); - } - - /** - * Tests the logic of saveState when click send button. This test cover code - * in method {@link UploadServiceChooserActivity#initState()} and - * {@link UploadServiceChooserActivity#saveState()}, - */ - public void testOnCreateDialog_saveState() { - initialActivity(true, true, true); - // Initial all values to true in SharedPreferences. - PreferencesUtils.setBoolean(uploadServiceChooserActivity, R.string.send_to_maps_key, true); - PreferencesUtils.setBoolean( - uploadServiceChooserActivity, R.string.send_to_fusion_tables_key, true); - PreferencesUtils.setBoolean(uploadServiceChooserActivity, R.string.send_to_docs_key, true); - uploadServiceChooserActivity.runOnUiThread(new Runnable() { - public void run() { - uploadServiceChooserActivity.initState(); - } - }); - instrumentation.waitForIdleSync(); - uploadServiceChooserActivity.saveState(); - // All values in SharedPreferences must be changed. - assertTrue(PreferencesUtils.getBoolean(uploadServiceChooserActivity, R.string.send_to_maps_key, - PreferencesUtils.SEND_TO_MAPS_DEFAULT)); - assertTrue(PreferencesUtils.getBoolean( - uploadServiceChooserActivity, R.string.send_to_fusion_tables_key, - PreferencesUtils.SEND_TO_FUSION_TABLES_DEFAULT)); - assertTrue(PreferencesUtils.getBoolean(uploadServiceChooserActivity, R.string.send_to_docs_key, - PreferencesUtils.SEND_TO_DOCS_DEFAULT)); - } - - /** - * Tests the logic of startNextActivity when click send button. This test - * cover code in method {@link UploadServiceChooserActivity#initState()} and - * {@link UploadServiceChooserActivity#startNextActivity()}. - */ - public void testOnCreateDialog_startNextActivity() { - initialActivity(true, true, true); - // Initial all values to true or false in SharedPreferences. - PreferencesUtils.setBoolean(uploadServiceChooserActivity, R.string.send_to_maps_key, true); - PreferencesUtils.setBoolean(uploadServiceChooserActivity, R.string.send_to_docs_key, true); - PreferencesUtils.setBoolean( - uploadServiceChooserActivity, R.string.send_to_fusion_tables_key, false); - uploadServiceChooserActivity.runOnUiThread(new Runnable() { - public void run() { - uploadServiceChooserActivity.initState(); - } - }); - instrumentation.waitForIdleSync(); - uploadServiceChooserActivity.startNextActivity(); - // All values in SendRequest must be same as set above. - assertTrue(uploadServiceChooserActivity.getSendRequest().isSendMaps()); - assertTrue(uploadServiceChooserActivity.getSendRequest().isSendDocs()); - - assertFalse(uploadServiceChooserActivity.getSendRequest().isSendFusionTables()); - } - - /** - * Initials a activity to be tested. - * - * @param showMaps - * @param showFusionTables - * @param showDocs - */ - private void initialActivity(boolean showMaps, boolean showFusionTables, boolean showDocs) { - Intent intent = new Intent(); - intent.putExtra(SendRequest.SEND_REQUEST_KEY, new SendRequest(1L, showMaps, showFusionTables, - showDocs)); - setActivityIntent(intent); - uploadServiceChooserActivity = this.getActivity(); - } - - private CheckBox getMapsCheckBox() { - return (CheckBox) uploadServiceChooserActivity.getAlertDialog().findViewById(R.id.send_google_maps); - } - - private CheckBox getFusionTablesCheckBox() { - return (CheckBox) uploadServiceChooserActivity.getAlertDialog().findViewById( - R.id.send_google_fusion_tables); - } - - private CheckBox getDocsCheckBox() { - return (CheckBox) uploadServiceChooserActivity.getAlertDialog().findViewById(R.id.send_google_docs); - } - - private RadioButton getNewMapRadioButton() { - return (RadioButton) uploadServiceChooserActivity.getAlertDialog().findViewById( - R.id.send_google_new_map); - } - - private RadioButton getExistingMapRadioButton() { - return (RadioButton) uploadServiceChooserActivity.getAlertDialog().findViewById( - R.id.send_google_existing_map); - } -} diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/services/TrackRecordingServiceTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/services/TrackRecordingServiceTest.java index 7208605d2..a795b3b04 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/services/TrackRecordingServiceTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/services/TrackRecordingServiceTest.java @@ -502,7 +502,7 @@ public class TrackRecordingServiceTest extends ServiceTestCase