Merge heads

This commit is contained in:
youtaol
2012-05-17 10:42:09 +08:00
parent 2fe97f55dd
commit 164ba7a16b
78 changed files with 1490 additions and 1666 deletions
@@ -47,8 +47,7 @@ public class AntPreference extends Preference {
if (sensorId == 0) {
setSummary(R.string.settings_sensor_ant_not_paired);
} else {
setSummary(
String.format(getContext().getString(R.string.settings_sensor_ant_paired), sensorId));
setSummary(getContext().getString(R.string.settings_sensor_ant_paired, sensorId));
}
// Add actions to allow repairing.
@@ -111,7 +111,7 @@ public class ImportActivity extends Activity {
switch (id) {
case DIALOG_PROGRESS_ID:
progressDialog = DialogUtils.createHorizontalProgressDialog(
this, R.string.import_progress_message, new DialogInterface.OnCancelListener() {
this, R.string.sd_card_import_progress_message, new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
importAsyncTask.cancel(true);
@@ -122,11 +122,12 @@ public class ImportActivity extends Activity {
case DIALOG_RESULT_ID:
String message;
if (successCount == 0) {
message = getString(R.string.import_no_file, path);
message = getString(R.string.sd_card_import_error_no_file, path);
} else {
String totalFiles = getResources()
.getQuantityString(R.plurals.importGpxFiles, totalCount, totalCount);
message = getString(R.string.import_success, successCount, totalFiles, path);
message = getString(
R.string.sd_card_import_success_count, successCount, totalFiles, path);
}
return new AlertDialog.Builder(this)
.setCancelable(true)
@@ -171,7 +172,8 @@ public class ImportActivity extends Activity {
if (success) {
showDialog(DIALOG_RESULT_ID);
} else {
Toast.makeText(this, getString(R.string.import_error, path), Toast.LENGTH_LONG).show();
Toast.makeText(this, getString(R.string.sd_card_import_error), Toast.LENGTH_LONG)
.show();
finish();
}
}
@@ -73,7 +73,7 @@ public class MarkerDetailActivity extends AbstractMyTracksActivity {
finish();
return;
}
name.setText(getString(R.string.marker_detail_name, waypoint.getName()));
name.setText(getString(R.string.generic_name_line, waypoint.getName()));
if (waypoint.getType() == Waypoint.TYPE_WAYPOINT) {
waypointSection.setVisibility(View.VISIBLE);
statisticsSection.setVisibility(View.GONE);
@@ -81,7 +81,7 @@ public class MarkerDetailActivity extends AbstractMyTracksActivity {
TextView markerType = (TextView) findViewById(R.id.marker_detail_waypoint_marker_type);
markerType.setText(getString(R.string.marker_detail_marker_type, waypoint.getCategory()));
TextView description = (TextView) findViewById(R.id.marker_detail_waypoint_description);
description.setText(getString(R.string.marker_detail_description, waypoint.getDescription()));
description.setText(getString(R.string.generic_description_line, waypoint.getDescription()));
} else {
waypointSection.setVisibility(View.GONE);
statisticsSection.setVisibility(View.VISIBLE);
@@ -146,8 +146,8 @@ public class MarkerListActivity extends AbstractMyTracksActivity {
}
};
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);
final long firstWaypointId = MyTracksProviderUtils.Factory.get(this)
.getFirstWaypointId(trackId);
@@ -1,115 +0,0 @@
/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
/**
* An activity to save all the tracks to the SD card.
*
* @author Sandor Dornbush
*/
public class SaveAllActivity extends Activity {
public static final String EXTRA_TRACK_FILE_FORMAT = "track_file_format";
private static final int DIALOG_PROGRESS_ID = 0;
private SaveAllAsyncTask saveAllAsyncTask;
private ProgressDialog progressDialog;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Object retained = getLastNonConfigurationInstance();
if (retained instanceof SaveAllAsyncTask) {
saveAllAsyncTask = (SaveAllAsyncTask) retained;
saveAllAsyncTask.setActivity(this);
} else {
Intent intent = getIntent();
TrackFileFormat trackFileFormat = intent.getParcelableExtra(EXTRA_TRACK_FILE_FORMAT);
saveAllAsyncTask = new SaveAllAsyncTask(this, trackFileFormat);
saveAllAsyncTask.execute();
}
}
@Override
public Object onRetainNonConfigurationInstance() {
saveAllAsyncTask.setActivity(null);
return saveAllAsyncTask;
}
@Override
protected Dialog onCreateDialog(int id) {
if (id != DIALOG_PROGRESS_ID) {
return null;
}
progressDialog = DialogUtils.createHorizontalProgressDialog(
this, R.string.save_all_progress_message, new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
saveAllAsyncTask.cancel(true);
finish();
}
});
return progressDialog;
}
/**
* Invokes when the associated AsyncTask completes.
*
* @param success true if the AsyncTask is successful
* @param messageId message id to display to user
*/
public void onAsyncTaskCompleted(boolean success, int messageId) {
removeDialog(DIALOG_PROGRESS_ID);
Toast.makeText(this, messageId, success ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG).show();
finish();
}
/**
* Shows the progress dialog.
*/
public void showProgressDialog() {
showDialog(DIALOG_PROGRESS_ID);
}
/**
* Sets the progress dialog value.
*
* @param number the number of tracks saved
* @param max the maximum number of tracks
*/
public void setProgressDialogValue(int number, int max) {
if (progressDialog != null) {
progressDialog.setIndeterminate(false);
progressDialog.setMax(max);
progressDialog.setProgress(Math.min(number, max));
}
}
}
@@ -1,162 +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;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.io.file.TrackWriter;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.util.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;
/**
* AsyncTask to save all the tracks to the SD card.
*
* @author Jimmy Shih
*/
public class SaveAllAsyncTask extends AsyncTask<Void, Integer, Boolean> {
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();
}
}
}
@@ -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());
}
@@ -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()
@@ -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);
}
@@ -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;
}
@@ -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<Cursor>() {
@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);
@@ -36,7 +36,9 @@ import java.util.Vector;
public class DescriptionGeneratorImpl implements DescriptionGenerator {
private static final String HTML_LINE_BREAK = "<br>";
private static final String HTML_PARAGRAPH_SEPARATOR = "<p>";
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<Double> distances, Vector<Double> elevations) {
Track track, Vector<Double> distances, Vector<Double> 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, "<a href='http://" + url + "'>", "</a>"));
builder.append("<p>");
String beginAnchor = html
? "<a href='http://" + context.getString(R.string.my_tracks_web_url) + "'>"
: "";
String endAnchor = html ? "</a>" : "";
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("<img border=\"0\" src=\""
+ ChartURLGenerator.getChartUrl(distances, elevations, track, context) + "\"/>");
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}.
*
@@ -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);
@@ -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<DisplayInfo> displayInfos = getDisplayInfos();
ArrayAdapter<DisplayInfo> arrayAdapter = new ArrayAdapter<DisplayInfo>(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<DisplayInfo> getDisplayInfos() {
List<DisplayInfo> displayInfos = new ArrayList<DisplayInfo>();
Intent intent = ShareCompat.IntentBuilder.from(getActivity())
.setType(IntentUtils.TEXT_PLAIN_TYPE).getIntent();
List<ResolveInfo> 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<ResolveInfo> resolveInfos, List<DisplayInfo> 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<CharSequence> duplicates = new HashSet<CharSequence>();
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));
}
}
}
}
@@ -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<String> pages = new ArrayList<String>();
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()]));
}
}
@@ -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]);
}
}
@@ -56,7 +56,7 @@ public class BackupAsyncTask extends AsyncTask<Void, Integer, Boolean> {
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<Void, Integer, Boolean> {
}
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);
@@ -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));
}
@@ -59,7 +59,7 @@ public class RestoreAsyncTask extends AsyncTask<Void, Integer, Boolean> {
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<Void, Integer, Boolean> {
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);
@@ -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;
}
@@ -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("</entry>");
@@ -197,7 +197,7 @@ public class KmlTrackWriter implements TrackFormatWriter {
printWriter.println("</gx:MultiTrack>");
printWriter.println("</Placemark>");
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);
}
}
@@ -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();
}
@@ -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<Void, Integer, Boolean> {
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<Void, Integer, Boolean> {
}
@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<Void, Integer, Boolean> {
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();
}
}
}
@@ -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;
}
@@ -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 {
@@ -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("<p>" + track.getDescription() + "</p><p>"
+ descriptionGenerator.generateTrackDescription(track, distances, elevations) + "</p>");
+ descriptionGenerator.generateTrackDescription(track, distances, elevations, true)
+ "</p>");
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");
@@ -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);
}
}
@@ -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<Double> distances, Vector<Double> elevations) {
DescriptionGenerator descriptionGenerator = new DescriptionGeneratorImpl(context);
return "<p>" + track.getDescription() + "</p><p>"
+ descriptionGenerator.generateTrackDescription(track, distances, elevations) + "</p>";
+ descriptionGenerator.generateTrackDescription(track, distances, elevations, true)
+ "</p>";
}
/**
@@ -80,9 +80,6 @@ public abstract class AbstractSendAsyncTask extends AsyncTask<Void, Integer, Boo
return performTask();
} finally {
closeConnection();
if (success) {
saveResult();
}
}
}
@@ -97,6 +94,9 @@ public abstract class AbstractSendAsyncTask extends AsyncTask<Void, Integer, Boo
protected void onPostExecute(Boolean result) {
success = result;
completed = true;
if (success) {
saveResult();
}
if (activity != null) {
activity.onAsyncTaskCompleted(success);
}
@@ -76,7 +76,6 @@ public class AccountChooserActivity extends Activity {
private SendRequest sendRequest;
private Account[] accounts;
private int selectedAccountIndex;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -84,32 +83,28 @@ public class AccountChooserActivity extends Activity {
sendRequest = getIntent().getParcelableExtra(SendRequest.SEND_REQUEST_KEY);
accounts = AccountManager.get(this).getAccountsByType(Constants.ACCOUNT_TYPE);
if (accounts.length == 0) {
showDialog(DIALOG_NO_ACCOUNT_ID);
return;
}
if (accounts.length == 1) {
sendRequest.setAccount(accounts[0]);
PreferencesUtils.setString(this, R.string.sharing_account_key, accounts[0].name);
getPermission(MapsConstants.SERVICE_NAME, sendRequest.isSendMaps(), mapsCallback);
return;
}
String preferredAccount = PreferencesUtils.getString(this, R.string.preferred_account_key,
PreferencesUtils.PREFERRED_ACCOUNT_DEFAULT);
selectedAccountIndex = 0;
String sharingAccount = PreferencesUtils.getString(this, R.string.sharing_account_key,
PreferencesUtils.SHARING_ACCOUNT_DEFAULT);
for (int i = 0; i < accounts.length; i++) {
if (accounts[i].name.equals(preferredAccount)) {
selectedAccountIndex = i;
break;
if (accounts[i].name.equals(sharingAccount)) {
sendRequest.setAccount(accounts[i]);
getPermission(MapsConstants.SERVICE_NAME, sendRequest.isSendMaps(), mapsCallback);
return;
}
}
}
@Override
protected void onResume() {
super.onResume();
if (accounts.length == 0) {
showDialog(DIALOG_NO_ACCOUNT_ID);
} else if (accounts.length > 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();
}
@@ -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));
@@ -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;
@@ -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<String> pages = new ArrayList<String>();
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;
}
}
@@ -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);
@@ -51,7 +51,7 @@ public class SingleColorTrackPathPainter implements TrackPathPainter {
@Override
public void updatePath(Projection projection, Rect viewRect, int startLocationIdx,
Boolean alwaysVisible, List<CachedLocation> points) {
path = new Path();
path = newPath();
updatePath(projection, viewRect, startLocationIdx, alwaysVisible, points, path);
}
@@ -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());
@@ -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();
}
@@ -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;
}
@@ -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
@@ -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);
@@ -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.
*/
@@ -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<String> entries = new ArrayList<String>();
@@ -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<String> entries = new ArrayList<String>();
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
@@ -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());
}
@@ -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);
}
@@ -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.
@@ -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());
}
}
@@ -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;