mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-07 03:53:05 +02:00
Merged to head
This commit is contained in:
@@ -78,9 +78,9 @@ public class AccountChooser {
|
||||
// Let the user choose.
|
||||
Log.e(Constants.TAG, "Multiple matching accounts found.");
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setTitle(R.string.choose_account_title);
|
||||
builder.setTitle(R.string.send_google_choose_account_title);
|
||||
builder.setCancelable(false);
|
||||
builder.setPositiveButton(R.string.ok,
|
||||
builder.setPositiveButton(R.string.generic_ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
@@ -92,7 +92,7 @@ public class AccountChooser {
|
||||
handler.onAccountSelected(selectedAccount);
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.cancel,
|
||||
builder.setNegativeButton(R.string.generic_cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
@@ -124,10 +124,10 @@ public class AccountChooser {
|
||||
final AccountHandler handler) {
|
||||
Log.e(Constants.TAG, "No matching accounts found.");
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setTitle(R.string.no_account_found_title);
|
||||
builder.setMessage(R.string.no_account_found);
|
||||
builder.setTitle(R.string.send_google_no_account_title);
|
||||
builder.setMessage(R.string.send_google_no_account_message);
|
||||
builder.setCancelable(true);
|
||||
builder.setNegativeButton(R.string.ok,
|
||||
builder.setPositiveButton(R.string.generic_ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
|
||||
@@ -74,7 +74,7 @@ public class AggregatedStatsActivity extends Activity implements
|
||||
}
|
||||
utils.setMetricUnits(metricUnits);
|
||||
utils.updateUnits();
|
||||
utils.setSpeedLabel(R.id.speed_label, R.string.speed, R.string.pace_label);
|
||||
utils.setSpeedLabel(R.id.speed_label, R.string.stat_speed, R.string.stat_pace);
|
||||
utils.setSpeedLabels();
|
||||
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
|
||||
@@ -43,9 +43,10 @@ public class AntPreference extends Preference {
|
||||
private void init() {
|
||||
int sensorId = getPersistedInt(0);
|
||||
if (sensorId == 0) {
|
||||
setSummary(R.string.settings_ant_not_paired);
|
||||
setSummary(R.string.settings_sensor_ant_not_paired);
|
||||
} else {
|
||||
setSummary(String.format(getContext().getString(R.string.settings_ant_paired), sensorId));
|
||||
setSummary(
|
||||
String.format(getContext().getString(R.string.settings_sensor_ant_paired), sensorId));
|
||||
}
|
||||
|
||||
// Add actions to allow repairing.
|
||||
@@ -54,7 +55,7 @@ public class AntPreference extends Preference {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
AntPreference.this.persistInt(0);
|
||||
setSummary(R.string.settings_ant_not_paired);
|
||||
setSummary(R.string.settings_sensor_ant_not_paired);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.google.android.apps.mytracks;
|
||||
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.AutoCompleteTextView;
|
||||
|
||||
/**
|
||||
* The {@link AutoCompleteTextPreference} class is a preference that allows for
|
||||
* string input using auto complete . It is a subclass of
|
||||
* {@link EditTextPreference} and shows the {@link AutoCompleteTextView} in a
|
||||
* dialog.
|
||||
* <p>
|
||||
* This preference will store a string into the SharedPreferences.
|
||||
*
|
||||
* @author Rimas Trumpa (with Matt Levan)
|
||||
*/
|
||||
public class AutoCompleteTextPreference extends EditTextPreference {
|
||||
|
||||
private AutoCompleteTextView mEditText = null;
|
||||
|
||||
public AutoCompleteTextPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mEditText = new AutoCompleteTextView(context, attrs);
|
||||
mEditText.setThreshold(0);
|
||||
|
||||
// Gets autocomplete values for 'Default Activity' preference
|
||||
if (getKey().equals(context.getString(R.string.default_activity_key))) {
|
||||
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(context,
|
||||
R.array.activity_types, android.R.layout.simple_dropdown_item_1line);
|
||||
mEditText.setAdapter(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBindDialogView(View view) {
|
||||
AutoCompleteTextView editText = mEditText;
|
||||
editText.setText(getText());
|
||||
|
||||
ViewParent oldParent = editText.getParent();
|
||||
if (oldParent != view) {
|
||||
if (oldParent != null) {
|
||||
((ViewGroup) oldParent).removeView(editText);
|
||||
}
|
||||
onAddEditTextToDialogView(view, editText);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDialogClosed(boolean positiveResult) {
|
||||
if (positiveResult) {
|
||||
String value = mEditText.getText().toString();
|
||||
if (callChangeListener(value)) {
|
||||
setText(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,7 +190,7 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
chartSettingsMenuItem =
|
||||
menu.add(0, Constants.MENU_CHART_SETTINGS, 0,
|
||||
R.string.chart_settings);
|
||||
R.string.menu_chart_view_chart_settings);
|
||||
chartSettingsMenuItem.setIcon(R.drawable.chart_settings);
|
||||
return true;
|
||||
}
|
||||
@@ -260,7 +260,6 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
||||
*
|
||||
* @param location the location to get data for (this method takes ownership of that location)
|
||||
* @param result the resulting point to fill out
|
||||
* @return the previous location, now available for reuse
|
||||
*/
|
||||
private void fillDataPoint(Location location, double result[]) {
|
||||
double timeOrDistance = Double.NaN,
|
||||
|
||||
@@ -20,8 +20,8 @@ import com.google.android.apps.mytracks.stats.ExtremityMonitor;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Paint.Style;
|
||||
import android.graphics.Path;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
@@ -133,9 +133,10 @@ public class ChartValueSeries {
|
||||
*
|
||||
* @param context The context for the chart
|
||||
* @param formatString The format of the decimal format for this series
|
||||
* @param fill The paint for filling the chart
|
||||
* @param stroke The paint for stroking the outside the chart, optional
|
||||
* @param fillColor The paint for filling the chart
|
||||
* @param strokeColor The paint for stroking the outside the chart, optional
|
||||
* @param zoomSettings The settings related to zooming
|
||||
* @param titleId The title ID
|
||||
*
|
||||
* TODO: Get rid of Context and inject appropriate values instead.
|
||||
*/
|
||||
|
||||
@@ -210,7 +210,7 @@ public class ChartView extends View {
|
||||
R.color.elevation_border,
|
||||
new ZoomSettings(MAX_INTERVALS,
|
||||
new int[] {5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000}),
|
||||
R.string.elevation);
|
||||
R.string.stat_elevation);
|
||||
|
||||
series[SPEED_SERIES] =
|
||||
new ChartValueSeries(context,
|
||||
@@ -219,14 +219,14 @@ public class ChartView extends View {
|
||||
R.color.speed_border,
|
||||
new ZoomSettings(MAX_INTERVALS, 0, Integer.MIN_VALUE,
|
||||
new int[] {1, 5, 10, 20, 50}),
|
||||
R.string.speed);
|
||||
R.string.stat_speed);
|
||||
series[POWER_SERIES] =
|
||||
new ChartValueSeries(context,
|
||||
"###,###",
|
||||
R.color.power_fill,
|
||||
R.color.power_border,
|
||||
new ZoomSettings(MAX_INTERVALS, 0, 1000, new int[] {5, 50, 100, 200}),
|
||||
R.string.power);
|
||||
R.string.sensor_state_power);
|
||||
series[CADENCE_SERIES] =
|
||||
new ChartValueSeries(context,
|
||||
"###,###",
|
||||
@@ -234,7 +234,7 @@ public class ChartView extends View {
|
||||
R.color.cadence_border,
|
||||
new ZoomSettings(MAX_INTERVALS, 0, Integer.MIN_VALUE,
|
||||
new int[] {5, 10, 25, 50}),
|
||||
R.string.cadence);
|
||||
R.string.sensor_state_cadence);
|
||||
series[HEART_RATE_SERIES] =
|
||||
new ChartValueSeries(context,
|
||||
"###,###",
|
||||
@@ -242,7 +242,7 @@ public class ChartView extends View {
|
||||
R.color.heartrate_border,
|
||||
new ZoomSettings(MAX_INTERVALS, 0, Integer.MIN_VALUE,
|
||||
new int[] {25, 50}),
|
||||
R.string.heart_rate);
|
||||
R.string.sensor_state_heart_rate);
|
||||
}
|
||||
|
||||
public void clearWaypoints() {
|
||||
@@ -269,8 +269,8 @@ public class ChartView extends View {
|
||||
|
||||
public void setReportSpeed(boolean reportSpeed, Context c) {
|
||||
series[SPEED_SERIES].setTitle(c.getString(reportSpeed
|
||||
? R.string.speed
|
||||
: R.string.pace_label));
|
||||
? R.string.stat_speed
|
||||
: R.string.stat_pace));
|
||||
}
|
||||
|
||||
private void addDataPointInternal(double[] theData) {
|
||||
@@ -832,8 +832,8 @@ public class ChartView extends View {
|
||||
canvas.drawLine(leftBorder, y, rightEdge, y, borderPaint);
|
||||
Context c = getContext();
|
||||
String s = mode == Mode.BY_DISTANCE
|
||||
? (metricUnits ? c.getString(R.string.kilometer) : c.getString(R.string.mile))
|
||||
: c.getString(R.string.min);
|
||||
? (metricUnits ? c.getString(R.string.unit_kilometer) : c.getString(R.string.unit_mile))
|
||||
: c.getString(R.string.unit_minute);
|
||||
canvas.drawText(s, rightEdge, effectiveHeight + .2f * UNIT_BORDER + topBorder, labelPaint);
|
||||
}
|
||||
|
||||
@@ -852,7 +852,7 @@ public class ChartView extends View {
|
||||
|
||||
Context c = getContext();
|
||||
// TODO: This should really show units for all series.
|
||||
String s = metricUnits ? c.getString(R.string.meter) : c.getString(R.string.feet);
|
||||
String s = metricUnits ? c.getString(R.string.unit_meter) : c.getString(R.string.unit_feet);
|
||||
canvas.drawText(s, leftBorder - UNIT_BORDER * .2f, UNIT_BORDER * .8f + topBorder, labelPaint);
|
||||
}
|
||||
|
||||
@@ -881,7 +881,6 @@ public class ChartView extends View {
|
||||
*
|
||||
* @param index the time series, one of {@link #ELEVATION_SERIES},
|
||||
* {@link #SPEED_SERIES}, {@link #POWER_SERIES}, etc.
|
||||
* @return true to be drawn, false otherwise
|
||||
*/
|
||||
public void setChartValueSeriesEnabled(int index, boolean enabled) {
|
||||
series[index].setEnabled(enabled);
|
||||
|
||||
@@ -23,73 +23,63 @@ import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Check to see if the units are the default for the locale.
|
||||
* This comes down to warning Americans that the default is metric.
|
||||
* Checks with the user if he prefers the metric units or the imperial units.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
class CheckUnits {
|
||||
private static final String PREFERENCE_UNITS_CHECKED = "checkunits.checked";
|
||||
private static final String PREFERENCES_CHECK_UNITS = "checkunits";
|
||||
private static final String CHECK_UNITS_PREFERENCE_FILE = "checkunits";
|
||||
private static final String CHECK_UNITS_PREFERENCE_KEY = "checkunits.checked";
|
||||
private static boolean metric = true;
|
||||
|
||||
static void check(final Context context) {
|
||||
final SharedPreferences preferences =
|
||||
context.getSharedPreferences(PREFERENCES_CHECK_UNITS, Activity.MODE_PRIVATE);
|
||||
|
||||
// Has the user already warned about the default units?
|
||||
if (preferences.getBoolean(PREFERENCE_UNITS_CHECKED, false)) {
|
||||
public static void check(final Context context) {
|
||||
final SharedPreferences checkUnitsSharedPreferences = context.getSharedPreferences(
|
||||
CHECK_UNITS_PREFERENCE_FILE, Activity.MODE_PRIVATE);
|
||||
if (checkUnitsSharedPreferences.getBoolean(CHECK_UNITS_PREFERENCE_KEY, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Is the user in the US?
|
||||
Locale current = Locale.getDefault();
|
||||
Locale enUs = new Locale(Locale.ENGLISH.getLanguage(),
|
||||
Locale.US.getCountry());
|
||||
if (!current.equals(enUs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.check_units_title);
|
||||
builder.setCancelable(true);
|
||||
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(context.getString(R.string.preferred_units_title));
|
||||
CharSequence[] items = { context.getString(R.string.preferred_units_metric),
|
||||
context.getString(R.string.preferred_units_imperial) };
|
||||
builder.setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
accept(context, preferences);
|
||||
if (which == 0) {
|
||||
metric = true;
|
||||
} else {
|
||||
metric = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
|
||||
builder.setCancelable(true);
|
||||
builder.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
recordCheckPerformed(preferences);
|
||||
recordCheckPerformed(checkUnitsSharedPreferences);
|
||||
SharedPreferences useMetricPreferences = context.getSharedPreferences(
|
||||
Constants.SETTINGS_NAME, Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = useMetricPreferences.edit();
|
||||
String key = context.getString(R.string.metric_units_key);
|
||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(
|
||||
editor.putBoolean(key, metric));
|
||||
}
|
||||
});
|
||||
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
recordCheckPerformed(preferences);
|
||||
recordCheckPerformed(checkUnitsSharedPreferences);
|
||||
}
|
||||
});
|
||||
builder.setMessage(R.string.check_units_message);
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private static void accept(Context context, SharedPreferences preferences) {
|
||||
recordCheckPerformed(preferences);
|
||||
Intent startIntent = new Intent(context, SettingsActivity.class);
|
||||
startIntent.putExtra(context.getString(R.string.open_settings_screen),
|
||||
context.getString(R.string.display_settings_screen_key));
|
||||
context.startActivity(startIntent);
|
||||
}
|
||||
|
||||
private static void recordCheckPerformed(SharedPreferences preferences) {
|
||||
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
|
||||
preferences.edit().putBoolean(PREFERENCE_UNITS_CHECKED, true));
|
||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(
|
||||
preferences.edit().putBoolean(CHECK_UNITS_PREFERENCE_KEY, true));
|
||||
}
|
||||
|
||||
private CheckUnits() {
|
||||
}
|
||||
private CheckUnits() {}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@ public abstract class Constants {
|
||||
public static final int MENU_MY_LOCATION = 1;
|
||||
public static final int MENU_TOGGLE_LAYERS = 2;
|
||||
public static final int MENU_CHART_SETTINGS = 3;
|
||||
public static final int MENU_CURRENT_SEGMENT = 4;
|
||||
|
||||
/*
|
||||
* Context menu ids:
|
||||
|
||||
@@ -51,10 +51,10 @@ public class DeleteAllTracks extends Handler {
|
||||
AlertDialog dialog = null;
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setMessage(
|
||||
context.getString(R.string.all_data_will_be_permanently_deleted));
|
||||
builder.setTitle(context.getString(R.string.are_you_sure_question));
|
||||
context.getString(R.string.track_list_delete_all_confirm_message));
|
||||
builder.setTitle(context.getString(R.string.generic_confirm_title));
|
||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
builder.setPositiveButton(context.getString(R.string.yes),
|
||||
builder.setPositiveButton(context.getString(R.string.generic_yes),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
dialogInterface.dismiss();
|
||||
@@ -65,14 +65,14 @@ public class DeleteAllTracks extends Handler {
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
// TODO: Go through data manager
|
||||
editor.putLong(context.getString(R.string.selected_track_key), -1);
|
||||
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(editor);
|
||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
||||
if (done != null) {
|
||||
Handler h = new Handler();
|
||||
h.post(done);
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(context.getString(R.string.no),
|
||||
builder.setNegativeButton(context.getString(R.string.generic_no),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
dialogInterface.dismiss();
|
||||
|
||||
@@ -77,11 +77,11 @@ public class DeleteTrack extends Activity
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setMessage(getString(R.string.track_will_be_permanently_deleted));
|
||||
builder.setTitle(getString(R.string.are_you_sure_question));
|
||||
builder.setMessage(getString(R.string.track_list_delete_track_confirm_message));
|
||||
builder.setTitle(getString(R.string.generic_confirm_title));
|
||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
builder.setPositiveButton(getString(R.string.yes), this);
|
||||
builder.setNegativeButton(getString(R.string.no), this);
|
||||
builder.setPositiveButton(getString(R.string.generic_yes), this);
|
||||
builder.setNegativeButton(getString(R.string.generic_no), this);
|
||||
builder.setOnCancelListener(this);
|
||||
return builder.create();
|
||||
}
|
||||
@@ -108,7 +108,7 @@ public class DeleteTrack extends Activity
|
||||
SharedPreferences preferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||
if (preferences.getLong(selectedKey, -1) == deleteTrackId) {
|
||||
Editor editor = preferences.edit().putLong(selectedKey, -1);
|
||||
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(editor);
|
||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ import android.view.WindowManager.BadTokenException;
|
||||
public class DialogManager {
|
||||
|
||||
/**
|
||||
* The equivalent of {@link #showDialogSafely(int)}, but for a specific
|
||||
* dialog instance.
|
||||
* The equivalent of {@link Dialog#show()}, but for a specific dialog
|
||||
* instance.
|
||||
*/
|
||||
public static void showDialogSafely(Activity activity, final Dialog dialog) {
|
||||
if (activity.isFinishing()) {
|
||||
@@ -53,8 +53,8 @@ public class DialogManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* The equivalent of {@link #dismissDialogSafely(int)}, but for a specific
|
||||
* dialog instance.
|
||||
* The equivalent of {@link Dialog#dismiss()}, but for a specific dialog
|
||||
* instance.
|
||||
*/
|
||||
public static void dismissDialogSafely(Activity activity, final Dialog dialog) {
|
||||
if (activity.isFinishing()) {
|
||||
|
||||
@@ -52,14 +52,14 @@ class Eula {
|
||||
}
|
||||
|
||||
final AlertDialog.Builder builder = initDialog(activity);
|
||||
builder.setPositiveButton(R.string.accept,
|
||||
builder.setPositiveButton(R.string.eula_accept,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
accept(activity, preferences);
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.decline,
|
||||
builder.setNegativeButton(R.string.eula_decline,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
@@ -82,7 +82,7 @@ class Eula {
|
||||
*/
|
||||
static void showEula(Context context) {
|
||||
AlertDialog.Builder builder = initDialog(context);
|
||||
builder.setPositiveButton(R.string.ok, null);
|
||||
builder.setPositiveButton(R.string.generic_ok, null);
|
||||
builder.show();
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ class Eula {
|
||||
}
|
||||
|
||||
private static void accept(Activity activity, SharedPreferences preferences) {
|
||||
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
|
||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(
|
||||
preferences.edit().putBoolean(PREFERENCE_EULA_ACCEPTED, true));
|
||||
Intent startIntent = new Intent(activity, WelcomeActivity.class);
|
||||
activity.startActivityForResult(startIntent, Constants.WELCOME);
|
||||
|
||||
@@ -78,10 +78,18 @@ public class ExportAllTracks {
|
||||
this.activity = activity;
|
||||
Log.i(Constants.TAG, "ExportAllTracks: Starting");
|
||||
|
||||
String exportFileFormat = activity.getString(R.string.track_list_export_file);
|
||||
String fileTypes[] = activity.getResources().getStringArray(R.array.file_types);
|
||||
|
||||
String[] choices = new String[fileTypes.length];
|
||||
for (int i = 0; i < fileTypes.length; i++) {
|
||||
choices[i] = String.format(exportFileFormat, fileTypes[i]);
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setSingleChoiceItems(R.array.export_formats, 0, itemClick);
|
||||
builder.setPositiveButton(R.string.ok, positiveClick);
|
||||
builder.setNegativeButton(R.string.cancel, null);
|
||||
builder.setSingleChoiceItems(choices, 0, itemClick);
|
||||
builder.setPositiveButton(R.string.generic_ok, positiveClick);
|
||||
builder.setNegativeButton(R.string.generic_cancel, null);
|
||||
builder.show();
|
||||
}
|
||||
|
||||
@@ -126,11 +134,11 @@ public class ExportAllTracks {
|
||||
Log.i(Constants.TAG, "ExportAllTracks: Releasing wake lock.");
|
||||
}
|
||||
Log.i(Constants.TAG, "ExportAllTracks: Done");
|
||||
showToast(R.string.export_done, Toast.LENGTH_SHORT);
|
||||
showToast(R.string.export_success, Toast.LENGTH_SHORT);
|
||||
}
|
||||
|
||||
private void makeProgressDialog(final int trackCount) {
|
||||
String exportMsg = activity.getString(R.string.tracklist_btn_export_all);
|
||||
String exportMsg = activity.getString(R.string.track_list_export_all);
|
||||
progress = new ProgressDialog(activity);
|
||||
progress.setIcon(android.R.drawable.ic_dialog_info);
|
||||
progress.setTitle(exportMsg);
|
||||
@@ -183,7 +191,7 @@ public class ExportAllTracks {
|
||||
TrackWriter writer =
|
||||
TrackWriterFactory.newWriter(activity, providerUtils, id, format);
|
||||
if (writer == null) {
|
||||
showToast(R.string.error_track_does_not_exist, Toast.LENGTH_LONG);
|
||||
showToast(R.string.export_error, Toast.LENGTH_LONG);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
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.GpxImporter;
|
||||
import com.google.android.apps.mytracks.util.FileUtils;
|
||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||
@@ -24,7 +25,11 @@ import com.google.android.maps.mytracks.R;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ContentUris;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
@@ -49,22 +54,36 @@ import org.xml.sax.SAXException;
|
||||
public class ImportAllTracks {
|
||||
|
||||
private final Activity activity;
|
||||
private FileUtils fileUtils;
|
||||
private boolean singleTrackSelected;
|
||||
private String gpxPath;
|
||||
private WakeLock wakeLock;
|
||||
private ProgressDialog progress;
|
||||
private FileUtils fileUtils;
|
||||
private String gpxPath;
|
||||
private int gpxFileCount;
|
||||
private int importSuccessCount;
|
||||
|
||||
private long importedTrackIds[];
|
||||
|
||||
public ImportAllTracks(Activity activity) {
|
||||
this.activity = activity;
|
||||
Log.i(Constants.TAG, "ImportAllTracks: Starting");
|
||||
fileUtils = new FileUtils();
|
||||
gpxPath = fileUtils.buildExternalDirectoryPath("gpx");
|
||||
|
||||
new Thread(runner).start();
|
||||
this(activity, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to import tracks.
|
||||
*
|
||||
* @param activity the activity
|
||||
* @param path path of the gpx file to import and display. If null, then just
|
||||
* import all the gpx files under MyTracks/gpx and do not display any
|
||||
* track.
|
||||
*/
|
||||
public ImportAllTracks(Activity activity, String path) {
|
||||
Log.i(Constants.TAG, "ImportAllTracks: Starting");
|
||||
this.activity = activity;
|
||||
fileUtils = new FileUtils();
|
||||
singleTrackSelected = path != null;
|
||||
gpxPath = path == null ? fileUtils.buildExternalDirectoryPath("gpx") : path;
|
||||
new Thread(runner).start();
|
||||
}
|
||||
|
||||
private final Runnable runner = new Runnable() {
|
||||
public void run() {
|
||||
aquireLocksAndImport();
|
||||
@@ -81,7 +100,7 @@ public class ImportAllTracks {
|
||||
if (prefs != null) {
|
||||
recordingTrackId = prefs.getLong(activity.getString(R.string.recording_track_key), -1);
|
||||
}
|
||||
if (recordingTrackId != -1) {
|
||||
if (recordingTrackId == -1) {
|
||||
wakeLock = SystemUtils.acquireWakeLock(activity, wakeLock);
|
||||
}
|
||||
|
||||
@@ -107,17 +126,31 @@ public class ImportAllTracks {
|
||||
Log.i(Constants.TAG, "ImportAllTracks: Done");
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
if (gpxFileCount == 0) {
|
||||
builder.setMessage(activity.getString(R.string.import_multi_empty, gpxPath + "/"));
|
||||
builder.setMessage(activity.getString(R.string.import_no_file, gpxPath));
|
||||
} else {
|
||||
builder.setMessage(activity.getString(R.string.import_multi_done, importSuccessCount, gpxFileCount,
|
||||
gpxPath + "/"));
|
||||
builder.setMessage(
|
||||
activity.getString(R.string.import_success, importSuccessCount, gpxFileCount, gpxPath));
|
||||
}
|
||||
builder.setPositiveButton(R.string.ok, null);
|
||||
builder.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (singleTrackSelected) {
|
||||
long lastTrackId = importedTrackIds[importedTrackIds.length - 1];
|
||||
Uri trackUri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, lastTrackId);
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setDataAndType(trackUri, TracksColumns.CONTENT_ITEMTYPE);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
activity.startActivity(intent);
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void makeProgressDialog(final int trackCount) {
|
||||
String importMsg = activity.getString(R.string.tracklist_btn_import_all);
|
||||
String importMsg = activity.getString(R.string.track_list_import_all);
|
||||
progress = new ProgressDialog(activity);
|
||||
progress.setIcon(android.R.drawable.ic_dialog_info);
|
||||
progress.setTitle(importMsg);
|
||||
@@ -185,7 +218,7 @@ public class ImportAllTracks {
|
||||
private boolean importFile(File gpxFile, MyTracksProviderUtils providerUtils) {
|
||||
Log.i(Constants.TAG, "ImportAllTracks: importing: " + gpxFile.getName());
|
||||
try {
|
||||
GpxImporter.importGPXFile(new FileInputStream(gpxFile), providerUtils);
|
||||
importedTrackIds = GpxImporter.importGPXFile(new FileInputStream(gpxFile), providerUtils);
|
||||
return true;
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.w(Constants.TAG, "GPX file wasn't found/went missing: "
|
||||
@@ -203,15 +236,22 @@ public class ImportAllTracks {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the GPX Files found in the GPX directory.
|
||||
* Gets a list of the GPX files. If singleTrackSelected is true, returns a
|
||||
* list containing just the gpxPath file. If singleTrackSelected is false,
|
||||
* returns a list of GPX files under the gpxPath directory.
|
||||
*/
|
||||
private List<File> getGpxFiles() {
|
||||
List<File> gpxFiles = new LinkedList<File>();
|
||||
File[] gpxFileCandidates = new File(gpxPath).listFiles();
|
||||
if (gpxFileCandidates != null) {
|
||||
for (File file : gpxFileCandidates) {
|
||||
if (!file.isDirectory() && file.getName().endsWith(".gpx")) {
|
||||
gpxFiles.add(file);
|
||||
List<File> gpxFiles = new LinkedList<File>();
|
||||
File file = new File(gpxPath);
|
||||
if (singleTrackSelected) {
|
||||
gpxFiles.add(file);
|
||||
} else {
|
||||
File[] gpxFileCandidates = file.listFiles();
|
||||
if (gpxFileCandidates != null) {
|
||||
for (File candidate : gpxFileCandidates) {
|
||||
if (!candidate.isDirectory() && candidate.getName().endsWith(".gpx")) {
|
||||
gpxFiles.add(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@ import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub;
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
||||
import com.google.android.apps.mytracks.content.TrackDataListener;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
||||
import com.google.android.apps.mytracks.io.file.SaveActivity;
|
||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendActivity;
|
||||
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
||||
@@ -44,14 +44,14 @@ import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SubMenu;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.View.OnCreateContextMenuListener;
|
||||
import android.view.Window;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
@@ -358,39 +358,43 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||
ContextMenuInfo menuInfo) {
|
||||
menu.setHeaderTitle(R.string.tracklist_this_track);
|
||||
menu.setHeaderTitle(R.string.track_list_context_menu_title);
|
||||
menu.add(0, Constants.MENU_EDIT, 0,
|
||||
R.string.tracklist_edit_track);
|
||||
R.string.track_list_edit_track);
|
||||
if (!dataHub.isRecordingSelected()) {
|
||||
String saveFileFormat = getString(R.string.track_list_save_file);
|
||||
String shareFileFormat = getString(R.string.track_list_share_file);
|
||||
String fileTypes[] = getResources().getStringArray(R.array.file_types);
|
||||
|
||||
menu.add(0, Constants.MENU_SEND_TO_GOOGLE, 0,
|
||||
R.string.tracklist_send_to_google);
|
||||
R.string.track_list_send_google);
|
||||
SubMenu share = menu.addSubMenu(0, Constants.MENU_SHARE, 0,
|
||||
R.string.tracklist_share_track);
|
||||
R.string.track_list_share_track);
|
||||
share.add(0, Constants.MENU_SHARE_LINK, 0,
|
||||
R.string.tracklist_share_link);
|
||||
share.add(0, Constants.MENU_SHARE_GPX_FILE, 0,
|
||||
R.string.tracklist_share_gpx_file);
|
||||
share.add(0, Constants.MENU_SHARE_KML_FILE, 0,
|
||||
R.string.tracklist_share_kml_file);
|
||||
share.add(0, Constants.MENU_SHARE_CSV_FILE, 0,
|
||||
R.string.tracklist_share_csv_file);
|
||||
share.add(0, Constants.MENU_SHARE_TCX_FILE, 0,
|
||||
R.string.tracklist_share_tcx_file);
|
||||
R.string.track_list_share_url);
|
||||
share.add(
|
||||
0, Constants.MENU_SHARE_GPX_FILE, 0, String.format(shareFileFormat, fileTypes[0]));
|
||||
share.add(
|
||||
0, Constants.MENU_SHARE_KML_FILE, 0, String.format(shareFileFormat, fileTypes[1]));
|
||||
share.add(
|
||||
0, Constants.MENU_SHARE_CSV_FILE, 0, String.format(shareFileFormat, fileTypes[2]));
|
||||
share.add(
|
||||
0, Constants.MENU_SHARE_TCX_FILE, 0, String.format(shareFileFormat, fileTypes[3]));
|
||||
SubMenu save = menu.addSubMenu(0,
|
||||
Constants.MENU_WRITE_TO_SD_CARD, 0,
|
||||
R.string.tracklist_write_to_sd);
|
||||
save.add(0, Constants.MENU_SAVE_GPX_FILE, 0,
|
||||
R.string.tracklist_save_as_gpx);
|
||||
save.add(0, Constants.MENU_SAVE_KML_FILE, 0,
|
||||
R.string.tracklist_save_as_kml);
|
||||
save.add(0, Constants.MENU_SAVE_CSV_FILE, 0,
|
||||
R.string.tracklist_save_as_csv);
|
||||
save.add(0, Constants.MENU_SAVE_TCX_FILE, 0,
|
||||
R.string.tracklist_save_as_tcx);
|
||||
R.string.track_list_save_sd);
|
||||
save.add(
|
||||
0, Constants.MENU_SAVE_GPX_FILE, 0, String.format(saveFileFormat, fileTypes[0]));
|
||||
save.add(
|
||||
0, Constants.MENU_SAVE_KML_FILE, 0, String.format(saveFileFormat, fileTypes[1]));
|
||||
save.add(
|
||||
0, Constants.MENU_SAVE_CSV_FILE, 0, String.format(saveFileFormat, fileTypes[2]));
|
||||
save.add(
|
||||
0, Constants.MENU_SAVE_TCX_FILE, 0, String.format(saveFileFormat, fileTypes[3]));
|
||||
menu.add(0, Constants.MENU_CLEAR_MAP, 0,
|
||||
R.string.tracklist_clear_map);
|
||||
R.string.track_list_clear_map);
|
||||
menu.add(0, Constants.MENU_DELETE, 0,
|
||||
R.string.tracklist_delete_track);
|
||||
R.string.track_list_delete_track);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -441,10 +445,10 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
myLocation = menu.add(0, Constants.MENU_MY_LOCATION, 0,
|
||||
R.string.mylocation);
|
||||
R.string.menu_map_view_my_location);
|
||||
myLocation.setIcon(android.R.drawable.ic_menu_mylocation);
|
||||
toggleLayers = menu.add(0, Constants.MENU_TOGGLE_LAYERS, 0,
|
||||
R.string.switch_to_sat);
|
||||
R.string.menu_map_view_satellite_mode);
|
||||
toggleLayers.setIcon(android.R.drawable.ic_menu_mapmode);
|
||||
return true;
|
||||
}
|
||||
@@ -452,7 +456,7 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
toggleLayers.setTitle(mapView.isSatellite() ?
|
||||
R.string.switch_to_map : R.string.switch_to_sat);
|
||||
R.string.menu_map_view_map_mode : R.string.menu_map_view_satellite_mode);
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@@ -507,12 +511,12 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
||||
final boolean isGpsDisabled;
|
||||
switch (state) {
|
||||
case DISABLED:
|
||||
messageId = R.string.status_enable_gps;
|
||||
messageId = R.string.gps_need_to_enable;
|
||||
isGpsDisabled = true;
|
||||
break;
|
||||
case NO_FIX:
|
||||
case BAD_FIX:
|
||||
messageId = R.string.wait_for_fix;
|
||||
messageId = R.string.gps_wait_for_fix;
|
||||
isGpsDisabled = false;
|
||||
break;
|
||||
case GOOD_FIX:
|
||||
@@ -534,7 +538,7 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
||||
if (isGpsDisabled) {
|
||||
// Give a warning about this state.
|
||||
Toast.makeText(MapActivity.this,
|
||||
R.string.error_no_gps_location_provider,
|
||||
R.string.gps_not_found,
|
||||
Toast.LENGTH_LONG).show();
|
||||
|
||||
// Make clicking take the user to the location settings.
|
||||
|
||||
@@ -35,7 +35,6 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@@ -78,7 +77,6 @@ public class MapOverlay extends Overlay implements OnSharedPreferenceChangeListe
|
||||
private GeoPoint lastReferencePoint;
|
||||
private Rect lastViewRect;
|
||||
private boolean lastPathExists;
|
||||
private Location lastLocation;
|
||||
private TrackPathPainter trackPathPainter;
|
||||
|
||||
/**
|
||||
@@ -305,17 +303,17 @@ public class MapOverlay extends Overlay implements OnSharedPreferenceChangeListe
|
||||
int cy = mapView.getMapCenter().getLatitudeE6();
|
||||
return new Rect(cx - w / 2, cy - h / 2, cx + w / 2, cy + h / 2);
|
||||
}
|
||||
|
||||
// Visible for testing.
|
||||
Path newPath() {
|
||||
return new Path();
|
||||
}
|
||||
|
||||
// Visible for testing.
|
||||
public Path getLastPath() {
|
||||
return trackPathPainter.getLastPath();
|
||||
|
||||
// For use in testing only.
|
||||
public TrackPathPainter getTrackPathPainter() {
|
||||
return trackPathPainter;
|
||||
}
|
||||
|
||||
// For use in testing only.
|
||||
public void setTrackPathPainter(TrackPathPainter trackPathPainter) {
|
||||
this.trackPathPainter = trackPathPainter;
|
||||
}
|
||||
|
||||
private void drawWaypoints(Canvas canvas, Projection projection) {
|
||||
synchronized (waypoints) {;
|
||||
for (Waypoint wpt : waypoints) {
|
||||
|
||||
@@ -42,10 +42,9 @@ class MenuManager {
|
||||
|
||||
public void onPrepareOptionsMenu(Menu menu, boolean hasRecorded,
|
||||
boolean isRecording, boolean hasSelectedTrack) {
|
||||
menu.findItem(R.id.menu_list_tracks);
|
||||
menu.findItem(R.id.menu_list_markers)
|
||||
menu.findItem(R.id.menu_markers)
|
||||
.setEnabled(hasRecorded && hasSelectedTrack);
|
||||
menu.findItem(R.id.menu_start_recording)
|
||||
menu.findItem(R.id.menu_record_track)
|
||||
.setEnabled(!isRecording)
|
||||
.setVisible(!isRecording);
|
||||
menu.findItem(R.id.menu_stop_recording)
|
||||
@@ -55,7 +54,7 @@ class MenuManager {
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_start_recording: {
|
||||
case R.id.menu_record_track: {
|
||||
activity.startRecording();
|
||||
return true;
|
||||
}
|
||||
@@ -63,12 +62,12 @@ class MenuManager {
|
||||
activity.stopRecording();
|
||||
return true;
|
||||
}
|
||||
case R.id.menu_list_tracks: {
|
||||
case R.id.menu_tracks: {
|
||||
activity.startActivityForResult(new Intent(activity, TrackList.class),
|
||||
Constants.SHOW_TRACK);
|
||||
return true;
|
||||
}
|
||||
case R.id.menu_list_markers: {
|
||||
case R.id.menu_markers: {
|
||||
Intent startIntent = new Intent(activity, WaypointsList.class);
|
||||
startIntent.putExtra("trackid", activity.getSelectedTrackId());
|
||||
activity.startActivityForResult(startIntent, Constants.SHOW_WAYPOINT);
|
||||
@@ -80,7 +79,7 @@ class MenuManager {
|
||||
case R.id.menu_settings: {
|
||||
return startActivity(SettingsActivity.class);
|
||||
}
|
||||
case R.id.menu_aggregated_stats: {
|
||||
case R.id.menu_aggregated_statistics: {
|
||||
return startActivity(AggregatedStatsActivity.class);
|
||||
}
|
||||
case R.id.menu_help: {
|
||||
|
||||
@@ -99,10 +99,10 @@ public class MyMapsListAdapter implements ListAdapter {
|
||||
(TextView) convertView.findViewById(R.id.maplistpublic);
|
||||
if (publicList.get(position)) {
|
||||
publicUnlisted.setTextColor(Color.RED);
|
||||
publicUnlisted.setText(R.string.public_map);
|
||||
publicUnlisted.setText(R.string.my_maps_list_public_label);
|
||||
} else {
|
||||
publicUnlisted.setTextColor(Color.GREEN);
|
||||
publicUnlisted.setText(R.string.unlisted_map);
|
||||
publicUnlisted.setText(R.string.my_maps_list_unlisted_label);
|
||||
}
|
||||
|
||||
return convertView;
|
||||
|
||||
@@ -134,12 +134,12 @@ public class MyTracks extends TabActivity implements OnTouchListener {
|
||||
super.onCreate(savedInstanceState);
|
||||
ApiFeatures apiFeatures = ApiFeatures.getInstance();
|
||||
if (!SystemUtils.isRelease(this)) {
|
||||
apiFeatures.getApiPlatformAdapter().enableStrictMode();
|
||||
apiFeatures.getApiAdapter().enableStrictMode();
|
||||
}
|
||||
|
||||
tracker = GoogleAnalyticsTracker.getInstance();
|
||||
// Start the tracker in manual dispatch mode...
|
||||
tracker.start(getString(R.string.google_analytics_id), getApplicationContext());
|
||||
tracker.start(getString(R.string.my_tracks_analytics_id), getApplicationContext());
|
||||
tracker.setProductVersion("android-mytracks", SystemUtils.getMyTracksVersion(this));
|
||||
tracker.trackPageView("/appstart");
|
||||
tracker.dispatch();
|
||||
@@ -369,13 +369,11 @@ public class MyTracks extends TabActivity implements OnTouchListener {
|
||||
try {
|
||||
long waypointId = trackRecordingService.insertWaypoint(request);
|
||||
if (waypointId >= 0) {
|
||||
Toast.makeText(this, R.string.status_statistics_inserted,
|
||||
Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, R.string.marker_insert_success, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
return waypointId;
|
||||
} catch (RemoteException e) {
|
||||
Toast.makeText(this, R.string.error_unable_to_insert_marker,
|
||||
Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, R.string.marker_insert_error, Toast.LENGTH_LONG).show();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -386,14 +384,11 @@ public class MyTracks extends TabActivity implements OnTouchListener {
|
||||
long recordingTrackId = trackRecordingService.startNewTrack();
|
||||
// Select the recording track.
|
||||
dataHub.loadTrack(recordingTrackId);
|
||||
Toast.makeText(this, getString(R.string.status_now_recording),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(this, getString(R.string.track_record_success), Toast.LENGTH_SHORT).show();
|
||||
// TODO: We catch Exception, because after eliminating the service process
|
||||
// all exceptions it may throw are no longer wrapped in a RemoteException.
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(this,
|
||||
getString(R.string.error_unable_to_start_recording),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(this, getString(R.string.track_record_error), Toast.LENGTH_SHORT).show();
|
||||
Log.w(TAG, "Unable to start recording.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ package com.google.android.apps.mytracks;
|
||||
*/
|
||||
public interface ProgressIndicator {
|
||||
|
||||
public void setProgressMessage(int resId);
|
||||
public void setProgressMessage(String message);
|
||||
public void clearProgressMessage();
|
||||
|
||||
public void setProgressValue(int percent);
|
||||
|
||||
@@ -20,6 +20,8 @@ import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.services.ITrackRecordingService;
|
||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||
import com.google.android.apps.mytracks.services.sensors.SensorManager;
|
||||
import com.google.android.apps.mytracks.services.sensors.SensorManagerFactory;
|
||||
import com.google.android.apps.mytracks.services.sensors.SensorUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
@@ -55,7 +57,8 @@ public class SensorStateActivity extends Activity {
|
||||
|
||||
private final Runnable stateUpdater = new Runnable() {
|
||||
public void run() {
|
||||
updateState();
|
||||
if (isVisible) // only update when UI is visible
|
||||
updateState();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -73,6 +76,23 @@ public class SensorStateActivity extends Activity {
|
||||
runOnUiThread(stateUpdater);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A temporary sensor manager, when none is available.
|
||||
*/
|
||||
SensorManager tempSensorManager = null;
|
||||
|
||||
/**
|
||||
* A state flag set to true when the activity is active/visible,
|
||||
* i.e. after resume, and before pause
|
||||
*
|
||||
* Used to avoid updating after the pause event, because sometimes an update
|
||||
* event occurs even after the timer is cancelled. In this case,
|
||||
* it could cause the {@link #tempSensorManager} to be recreated, after it
|
||||
* is destroyed at the pause event.
|
||||
*/
|
||||
boolean isVisible = false;
|
||||
|
||||
public SensorStateActivity() {
|
||||
utils = new StatsUtilities(this);
|
||||
@@ -86,7 +106,6 @@ public class SensorStateActivity extends Activity {
|
||||
|
||||
setContentView(R.layout.sensor_state);
|
||||
|
||||
// TODO: Allow reading from sensors even if service is not running.
|
||||
serviceConnection = new TrackRecordingServiceConnection(this, stateUpdater);
|
||||
serviceConnection.bindIfRunning();
|
||||
updateState();
|
||||
@@ -95,6 +114,8 @@ public class SensorStateActivity extends Activity {
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
isVisible = true;
|
||||
|
||||
serviceConnection.bindIfRunning();
|
||||
|
||||
@@ -104,9 +125,12 @@ public class SensorStateActivity extends Activity {
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
isVisible = false;
|
||||
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
timer = null;
|
||||
stopTempSensorManager();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@@ -117,35 +141,106 @@ public class SensorStateActivity extends Activity {
|
||||
}
|
||||
|
||||
protected void updateState() {
|
||||
Log.d(TAG, "Updating SensorStateActivity");
|
||||
|
||||
ITrackRecordingService service = serviceConnection.getServiceIfBound();
|
||||
if (service == null) {
|
||||
Log.d(Constants.TAG, "Could not get track recording service.");
|
||||
updateSensorState(Sensor.SensorState.NONE);
|
||||
updateSensorData(null);
|
||||
return;
|
||||
}
|
||||
|
||||
Sensor.SensorDataSet sds = null;
|
||||
try {
|
||||
byte[] buff = service.getSensorData();
|
||||
if (buff != null) {
|
||||
sds = Sensor.SensorDataSet.parseFrom(buff);
|
||||
updateSensorData(sds);
|
||||
|
||||
// Check if service is available, and recording.
|
||||
boolean isRecording = false;
|
||||
if (service != null) {
|
||||
try {
|
||||
isRecording = service.isRecording();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Unable to determine if service is recording.", e);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(Constants.TAG, "Could not read sensor data.", e);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
Log.e(Constants.TAG, "Could not read sensor data.", e);
|
||||
}
|
||||
updateSensorData(sds);
|
||||
|
||||
// If either service isn't available, or not recording.
|
||||
if (!isRecording) {
|
||||
updateFromTempSensorManager();
|
||||
} else {
|
||||
updateFromSysSensorManager();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFromTempSensorManager()
|
||||
{
|
||||
// Use variables to hold the sensor state and data set.
|
||||
Sensor.SensorState currentState = null;
|
||||
Sensor.SensorDataSet currentDataSet = null;
|
||||
|
||||
// If no temp sensor manager is present, create one, and start it.
|
||||
if (tempSensorManager == null) {
|
||||
tempSensorManager = SensorManagerFactory.getSensorManager(this);
|
||||
if (tempSensorManager != null)
|
||||
tempSensorManager.onStartTrack();
|
||||
}
|
||||
|
||||
// If a temp sensor manager is available, use states from temp sensor
|
||||
// manager.
|
||||
if (tempSensorManager != null) {
|
||||
currentState = tempSensorManager.getSensorState();
|
||||
currentDataSet = tempSensorManager.getSensorDataSet();
|
||||
}
|
||||
|
||||
try {
|
||||
int i = service.getSensorState();
|
||||
updateSensorState(Sensor.SensorState.valueOf(i));
|
||||
} catch (RemoteException e) {
|
||||
Log.e(Constants.TAG, "Could not read sensor state.", e);
|
||||
updateSensorState(Sensor.SensorState.NONE);
|
||||
// Update the sensor state, and sensor data, using the variables.
|
||||
updateSensorStateAndData(currentState, currentDataSet);
|
||||
}
|
||||
|
||||
private void updateFromSysSensorManager()
|
||||
{
|
||||
// Use variables to hold the sensor state and data set.
|
||||
Sensor.SensorState currentState = null;
|
||||
Sensor.SensorDataSet currentDataSet = null;
|
||||
|
||||
ITrackRecordingService service = serviceConnection.getServiceIfBound();
|
||||
|
||||
// If a temp sensor manager is present, shut it down,
|
||||
// probably recording just started.
|
||||
stopTempSensorManager();
|
||||
|
||||
// Get sensor details from the service.
|
||||
if (service == null) {
|
||||
Log.d(TAG, "Could not get track recording service.");
|
||||
} else {
|
||||
try {
|
||||
byte[] buff = service.getSensorData();
|
||||
if (buff != null) {
|
||||
currentDataSet = Sensor.SensorDataSet.parseFrom(buff);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not read sensor data.", e);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
Log.e(TAG, "Could not read sensor data.", e);
|
||||
}
|
||||
|
||||
try {
|
||||
currentState = Sensor.SensorState.valueOf(service.getSensorState());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not read sensor state.", e);
|
||||
currentState = Sensor.SensorState.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the sensor state, and sensor data, using the variables.
|
||||
updateSensorStateAndData(currentState, currentDataSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the temporary sensor manager, if one exists.
|
||||
*/
|
||||
private void stopTempSensorManager()
|
||||
{
|
||||
if (tempSensorManager != null) {
|
||||
tempSensorManager.shutdown();
|
||||
tempSensorManager = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSensorStateAndData(Sensor.SensorState state, Sensor.SensorDataSet dataSet)
|
||||
{
|
||||
updateSensorState(state == null ? Sensor.SensorState.NONE : state);
|
||||
updateSensorData(dataSet);
|
||||
}
|
||||
|
||||
private void updateSensorState(Sensor.SensorState state) {
|
||||
|
||||
@@ -54,15 +54,44 @@ import java.util.Set;
|
||||
/**
|
||||
* An activity that let's the user see and edit the settings.
|
||||
*
|
||||
* This activity has two entry points, "root" and "display" preference screen.
|
||||
* If bundle.getString("open_settings_screen") is set to "display_settings_screen_key", then
|
||||
* the "display" preference screen is shown, otherwise, the "root" display preference is shown.
|
||||
*
|
||||
* @author Leif Hendrik Wilden
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class SettingsActivity extends PreferenceActivity {
|
||||
|
||||
// Value when the task frequency is off.
|
||||
private static final String TASK_FREQUENCY_OFF = "0";
|
||||
|
||||
// Value when the recording interval is 'Adapt battery life'.
|
||||
private static final String RECORDING_INTERVAL_ADAPT_BATTERY_LIFE = "-2";
|
||||
|
||||
// Value when the recording interval is 'Adapt accuracy'.
|
||||
private static final String RECORDING_INTERVAL_ADAPT_ACCURACY = "-1";
|
||||
|
||||
// Value for the recommended recording interval.
|
||||
private static final String RECORDING_INTERVAL_RECOMMENDED = "0";
|
||||
|
||||
// Value when the auto resume timeout is never.
|
||||
private static final String AUTO_RESUME_TIMEOUT_NEVER = "0";
|
||||
|
||||
// Value when the auto resume timeout is always.
|
||||
private static final String AUTO_RESUME_TIMEOUT_ALWAYS = "-1";
|
||||
|
||||
// Value for the recommended recording distance.
|
||||
private static final String RECORDING_DISTANCE_RECOMMENDED = "5";
|
||||
|
||||
// Value for the recommended track distance.
|
||||
private static final String TRACK_DISTANCE_RECOMMENDED = "200";
|
||||
|
||||
// Value for the recommended GPS accuracy.
|
||||
private static final String GPS_ACCURACY_RECOMMENDED = "200";
|
||||
|
||||
// Value when the GPS accuracy is for excellent GPS signal.
|
||||
private static final String GPS_ACCURACY_EXCELLENT = "10";
|
||||
|
||||
// Value when the GPS accuracy is for poor GPS signal.
|
||||
private static final String GPS_ACCURACY_POOR = "5000";
|
||||
|
||||
private BackupPreferencesListener backupListener;
|
||||
private SharedPreferences preferences;
|
||||
|
||||
@@ -71,16 +100,6 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
protected void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
initActivityCommons();
|
||||
|
||||
// If we only need the display setting screen nothing else needs to load.
|
||||
if (processIntent())
|
||||
return;
|
||||
|
||||
initActivitySpecifics();
|
||||
}
|
||||
|
||||
private void initActivityCommons() {
|
||||
// The volume we want to control is the Text-To-Speech volume
|
||||
ApiFeatures apiFeatures = ApiFeatures.getInstance();
|
||||
int volumeStream =
|
||||
@@ -93,26 +112,26 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
preferenceManager.setSharedPreferencesMode(0);
|
||||
|
||||
// Set up automatic preferences backup
|
||||
backupListener = BackupPreferencesListener.create(this, apiFeatures);
|
||||
backupListener = apiFeatures.getApiAdapter().getBackupPreferencesListener(this);
|
||||
preferences = preferenceManager.getSharedPreferences();
|
||||
preferences.registerOnSharedPreferenceChangeListener(backupListener);
|
||||
|
||||
// Load the preferences to be displayed
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
|
||||
// Disable TTS announcement preference if not available
|
||||
// Disable voice announcement if not available
|
||||
if (!apiFeatures.hasTextToSpeech()) {
|
||||
IntegerListPreference announcementFrequency =
|
||||
(IntegerListPreference) findPreference(
|
||||
getString(R.string.announcement_frequency_key));
|
||||
announcementFrequency.setEnabled(false);
|
||||
announcementFrequency.setValue("-1");
|
||||
announcementFrequency.setSummary(
|
||||
R.string.settings_not_available_summary);
|
||||
announcementFrequency.setValue(TASK_FREQUENCY_OFF);
|
||||
announcementFrequency.setSummary(R.string.settings_recording_voice_not_available);
|
||||
}
|
||||
}
|
||||
|
||||
private void initActivitySpecifics() {
|
||||
|
||||
setRecordingIntervalOptions();
|
||||
setAutoResumeTimeoutOptions();
|
||||
|
||||
// Hook up switching of displayed list entries between metric and imperial
|
||||
// units
|
||||
CheckBoxPreference metricUnitsPreference =
|
||||
@@ -124,11 +143,11 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
public boolean onPreferenceChange(Preference preference,
|
||||
Object newValue) {
|
||||
boolean isMetric = (Boolean) newValue;
|
||||
updatePreferenceUnits(isMetric);
|
||||
updateDisplayOptions(isMetric);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
updatePreferenceUnits(metricUnitsPreference.isChecked());
|
||||
updateDisplayOptions(metricUnitsPreference.isChecked());
|
||||
|
||||
customizeSensorOptionsPreferences();
|
||||
customizeTrackColorModePreferences();
|
||||
@@ -142,23 +161,85 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// Add a confirmation dialog for the 'Allow access' preference.
|
||||
final CheckBoxPreference allowAccessPreference = (CheckBoxPreference) findPreference(
|
||||
getString(R.string.allow_access_key));
|
||||
allowAccessPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if ((Boolean) newValue) {
|
||||
AlertDialog dialog = new AlertDialog.Builder(SettingsActivity.this)
|
||||
.setCancelable(true)
|
||||
.setTitle(getString(R.string.settings_sharing_allow_access))
|
||||
.setMessage(getString(R.string.settings_sharing_allow_access_confirm_message))
|
||||
.setPositiveButton(android.R.string.ok, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int button) {
|
||||
allowAccessPreference.setChecked(true);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
dialog.show();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean processIntent() {
|
||||
boolean showDisplaySettings = false;
|
||||
Bundle bundle = getIntent().getExtras();
|
||||
PreferenceScreen preferenceScreen;
|
||||
String intentString = getString(R.string.open_settings_screen);
|
||||
|
||||
if (bundle != null) {
|
||||
preferenceScreen = (PreferenceScreen) findPreference(bundle.getString(intentString));
|
||||
if (preferenceScreen != null) {
|
||||
showDisplaySettings = true;
|
||||
setPreferenceScreen(preferenceScreen);
|
||||
/**
|
||||
* Sets the display options for the 'Time between points' option.
|
||||
*/
|
||||
private void setRecordingIntervalOptions() {
|
||||
String[] values = getResources().getStringArray(R.array.recording_interval_values);
|
||||
String[] options = new String[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (values[i].equals(RECORDING_INTERVAL_ADAPT_BATTERY_LIFE)) {
|
||||
options[i] = getString(R.string.value_adapt_battery_life);
|
||||
} else if (values[i].equals(RECORDING_INTERVAL_ADAPT_ACCURACY)) {
|
||||
options[i] = getString(R.string.value_adapt_accuracy);
|
||||
} else if (values[i].equals(RECORDING_INTERVAL_RECOMMENDED)) {
|
||||
options[i] = getString(R.string.value_smallest_recommended);
|
||||
} else {
|
||||
int value = Integer.parseInt(values[i]);
|
||||
String format;
|
||||
if (value < 60) {
|
||||
format = getString(R.string.value_integer_second);
|
||||
} else {
|
||||
value = value / 60;
|
||||
format = getString(R.string.value_integer_minute);
|
||||
}
|
||||
options[i] = String.format(format, value);
|
||||
}
|
||||
}
|
||||
|
||||
return showDisplaySettings;
|
||||
ListPreference list = (ListPreference) findPreference(
|
||||
getString(R.string.min_recording_interval_key));
|
||||
list.setEntries(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the display options for the 'Auto-resume timeout' option.
|
||||
*/
|
||||
private void setAutoResumeTimeoutOptions() {
|
||||
String[] values = getResources().getStringArray(R.array.recording_auto_resume_timeout_values);
|
||||
String[] options = new String[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (values[i].equals(AUTO_RESUME_TIMEOUT_NEVER)) {
|
||||
options[i] = getString(R.string.value_never);
|
||||
} else if (values[i].equals(AUTO_RESUME_TIMEOUT_ALWAYS)) {
|
||||
options[i] = getString(R.string.value_always);
|
||||
} else {
|
||||
int value = Integer.parseInt(values[i]);
|
||||
String format = getString(R.string.value_integer_minute);
|
||||
options[i] = String.format(format, value);
|
||||
}
|
||||
}
|
||||
ListPreference list = (ListPreference) findPreference(
|
||||
getString(R.string.auto_resume_track_timeout_key));
|
||||
list.setEntries(options);
|
||||
}
|
||||
|
||||
private void customizeSensorOptionsPreferences() {
|
||||
@@ -182,7 +263,7 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
|
||||
Set<Integer> toRemove = new HashSet<Integer>();
|
||||
|
||||
String[] antValues = getResources().getStringArray(R.array.ant_sensor_type_values);
|
||||
String[] antValues = getResources().getStringArray(R.array.sensor_type_ant_values);
|
||||
for (String antValue : antValues) {
|
||||
toRemove.add(sensorTypePreference.findIndexOfValue(antValue));
|
||||
}
|
||||
@@ -224,21 +305,19 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
|
||||
setTrackColorModePreferenceListeners();
|
||||
|
||||
PreferenceCategory speedOptionsCategory =
|
||||
(PreferenceCategory) findPreference(getString(R.string.track_color_mode_fixed_speed_options_key));
|
||||
PreferenceCategory speedOptionsCategory = (PreferenceCategory) findPreference(
|
||||
getString(R.string.track_color_mode_fixed_speed_options_key));
|
||||
|
||||
speedOptionsCategory.removePreference(findPreference(getString(R.string.track_color_mode_fixed_speed_slow_key)));
|
||||
speedOptionsCategory.removePreference(findPreference(getString(R.string.track_color_mode_fixed_speed_medium_key)));
|
||||
speedOptionsCategory.removePreference(
|
||||
findPreference(getString(R.string.track_color_mode_fixed_speed_slow_key)));
|
||||
speedOptionsCategory.removePreference(
|
||||
findPreference(getString(R.string.track_color_mode_fixed_speed_medium_key)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// If we only need the display setting screen nothing else needs to load.
|
||||
if (processIntent())
|
||||
return;
|
||||
|
||||
configureBluetoothPreferences();
|
||||
Preference backupNowPreference =
|
||||
findPreference(getString(R.string.backup_to_sd_key));
|
||||
@@ -255,10 +334,10 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
resetPreference.setEnabled(!recording);
|
||||
backupNowPreference.setSummary(
|
||||
recording ? R.string.settings_not_while_recording
|
||||
: R.string.settings_backup_to_sd_summary);
|
||||
: R.string.settings_backup_now_summary);
|
||||
restoreNowPreference.setSummary(
|
||||
recording ? R.string.settings_not_while_recording
|
||||
: R.string.settings_restore_from_sd_summary);
|
||||
: R.string.settings_backup_restore_summary);
|
||||
resetPreference.setSummary(
|
||||
recording ? R.string.settings_not_while_recording
|
||||
: R.string.settings_reset_summary);
|
||||
@@ -296,8 +375,8 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
|
||||
private void updateSensorSettings(String sensorType) {
|
||||
boolean usesBluetooth =
|
||||
getString(R.string.zephyr_sensor_type).equals(sensorType)
|
||||
|| getString(R.string.polar_sensor_type).equals(sensorType);
|
||||
getString(R.string.sensor_type_value_zephyr).equals(sensorType)
|
||||
|| getString(R.string.sensor_type_value_polar).equals(sensorType);
|
||||
findPreference(
|
||||
getString(R.string.bluetooth_sensor_key)).setEnabled(usesBluetooth);
|
||||
findPreference(
|
||||
@@ -309,63 +388,168 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
Preference antSrm = findPreference(getString(R.string.ant_srm_bridge_sensor_id_key));
|
||||
if (antHrm != null && antSrm != null) {
|
||||
antHrm
|
||||
.setEnabled(getString(R.string.ant_sensor_type).equals(sensorType));
|
||||
.setEnabled(getString(R.string.sensor_type_value_ant).equals(sensorType));
|
||||
antSrm
|
||||
.setEnabled(getString(R.string.srm_ant_bridge_sensor_type).equals(sensorType));
|
||||
.setEnabled(getString(R.string.sensor_type_value_srm_ant_bridge).equals(sensorType));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTrackColorModeSettings(String trackColorMode) {
|
||||
boolean usesFixedSpeed = trackColorMode.equals(getString(R.string.track_color_mode_fixed));
|
||||
boolean usesDynamicSpeed = trackColorMode.equals(getString(R.string.track_color_mode_dynamic));
|
||||
|
||||
findPreference(
|
||||
getString(R.string.track_color_mode_fixed_speed_slow_display_key)).setEnabled(usesFixedSpeed);
|
||||
findPreference(
|
||||
getString(R.string.track_color_mode_fixed_speed_medium_display_key)).setEnabled(usesFixedSpeed);
|
||||
findPreference(
|
||||
getString(R.string.track_color_mode_dynamic_speed_variation_key)).setEnabled(usesDynamicSpeed);
|
||||
boolean usesFixedSpeed =
|
||||
trackColorMode.equals(getString(R.string.display_track_color_value_fixed));
|
||||
boolean usesDynamicSpeed =
|
||||
trackColorMode.equals(getString(R.string.display_track_color_value_dynamic));
|
||||
|
||||
findPreference(getString(R.string.track_color_mode_fixed_speed_slow_display_key))
|
||||
.setEnabled(usesFixedSpeed);
|
||||
findPreference(getString(R.string.track_color_mode_fixed_speed_medium_display_key))
|
||||
.setEnabled(usesFixedSpeed);
|
||||
findPreference(getString(R.string.track_color_mode_dynamic_speed_variation_key))
|
||||
.setEnabled(usesDynamicSpeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all the preferences which give options with distance units to use
|
||||
* the proper unit the user has selected.
|
||||
* Updates display options that depends on the preferred distance units, metric or imperial.
|
||||
*
|
||||
* @param isMetric true to use metric units, false to use imperial
|
||||
*/
|
||||
private void updatePreferenceUnits(boolean isMetric) {
|
||||
final ListPreference minRecordingDistance =
|
||||
(ListPreference) findPreference(
|
||||
getString(R.string.min_recording_distance_key));
|
||||
final ListPreference maxRecordingDistance =
|
||||
(ListPreference) findPreference(
|
||||
getString(R.string.max_recording_distance_key));
|
||||
final ListPreference minRequiredAccuracy =
|
||||
(ListPreference) findPreference(
|
||||
getString(R.string.min_required_accuracy_key));
|
||||
|
||||
minRecordingDistance.setEntries(isMetric
|
||||
? R.array.min_recording_distance_options
|
||||
: R.array.min_recording_distance_options_ft);
|
||||
maxRecordingDistance.setEntries(isMetric
|
||||
? R.array.max_recording_distance_options
|
||||
: R.array.max_recording_distance_options_ft);
|
||||
minRequiredAccuracy.setEntries(isMetric
|
||||
? R.array.min_required_accuracy_options
|
||||
: R.array.min_required_accuracy_options_ft);
|
||||
private void updateDisplayOptions(boolean isMetric) {
|
||||
setTaskOptions(isMetric, R.string.announcement_frequency_key);
|
||||
setTaskOptions(isMetric, R.string.split_frequency_key);
|
||||
setRecordingDistanceOptions(isMetric, R.string.min_recording_distance_key);
|
||||
setTrackDistanceOptions(isMetric, R.string.max_recording_distance_key);
|
||||
setGpsAccuracyOptions(isMetric, R.string.min_required_accuracy_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user visible options for a periodic task.
|
||||
* Sets the display options for a periodic task.
|
||||
*/
|
||||
private void setTaskOptions(boolean isMetric, int listId) {
|
||||
final ListPreference taskFrequency =
|
||||
(ListPreference) findPreference(getString(listId));
|
||||
taskFrequency.setEntries(isMetric
|
||||
? R.array.task_frequency_options
|
||||
: R.array.task_frequency_options_ft);
|
||||
String[] values = getResources().getStringArray(R.array.recording_task_frequency_values);
|
||||
String[] options = new String[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (values[i].equals(TASK_FREQUENCY_OFF)) {
|
||||
options[i] = getString(R.string.value_off);
|
||||
} else if (values[i].startsWith("-")) {
|
||||
int value = Integer.parseInt(values[i].substring(1));
|
||||
int stringId = isMetric ? R.string.value_integer_kilometer : R.string.value_integer_mile;
|
||||
String format = getString(stringId);
|
||||
options[i] = String.format(format, value);
|
||||
} else {
|
||||
int value = Integer.parseInt(values[i]);
|
||||
String format = getString(R.string.value_integer_minute);
|
||||
options[i] = String.format(format, value);
|
||||
}
|
||||
}
|
||||
|
||||
ListPreference list = (ListPreference) findPreference(getString(listId));
|
||||
list.setEntries(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the display options for 'Distance between points' option.
|
||||
*/
|
||||
private void setRecordingDistanceOptions(boolean isMetric, int listId) {
|
||||
String[] values = getResources().getStringArray(R.array.recording_distance_values);
|
||||
String[] options = new String[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
int value = Integer.parseInt(values[i]);
|
||||
if (!isMetric) {
|
||||
value = (int) (value * UnitConversions.M_TO_FT);
|
||||
}
|
||||
String format;
|
||||
if (values[i].equals(RECORDING_DISTANCE_RECOMMENDED)) {
|
||||
int stringId = isMetric ? R.string.value_integer_meter_recommended
|
||||
: R.string.value_integer_feet_recommended;
|
||||
format = getString(stringId);
|
||||
} else {
|
||||
int stringId = isMetric ? R.string.value_integer_meter : R.string.value_integer_feet;
|
||||
format = getString(stringId);
|
||||
}
|
||||
options[i] = String.format(format, value);
|
||||
}
|
||||
|
||||
ListPreference list = (ListPreference) findPreference(getString(listId));
|
||||
list.setEntries(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the display options for 'Distance between Tracks'.
|
||||
*/
|
||||
private void setTrackDistanceOptions(boolean isMetric, int listId) {
|
||||
String[] values = getResources().getStringArray(R.array.recording_track_distance_values);
|
||||
String[] options = new String[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
int value = Integer.parseInt(values[i]);
|
||||
String format;
|
||||
if (isMetric) {
|
||||
int stringId = values[i].equals(TRACK_DISTANCE_RECOMMENDED)
|
||||
? R.string.value_integer_meter_recommended : R.string.value_integer_meter;
|
||||
format = getString(stringId);
|
||||
options[i] = String.format(format, value);
|
||||
} else {
|
||||
value = (int) (value * UnitConversions.M_TO_FT);
|
||||
if (value < 2000) {
|
||||
int stringId = values[i].equals(TRACK_DISTANCE_RECOMMENDED)
|
||||
? R.string.value_integer_feet_recommended : R.string.value_integer_feet;
|
||||
format = getString(stringId);
|
||||
options[i] = String.format(format, value);
|
||||
} else {
|
||||
double mile = value / UnitConversions.MI_TO_FEET;
|
||||
format = getString(R.string.value_float_mile);
|
||||
options[i] = String.format(format, mile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListPreference list = (ListPreference) findPreference(getString(listId));
|
||||
list.setEntries(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the display options for 'GPS accuracy'.
|
||||
*/
|
||||
private void setGpsAccuracyOptions(boolean isMetric, int listId) {
|
||||
String[] values = getResources().getStringArray(R.array.recording_gps_accuracy_values);
|
||||
String[] options = new String[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
int value = Integer.parseInt(values[i]);
|
||||
String format;
|
||||
if (isMetric) {
|
||||
if (values[i].equals(GPS_ACCURACY_RECOMMENDED)) {
|
||||
format = getString(R.string.value_integer_meter_recommended);
|
||||
} else if (values[i].equals(GPS_ACCURACY_EXCELLENT)) {
|
||||
format = getString(R.string.value_integer_meter_excellent_gps);
|
||||
} else if (values[i].equals(GPS_ACCURACY_POOR)) {
|
||||
format = getString(R.string.value_integer_meter_poor_gps);
|
||||
} else {
|
||||
format = getString(R.string.value_integer_meter);
|
||||
}
|
||||
options[i] = String.format(format, value);
|
||||
} else {
|
||||
value = (int) (value * UnitConversions.M_TO_FT);
|
||||
if (value < 2000) {
|
||||
if (values[i].equals(GPS_ACCURACY_RECOMMENDED)) {
|
||||
format = getString(R.string.value_integer_feet_recommended);
|
||||
} else if (values[i].equals(GPS_ACCURACY_EXCELLENT)) {
|
||||
format = getString(R.string.value_integer_feet_excellent_gps);
|
||||
} else {
|
||||
format = getString(R.string.value_integer_feet);
|
||||
}
|
||||
options[i] = String.format(format, value);
|
||||
} else {
|
||||
double mile = value / UnitConversions.MI_TO_FEET;
|
||||
if (values[i].equals(GPS_ACCURACY_POOR)) {
|
||||
format = getString(R.string.value_float_mile_poor_gps);
|
||||
} else {
|
||||
format = getString(R.string.value_float_mile);
|
||||
}
|
||||
options[i] = String.format(format, mile);
|
||||
}
|
||||
}
|
||||
}
|
||||
ListPreference list = (ListPreference) findPreference(getString(listId));
|
||||
list.setEntries(options);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -482,15 +666,15 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
* Saves the given edit text preference value.
|
||||
* If the units are not metric convert the value before saving.
|
||||
*/
|
||||
private void validateTrackColorModeSettings(EditTextPreference preference,
|
||||
String newValue, int id) {
|
||||
private void validateTrackColorModeSettings(String newValue, int id) {
|
||||
CheckBoxPreference metricUnitsPreference = (CheckBoxPreference) findPreference(
|
||||
getString(R.string.metric_units_key));
|
||||
String metricspeed;
|
||||
if(!metricUnitsPreference.isChecked()) {
|
||||
// Convert miles/h to km/h
|
||||
try {
|
||||
metricspeed = String.valueOf((int) (Double.parseDouble(newValue) * UnitConversions.MPH_TO_KMH) + 1);
|
||||
metricspeed = String.valueOf(
|
||||
(int) (Double.parseDouble(newValue) * UnitConversions.MPH_TO_KMH) + 1);
|
||||
} catch (NumberFormatException e) {
|
||||
metricspeed = "0";
|
||||
}
|
||||
@@ -522,7 +706,7 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference,
|
||||
Object newValue) {
|
||||
validateTrackColorModeSettings((EditTextPreference) preference, (String) newValue, metricKey);
|
||||
validateTrackColorModeSettings((String) newValue, metricKey);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -33,8 +33,6 @@ import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.Window;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
@@ -68,12 +66,6 @@ public class StatsActivity extends Activity implements TrackDataListener {
|
||||
*/
|
||||
private long startTime = -1;
|
||||
|
||||
/**
|
||||
* If true, the statistics for the current segment are shown, otherwise
|
||||
* for the full track.
|
||||
*/
|
||||
private boolean showCurrentSegment = false;
|
||||
|
||||
private TrackDataHub dataHub;
|
||||
private SharedPreferences preferences;
|
||||
|
||||
@@ -185,43 +177,12 @@ public class StatsActivity extends Activity implements TrackDataListener {
|
||||
@Override
|
||||
public void run() {
|
||||
utils.updateUnits();
|
||||
utils.setSpeedLabel(R.id.speed_label, R.string.speed, R.string.pace_label);
|
||||
utils.setSpeedLabel(R.id.speed_label, R.string.stat_speed, R.string.stat_pace);
|
||||
utils.setSpeedLabels();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
MenuItem currentSegment = menu.add(0,
|
||||
Constants.MENU_CURRENT_SEGMENT, 0, R.string.current_segment);
|
||||
currentSegment.setIcon(R.drawable.ic_menu_lastsegment);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
MenuItem item = menu.findItem(Constants.MENU_CURRENT_SEGMENT);
|
||||
if (item != null) {
|
||||
item.setTitle(showCurrentSegment
|
||||
? getString(R.string.current_track)
|
||||
: getString(R.string.current_segment));
|
||||
}
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case Constants.MENU_CURRENT_SEGMENT:
|
||||
showCurrentSegment = !showCurrentSegment;
|
||||
// TODO: Re-read only the data that interests us
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the given location fields (latitude, longitude, altitude) and all
|
||||
* other fields.
|
||||
|
||||
@@ -20,13 +20,13 @@ import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.NumberFormat;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.util.Log;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.NumberFormat;
|
||||
|
||||
/**
|
||||
* Various utility functions for views that display statistics information.
|
||||
*
|
||||
@@ -77,7 +77,7 @@ public class StatsUtilities {
|
||||
}
|
||||
|
||||
public void setUnknown(int id) {
|
||||
((TextView) activity.findViewById(id)).setText(R.string.unknown);
|
||||
((TextView) activity.findViewById(id)).setText(R.string.value_unknown);
|
||||
}
|
||||
|
||||
public void setText(int id, double d, NumberFormat format) {
|
||||
@@ -128,24 +128,24 @@ public class StatsUtilities {
|
||||
|
||||
public void setAltitudeUnits(int unitLabelId) {
|
||||
TextView unitTextView = (TextView) activity.findViewById(unitLabelId);
|
||||
unitTextView.setText(metricUnits ? R.string.meter : R.string.feet);
|
||||
unitTextView.setText(metricUnits ? R.string.unit_meter : R.string.unit_feet);
|
||||
}
|
||||
|
||||
public void setDistanceUnits(int unitLabelId) {
|
||||
TextView unitTextView = (TextView) activity.findViewById(unitLabelId);
|
||||
unitTextView.setText(metricUnits ? R.string.kilometer : R.string.mile);
|
||||
unitTextView.setText(metricUnits ? R.string.unit_kilometer : R.string.unit_mile);
|
||||
}
|
||||
|
||||
public void setSpeedUnits(int unitLabelId, int unitLabelBottomId) {
|
||||
TextView unitTextView = (TextView) activity.findViewById(unitLabelId);
|
||||
unitTextView.setText(reportSpeed
|
||||
? (metricUnits ? R.string.kilometer : R.string.mile)
|
||||
: R.string.min);
|
||||
? (metricUnits ? R.string.unit_kilometer : R.string.unit_mile)
|
||||
: R.string.unit_minute);
|
||||
|
||||
unitTextView = (TextView) activity.findViewById(unitLabelBottomId);
|
||||
unitTextView.setText(reportSpeed
|
||||
? R.string.hr
|
||||
: (metricUnits ? R.string.kilometer : R.string.mile));
|
||||
? R.string.unit_hour
|
||||
: (metricUnits ? R.string.unit_kilometer : R.string.unit_mile));
|
||||
}
|
||||
|
||||
public void setTime(int id, long l) {
|
||||
@@ -251,13 +251,13 @@ public class StatsUtilities {
|
||||
|
||||
public void setSpeedLabels() {
|
||||
setSpeedLabel(R.id.average_speed_label,
|
||||
R.string.average_speed_label,
|
||||
R.string.average_pace_label);
|
||||
R.string.stat_average_speed,
|
||||
R.string.stat_average_pace);
|
||||
setSpeedLabel(R.id.average_moving_speed_label,
|
||||
R.string.average_moving_speed_label,
|
||||
R.string.average_moving_pace_label);
|
||||
R.string.stat_average_moving_speed,
|
||||
R.string.stat_average_moving_pace);
|
||||
setSpeedLabel(R.id.max_speed_label,
|
||||
R.string.max_speed_label,
|
||||
R.string.min_pace_label);
|
||||
R.string.stat_max_speed,
|
||||
R.string.stat_min_pace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class TrackDetails extends Activity implements OnClickListener {
|
||||
cancel.setOnClickListener(this);
|
||||
cancel.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
cancel.setVisibility(View.GONE);
|
||||
cancel.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
Button save = (Button) findViewById(R.id.trackdetails_save);
|
||||
save.setOnClickListener(this);
|
||||
|
||||
@@ -75,44 +75,48 @@ public class TrackList extends ListActivity
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||
ContextMenuInfo menuInfo) {
|
||||
menu.setHeaderTitle(R.string.tracklist_this_track);
|
||||
menu.setHeaderTitle(R.string.track_list_context_menu_title);
|
||||
AdapterView.AdapterContextMenuInfo info =
|
||||
(AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
contextPosition = info.position;
|
||||
trackId = TrackList.this.listView.getAdapter().getItemId(
|
||||
contextPosition);
|
||||
menu.add(0, Constants.MENU_SHOW, 0,
|
||||
R.string.tracklist_show_track);
|
||||
R.string.track_list_show_on_map);
|
||||
menu.add(0, Constants.MENU_EDIT, 0,
|
||||
R.string.tracklist_edit_track);
|
||||
R.string.track_list_edit_track);
|
||||
if (!isRecording() || trackId != recordingTrackId) {
|
||||
String saveFileFormat = getString(R.string.track_list_save_file);
|
||||
String shareFileFormat = getString(R.string.track_list_share_file);
|
||||
String fileTypes[] = getResources().getStringArray(R.array.file_types);
|
||||
|
||||
menu.add(0, Constants.MENU_SEND_TO_GOOGLE, 0,
|
||||
R.string.tracklist_send_to_google);
|
||||
R.string.track_list_send_google);
|
||||
SubMenu share = menu.addSubMenu(0, Constants.MENU_SHARE, 0,
|
||||
R.string.tracklist_share_track);
|
||||
R.string.track_list_share_track);
|
||||
share.add(0, Constants.MENU_SHARE_LINK, 0,
|
||||
R.string.tracklist_share_link);
|
||||
share.add(0, Constants.MENU_SHARE_GPX_FILE, 0,
|
||||
R.string.tracklist_share_gpx_file);
|
||||
share.add(0, Constants.MENU_SHARE_KML_FILE, 0,
|
||||
R.string.tracklist_share_kml_file);
|
||||
share.add(0, Constants.MENU_SHARE_CSV_FILE, 0,
|
||||
R.string.tracklist_share_csv_file);
|
||||
share.add(0, Constants.MENU_SHARE_TCX_FILE, 0,
|
||||
R.string.tracklist_share_tcx_file);
|
||||
R.string.track_list_share_url);
|
||||
share.add(
|
||||
0, Constants.MENU_SHARE_GPX_FILE, 0, String.format(shareFileFormat, fileTypes[0]));
|
||||
share.add(
|
||||
0, Constants.MENU_SHARE_KML_FILE, 0, String.format(shareFileFormat, fileTypes[1]));
|
||||
share.add(
|
||||
0, Constants.MENU_SHARE_CSV_FILE, 0, String.format(shareFileFormat, fileTypes[2]));
|
||||
share.add(
|
||||
0, Constants.MENU_SHARE_TCX_FILE, 0, String.format(shareFileFormat, fileTypes[3]));
|
||||
SubMenu save = menu.addSubMenu(0,
|
||||
Constants.MENU_WRITE_TO_SD_CARD, 0,
|
||||
R.string.tracklist_write_to_sd);
|
||||
save.add(0, Constants.MENU_SAVE_GPX_FILE, 0,
|
||||
R.string.tracklist_save_as_gpx);
|
||||
save.add(0, Constants.MENU_SAVE_KML_FILE, 0,
|
||||
R.string.tracklist_save_as_kml);
|
||||
save.add(0, Constants.MENU_SAVE_CSV_FILE, 0,
|
||||
R.string.tracklist_save_as_csv);
|
||||
save.add(0, Constants.MENU_SAVE_TCX_FILE, 0,
|
||||
R.string.tracklist_save_as_tcx);
|
||||
R.string.track_list_save_sd);
|
||||
save.add(
|
||||
0, Constants.MENU_SAVE_GPX_FILE, 0, String.format(saveFileFormat, fileTypes[0]));
|
||||
save.add(
|
||||
0, Constants.MENU_SAVE_KML_FILE, 0, String.format(saveFileFormat, fileTypes[1]));
|
||||
save.add(
|
||||
0, Constants.MENU_SAVE_CSV_FILE, 0, String.format(saveFileFormat, fileTypes[2]));
|
||||
save.add(
|
||||
0, Constants.MENU_SAVE_TCX_FILE, 0, String.format(saveFileFormat, fileTypes[3]));
|
||||
menu.add(0, Constants.MENU_DELETE, 0,
|
||||
R.string.tracklist_delete_track);
|
||||
R.string.track_list_delete_track);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -312,17 +316,17 @@ public class TrackList extends ListActivity
|
||||
if (metricUnits) {
|
||||
if (length > 1000) {
|
||||
length /= 1000;
|
||||
lengthUnit = getString(R.string.kilometer);
|
||||
lengthUnit = getString(R.string.unit_kilometer);
|
||||
} else {
|
||||
lengthUnit = getString(R.string.meter);
|
||||
lengthUnit = getString(R.string.unit_meter);
|
||||
}
|
||||
} else {
|
||||
if (length > UnitConversions.MI_TO_M) {
|
||||
length /= UnitConversions.MI_TO_M;
|
||||
lengthUnit = getString(R.string.mile);
|
||||
lengthUnit = getString(R.string.unit_mile);
|
||||
} else {
|
||||
length *= UnitConversions.M_TO_FT;
|
||||
lengthUnit = getString(R.string.feet);
|
||||
lengthUnit = getString(R.string.unit_feet);
|
||||
}
|
||||
}
|
||||
textView.setText(String.format("%s %.2f %s",
|
||||
|
||||
@@ -110,7 +110,7 @@ public class WaypointDetails extends Activity
|
||||
cancel.setOnClickListener(this);
|
||||
cancel.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
cancel.setVisibility(View.GONE);
|
||||
cancel.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
Button save = (Button) findViewById(R.id.waypointdetails_save);
|
||||
save.setOnClickListener(this);
|
||||
|
||||
@@ -73,7 +73,7 @@ public class WaypointsList extends ListActivity
|
||||
new OnCreateContextMenuListener() {
|
||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||
ContextMenuInfo menuInfo) {
|
||||
menu.setHeaderTitle(R.string.waypointslist_this_waypoint);
|
||||
menu.setHeaderTitle(R.string.marker_list_context_menu_title);
|
||||
AdapterView.AdapterContextMenuInfo info =
|
||||
(AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
contextPosition = info.position;
|
||||
@@ -83,11 +83,11 @@ public class WaypointsList extends ListActivity
|
||||
if (waypoint != null) {
|
||||
int type = waypoint.getType();
|
||||
menu.add(0, Constants.MENU_SHOW, 0,
|
||||
R.string.waypointslist_show_waypoint);
|
||||
R.string.marker_list_show_on_map);
|
||||
menu.add(0, Constants.MENU_EDIT, 0,
|
||||
R.string.waypointslist_edit_waypoint);
|
||||
R.string.marker_list_edit_marker);
|
||||
menu.add(0, Constants.MENU_DELETE, 0,
|
||||
R.string.waypointslist_delete_waypoint).setEnabled(
|
||||
R.string.marker_list_delete_marker).setEnabled(
|
||||
recordingTrackId < 0 || type == Waypoint.TYPE_WAYPOINT ||
|
||||
info.id != providerUtils.getLastWaypointId(recordingTrackId));
|
||||
}
|
||||
@@ -211,8 +211,7 @@ public class WaypointsList extends ListActivity
|
||||
}
|
||||
long id = insertWaypoint(request);
|
||||
if (id < 0) {
|
||||
Toast.makeText(this, R.string.error_unable_to_insert_marker,
|
||||
Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, R.string.marker_insert_error, Toast.LENGTH_LONG).show();
|
||||
Log.e(Constants.TAG, "Failed to insert marker.");
|
||||
return;
|
||||
}
|
||||
@@ -227,8 +226,7 @@ public class WaypointsList extends ListActivity
|
||||
if (trackRecordingService != null) {
|
||||
long waypointId = trackRecordingService.insertWaypoint(request);
|
||||
if (waypointId >= 0) {
|
||||
Toast.makeText(this, R.string.status_statistics_inserted,
|
||||
Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, R.string.marker_insert_success, Toast.LENGTH_LONG).show();
|
||||
return waypointId;
|
||||
}
|
||||
} else {
|
||||
@@ -295,10 +293,10 @@ public class WaypointsList extends ListActivity
|
||||
public void deleteWaypoint(final long waypointId) {
|
||||
AlertDialog dialog = null;
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setMessage(getString(R.string.marker_will_be_permanently_deleted));
|
||||
builder.setTitle(getString(R.string.are_you_sure_question));
|
||||
builder.setMessage(getString(R.string.marker_list_delete_marker_confirm_message));
|
||||
builder.setTitle(getString(R.string.generic_confirm_title));
|
||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
builder.setPositiveButton(getString(R.string.yes),
|
||||
builder.setPositiveButton(getString(R.string.generic_yes),
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
@@ -307,7 +305,7 @@ public class WaypointsList extends ListActivity
|
||||
new StringUtils(WaypointsList.this));
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(getString(R.string.no),
|
||||
builder.setNegativeButton(getString(R.string.generic_no),
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
|
||||
@@ -47,7 +47,7 @@ public class WelcomeActivity extends Activity {
|
||||
WebView web = (WebView) findViewById(R.id.welcome_web);
|
||||
web.loadUrl("file:///android_asset/welcome.html");
|
||||
|
||||
findViewById(R.id.welcome_read_later).setOnClickListener(
|
||||
findViewById(R.id.welcome_ok).setOnClickListener(
|
||||
new OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
finish();
|
||||
@@ -71,8 +71,8 @@ public class WelcomeActivity extends Activity {
|
||||
View view = li.inflate(R.layout.about, null);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setView(view);
|
||||
builder.setPositiveButton(R.string.ok, null);
|
||||
builder.setNeutralButton(R.string.license, new DialogInterface.OnClickListener() {
|
||||
builder.setPositiveButton(R.string.generic_ok, null);
|
||||
builder.setNegativeButton(R.string.about_license, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Eula.showEula(WelcomeActivity.this);
|
||||
|
||||
@@ -147,10 +147,10 @@ class DataSourcesWrapperImpl implements DataSourcesWrapper {
|
||||
// We don't have a recent GPS fix, just use cell towers if available
|
||||
loc = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
|
||||
|
||||
int toastResId = R.string.status_approximate_location;
|
||||
int toastResId = R.string.my_location_approximate_location;
|
||||
if (loc == null || loc.getTime() < now - MAX_NETWORK_AGE_MS) {
|
||||
// We don't have a recent cell tower location, let the user know:
|
||||
toastResId = R.string.status_no_location;
|
||||
toastResId = R.string.my_location_no_location;
|
||||
}
|
||||
|
||||
// Let the user know we have only an approximate location:
|
||||
|
||||
@@ -17,11 +17,13 @@ package com.google.android.apps.mytracks.content;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.UriMatcher;
|
||||
import android.database.Cursor;
|
||||
import android.database.SQLException;
|
||||
@@ -30,6 +32,8 @@ import android.database.sqlite.SQLiteException;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.database.sqlite.SQLiteQueryBuilder;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
import android.os.Process;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -183,8 +187,22 @@ public class MyTracksProvider extends ContentProvider {
|
||||
"waypoints/#", WAYPOINTS_ID);
|
||||
}
|
||||
|
||||
private boolean canAccess() {
|
||||
if (Binder.getCallingPid() == Process.myPid()) {
|
||||
return true;
|
||||
} else {
|
||||
Context context = getContext();
|
||||
SharedPreferences sharedPreferences = context.getSharedPreferences(
|
||||
Constants.SETTINGS_NAME, 0);
|
||||
return sharedPreferences.getBoolean(context.getString(R.string.allow_access_key), false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
if (!canAccess()) {
|
||||
return false;
|
||||
}
|
||||
DatabaseHelper dbHelper = new DatabaseHelper(getContext());
|
||||
try {
|
||||
db = dbHelper.getWritableDatabase();
|
||||
@@ -196,6 +214,9 @@ public class MyTracksProvider extends ContentProvider {
|
||||
|
||||
@Override
|
||||
public int delete(Uri url, String where, String[] selectionArgs) {
|
||||
if (!canAccess()) {
|
||||
return 0;
|
||||
}
|
||||
String table;
|
||||
boolean shouldVacuum = false;
|
||||
switch (urlMatcher.match(url)) {
|
||||
@@ -228,6 +249,9 @@ public class MyTracksProvider extends ContentProvider {
|
||||
|
||||
@Override
|
||||
public String getType(Uri url) {
|
||||
if (!canAccess()) {
|
||||
return null;
|
||||
}
|
||||
switch (urlMatcher.match(url)) {
|
||||
case TRACKPOINTS:
|
||||
return TrackPointsColumns.CONTENT_TYPE;
|
||||
@@ -248,6 +272,9 @@ public class MyTracksProvider extends ContentProvider {
|
||||
|
||||
@Override
|
||||
public Uri insert(Uri url, ContentValues initialValues) {
|
||||
if (!canAccess()) {
|
||||
return null;
|
||||
}
|
||||
Log.d(MyTracksProvider.TAG, "MyTracksProvider.insert");
|
||||
ContentValues values;
|
||||
if (initialValues != null) {
|
||||
@@ -276,6 +303,9 @@ public class MyTracksProvider extends ContentProvider {
|
||||
|
||||
@Override
|
||||
public int bulkInsert(Uri url, ContentValues[] valuesBulk) {
|
||||
if (!canAccess()) {
|
||||
return 0;
|
||||
}
|
||||
Log.d(MyTracksProvider.TAG, "MyTracksProvider.bulkInsert");
|
||||
int numInserted = 0;
|
||||
try {
|
||||
@@ -348,6 +378,9 @@ public class MyTracksProvider extends ContentProvider {
|
||||
public Cursor query(
|
||||
Uri url, String[] projection, String selection, String[] selectionArgs,
|
||||
String sort) {
|
||||
if (!canAccess()) {
|
||||
return null;
|
||||
}
|
||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||
int match = urlMatcher.match(url);
|
||||
String sortOrder = null;
|
||||
@@ -399,6 +432,9 @@ public class MyTracksProvider extends ContentProvider {
|
||||
@Override
|
||||
public int update(Uri url, ContentValues values, String where,
|
||||
String[] selectionArgs) {
|
||||
if (!canAccess()) {
|
||||
return 0;
|
||||
}
|
||||
int count;
|
||||
int match = urlMatcher.match(url);
|
||||
if (match == TRACKPOINTS) {
|
||||
|
||||
@@ -84,7 +84,7 @@ public class TrackDataHub {
|
||||
|
||||
/**
|
||||
* Listen to sampled-out points.
|
||||
* Listening to this without listening to {@link #SAMPLED_POINT_UPDATES}
|
||||
* Listening to this without listening to {@link #POINT_UPDATES}
|
||||
* makes no sense and may yield unexpected results.
|
||||
*/
|
||||
SAMPLED_OUT_POINT_UPDATES,
|
||||
@@ -292,7 +292,8 @@ public class TrackDataHub {
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
if (isStarted() || listenerHandlerThread.isAlive()) {
|
||||
if (isStarted() ||
|
||||
(listenerHandlerThread != null && listenerHandlerThread.isAlive())) {
|
||||
Log.e(TAG, "Forgot to stop() TrackDataHub");
|
||||
}
|
||||
|
||||
@@ -384,8 +385,8 @@ public class TrackDataHub {
|
||||
|
||||
/**
|
||||
* Loads the given track and makes it the currently-selected one.
|
||||
* It is ok to call this method before {@link start}, and in that case
|
||||
* the data will only be passed to listeners when {@link start} is called.
|
||||
* It is ok to call this method before {@link #start}, and in that case
|
||||
* the data will only be passed to listeners when {@link #start} is called.
|
||||
*
|
||||
* @param trackId the ID of the track to load
|
||||
*/
|
||||
@@ -397,7 +398,7 @@ public class TrackDataHub {
|
||||
|
||||
// Save the selection to memory and flush.
|
||||
selectedTrackId = trackId;
|
||||
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
|
||||
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(
|
||||
preferences.edit().putLong(SELECTED_TRACK_KEY, trackId));
|
||||
|
||||
// Force it to reload data from the beginning.
|
||||
@@ -800,7 +801,7 @@ public class TrackDataHub {
|
||||
/**
|
||||
* Notifies that a new track has been selected..
|
||||
*
|
||||
* @param track the new selected track
|
||||
* @param trackId the new selected track
|
||||
* @param listeners the listeners to notify
|
||||
*/
|
||||
private void notifySelectedTrackChanged(long trackId,
|
||||
|
||||
@@ -97,8 +97,8 @@ class TrackDataListeners {
|
||||
|
||||
/**
|
||||
* Registers a listener to send data to.
|
||||
* It is ok to call this method before {@link start}, and in that case
|
||||
* the data will only be passed to listeners when {@link start} is called.
|
||||
* It is ok to call this method before {@link TrackDataHub#start}, and in that case
|
||||
* the data will only be passed to listeners when {@link TrackDataHub#start} is called.
|
||||
*
|
||||
* @param listener the listener to register
|
||||
* @param dataTypes the type of data that the listener is interested in
|
||||
|
||||
@@ -135,9 +135,6 @@ public class ModernAuthManager implements AuthManager {
|
||||
* {@link Activity#onActivityResult} function
|
||||
* @param results The data passed in to the {@link Activity}'s
|
||||
* {@link Activity#onActivityResult} function
|
||||
* @return True if the auth token was fetched or we aren't done fetching
|
||||
* the auth token, or False if there was an error or the request was
|
||||
* canceled
|
||||
*/
|
||||
public void authResult(int resultCode, Intent results) {
|
||||
boolean retry = false;
|
||||
@@ -169,12 +166,11 @@ public class ModernAuthManager implements AuthManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the existing auth token and request a new one. The
|
||||
* {@link Runnable} provided will be executed when the new auth token is
|
||||
* successfully fetched.
|
||||
* Invalidates the existing auth token and request a new one. The callback
|
||||
* provided will be executed when the new auth token is successfully fetched.
|
||||
*
|
||||
* @param runnable A {@link Runnable} to execute when a new auth token
|
||||
* is successfully fetched
|
||||
* @param callback A callback to execute when a new auth token is successfully
|
||||
* fetched
|
||||
*/
|
||||
public void invalidateAndRefresh(final AuthCallback callback) {
|
||||
this.authCallback = callback;
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.io.docs.DocsHelper;
|
||||
import com.google.android.apps.mytracks.io.gdata.GDataClientFactory;
|
||||
import com.google.android.apps.mytracks.io.gdata.GDataWrapper;
|
||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendType;
|
||||
import com.google.android.common.gdata.AndroidXmlParserFactory;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import com.google.wireless.gdata.client.GDataClient;
|
||||
@@ -92,7 +93,9 @@ public class SendToDocs {
|
||||
|
||||
private void doUpload(long trackId) {
|
||||
// TODO
|
||||
statusMessage = activity.getString(R.string.error_sending_to_fusiontables);
|
||||
String errorFormat = activity.getString(R.string.send_google_error_service);
|
||||
String serviceName = activity.getString(SendType.DOCS.getServiceName());
|
||||
statusMessage = String.format(errorFormat, serviceName);
|
||||
success = false;
|
||||
|
||||
try {
|
||||
@@ -115,15 +118,11 @@ public class SendToDocs {
|
||||
Log.d(Constants.TAG, "SendToDocs: Uploading to spreadsheet");
|
||||
success = uploadToDocs(track);
|
||||
if (success) {
|
||||
if (createdNewSpreadSheet) {
|
||||
statusMessage = activity.getString(
|
||||
R.string.status_tracks_have_been_uploaded_to_new_doc);
|
||||
} else {
|
||||
statusMessage = activity.getString(
|
||||
R.string.status_tracks_have_been_uploaded_to_docs);
|
||||
}
|
||||
} else {
|
||||
statusMessage = activity.getString(R.string.error_sending_to_docs);
|
||||
String successFormat = createdNewSpreadSheet
|
||||
? activity.getString(R.string.send_google_success_new)
|
||||
: activity.getString(R.string.send_google_success_existing);
|
||||
String url = activity.getString(SendType.DOCS.getServiceUrl());
|
||||
statusMessage = String.format(successFormat, serviceName, url);
|
||||
}
|
||||
Log.d(Constants.TAG, "SendToDocs: Done.");
|
||||
} finally {
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.io.gdata.GDataWrapper;
|
||||
import com.google.android.apps.mytracks.io.gdata.GDataWrapper.QueryFunction;
|
||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendType;
|
||||
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
@@ -41,8 +42,6 @@ import com.google.api.client.http.HttpResponse;
|
||||
import com.google.api.client.http.HttpResponseException;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.http.InputStreamContent;
|
||||
import com.google.api.client.http.apache.ApacheHttpTransport;
|
||||
import com.google.api.client.http.javanet.NetHttpTransport;
|
||||
import com.google.api.client.util.Strings;
|
||||
|
||||
import android.app.Activity;
|
||||
@@ -73,7 +72,7 @@ public class SendToFusionTables implements Runnable {
|
||||
* Listener invoked when sending to fusion tables completes.
|
||||
*/
|
||||
public interface OnSendCompletedListener {
|
||||
void onSendCompleted(String tableId, boolean success, int statusMessage);
|
||||
void onSendCompleted(String tableId, boolean success, String statusMessage);
|
||||
}
|
||||
|
||||
/** The GData service id for Fusion Tables. */
|
||||
@@ -140,8 +139,7 @@ public class SendToFusionTables implements Runnable {
|
||||
this.stringUtils = new StringUtils(context);
|
||||
this.providerUtils = MyTracksProviderUtils.Factory.get(context);
|
||||
|
||||
HttpTransport transport = ApiFeatures.getInstance().useNetHttpTransport()
|
||||
? new NetHttpTransport() : new ApacheHttpTransport();
|
||||
HttpTransport transport = ApiFeatures.getInstance().getApiAdapter().getHttpTransport();
|
||||
httpRequestFactory = transport.createRequestFactory(new MethodOverride());
|
||||
}
|
||||
|
||||
@@ -171,11 +169,14 @@ public class SendToFusionTables implements Runnable {
|
||||
}
|
||||
|
||||
private void doUpload() {
|
||||
int statusMessageId = R.string.error_sending_to_fusiontables;
|
||||
String errorFormat = context.getString(R.string.send_google_error_service);
|
||||
String serviceName = context.getString(SendType.FUSION_TABLES.getServiceName());
|
||||
String statusMessage = String.format(errorFormat, serviceName);
|
||||
boolean success = true;
|
||||
try {
|
||||
progressIndicator.setProgressValue(PROGRESS_INITIALIZATION);
|
||||
progressIndicator.setProgressMessage(R.string.progress_message_reading_track);
|
||||
progressIndicator.setProgressMessage(
|
||||
context.getString(R.string.send_google_progress_reading_track));
|
||||
|
||||
// Get the track meta-data
|
||||
Track track = providerUtils.getTrack(trackId);
|
||||
@@ -188,13 +189,15 @@ public class SendToFusionTables implements Runnable {
|
||||
|
||||
// Create a new table:
|
||||
progressIndicator.setProgressValue(PROGRESS_FUSION_TABLE_CREATE);
|
||||
progressIndicator.setProgressMessage(R.string.progress_message_creating_fusiontable);
|
||||
String creatingFormat = context.getString(R.string.send_google_progress_creating);
|
||||
progressIndicator.setProgressMessage(String.format(creatingFormat, serviceName));
|
||||
if (!createNewTable(track) || !makeTableUnlisted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
progressIndicator.setProgressValue(PROGRESS_UPLOAD_DATA_MIN);
|
||||
progressIndicator.setProgressMessage(R.string.progress_message_sending_fusiontables);
|
||||
String sendingFormat = context.getString(R.string.send_google_progress_sending);
|
||||
progressIndicator.setProgressMessage(String.format(sendingFormat, serviceName));
|
||||
|
||||
// Upload all of the segments of the track plus start/end markers
|
||||
if (!uploadAllTrackPoints(track, originalDescription)) {
|
||||
@@ -208,17 +211,18 @@ public class SendToFusionTables implements Runnable {
|
||||
return;
|
||||
}
|
||||
|
||||
statusMessageId = R.string.status_new_fusiontable_has_been_created;
|
||||
String successFormat = context.getString(R.string.send_google_success_new);
|
||||
String url = context.getString(SendType.FUSION_TABLES.getServiceUrl());
|
||||
statusMessage = String.format(successFormat, serviceName, url);
|
||||
Log.d(Constants.TAG, "SendToFusionTables: Done: " + success);
|
||||
progressIndicator.setProgressValue(PROGRESS_COMPLETE);
|
||||
} finally {
|
||||
final boolean finalSuccess = success;
|
||||
final int finalStatusMessageId = statusMessageId;
|
||||
final String finalStatusMessage = statusMessage;
|
||||
context.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if (onCompletion != null) {
|
||||
onCompletion.onSendCompleted(
|
||||
tableId, finalSuccess, finalStatusMessageId);
|
||||
onCompletion.onSendCompleted(tableId, finalSuccess, finalStatusMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -342,7 +346,7 @@ public class SendToFusionTables implements Runnable {
|
||||
|
||||
if (totalLocationsRead == 0) {
|
||||
// Put a marker at the first point of the first valid segment:
|
||||
String name = track.getName() + " " + context.getString(R.string.start);
|
||||
String name = track.getName() + " " + context.getString(R.string.marker_label_start);
|
||||
createNewPoint(name, "", loc, MARKER_TYPE_START);
|
||||
}
|
||||
|
||||
@@ -388,7 +392,7 @@ public class SendToFusionTables implements Runnable {
|
||||
track.setDescription("<p>" + originalDescription + "</p><p>"
|
||||
+ stringUtils.generateTrackDescription(track, distances, elevations)
|
||||
+ "</p>");
|
||||
String name = track.getName() + " " + context.getString(R.string.end);
|
||||
String name = track.getName() + " " + context.getString(R.string.marker_label_end);
|
||||
return createNewPoint(name, track.getDescription(), lastLocation, MARKER_TYPE_END);
|
||||
}
|
||||
|
||||
@@ -465,7 +469,7 @@ public class SendToFusionTables implements Runnable {
|
||||
if (totalSegmentsUploaded > 1) {
|
||||
splitTrack.setName(splitTrack.getName() + " "
|
||||
+ String.format(
|
||||
context.getString(R.string.part), totalSegmentsUploaded));
|
||||
context.getString(R.string.send_google_track_part_label), totalSegmentsUploaded));
|
||||
}
|
||||
totalSegmentsUploaded++;
|
||||
Log.d(Constants.TAG,
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
package com.google.android.apps.mytracks.io;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.ProgressIndicator;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.io.mymaps.MapsFacade;
|
||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendType;
|
||||
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||
@@ -74,7 +76,7 @@ public class SendToMyMaps implements Runnable {
|
||||
private int totalSegmentsUploaded;
|
||||
|
||||
public interface OnSendCompletedListener {
|
||||
void onSendCompleted(String mapId, boolean success, int statusMessage);
|
||||
void onSendCompleted(String mapId, boolean success, String statusMessage);
|
||||
}
|
||||
|
||||
public SendToMyMaps(Activity context, String mapId, AuthManager auth,
|
||||
@@ -97,11 +99,13 @@ public class SendToMyMaps implements Runnable {
|
||||
}
|
||||
|
||||
private void doUpload() {
|
||||
int statusMessageId = R.string.error_sending_to_mymap;
|
||||
String errorFormat = context.getString(R.string.send_google_error_service);
|
||||
String serviceName = context.getString(SendType.MYMAPS.getServiceName());
|
||||
String statusMessage = String.format(errorFormat, serviceName);
|
||||
boolean success = true;
|
||||
try {
|
||||
progressIndicator.setProgressMessage(
|
||||
R.string.progress_message_reading_track);
|
||||
context.getString(R.string.send_google_progress_reading_track));
|
||||
|
||||
// Get the track meta-data
|
||||
Track track = providerUtils.getTrack(trackId);
|
||||
@@ -127,8 +131,8 @@ public class SendToMyMaps implements Runnable {
|
||||
context.getString(R.string.default_map_public_key), true);
|
||||
}
|
||||
|
||||
progressIndicator.setProgressMessage(
|
||||
R.string.progress_message_creating_map);
|
||||
String creatingFormat = context.getString(R.string.send_google_progress_creating);
|
||||
progressIndicator.setProgressMessage(String.format(creatingFormat, serviceName));
|
||||
|
||||
StringBuilder mapIdBuilder = new StringBuilder();
|
||||
success = mapsClient.createNewMap(
|
||||
@@ -172,9 +176,10 @@ public class SendToMyMaps implements Runnable {
|
||||
}
|
||||
|
||||
if (success) {
|
||||
statusMessageId = isNewMap
|
||||
? R.string.status_new_mymap_has_been_created
|
||||
: R.string.status_tracks_have_been_uploaded;
|
||||
String successFormat = isNewMap ? context.getString(R.string.send_google_success_new)
|
||||
: context.getString(R.string.send_google_success_existing);
|
||||
String url = context.getString(SendType.MYMAPS.getServiceUrl());
|
||||
statusMessage = String.format(successFormat, serviceName, url);
|
||||
}
|
||||
Log.d(TAG, "SendToMyMaps: Done: " + success);
|
||||
progressIndicator.setProgressValue(100);
|
||||
@@ -184,12 +189,11 @@ public class SendToMyMaps implements Runnable {
|
||||
}
|
||||
|
||||
final boolean finalSuccess = success;
|
||||
final int finalStatusMessageId = statusMessageId;
|
||||
final String finalStatusMessage = statusMessage;
|
||||
context.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if (onCompletion != null) {
|
||||
onCompletion.onSendCompleted(
|
||||
mapId, finalSuccess, finalStatusMessageId);
|
||||
onCompletion.onSendCompleted(mapId, finalSuccess, finalStatusMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -236,7 +240,7 @@ public class SendToMyMaps implements Runnable {
|
||||
|
||||
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
|
||||
progressIndicator.setProgressMessage(
|
||||
R.string.progress_message_reading_track);
|
||||
context.getString(R.string.send_google_progress_reading_track));
|
||||
Location lastLocation = null;
|
||||
do {
|
||||
if (totalLocationsRead % 100 == 0) {
|
||||
@@ -310,7 +314,7 @@ public class SendToMyMaps implements Runnable {
|
||||
|
||||
private boolean prepareAndUploadPoints(Track track, List<Location> locations) {
|
||||
progressIndicator.setProgressMessage(
|
||||
R.string.progress_message_preparing_track);
|
||||
context.getString(R.string.send_google_progress_preparing_track));
|
||||
updateProgress();
|
||||
|
||||
int numLocations = locations.size();
|
||||
@@ -324,13 +328,14 @@ public class SendToMyMaps implements Runnable {
|
||||
ArrayList<Track> splitTracks = prepareLocations(track, locations);
|
||||
|
||||
// Start uploading them
|
||||
progressIndicator.setProgressMessage(
|
||||
R.string.progress_message_sending_mymaps);
|
||||
String sendingFormat = context.getString(R.string.send_google_progress_sending);
|
||||
String serviceName = context.getString(SendType.MYMAPS.getServiceName());
|
||||
progressIndicator.setProgressMessage(String.format(sendingFormat, serviceName));
|
||||
for (Track splitTrack : splitTracks) {
|
||||
if (totalSegmentsUploaded > 1) {
|
||||
splitTrack.setName(splitTrack.getName() + " "
|
||||
+ String.format(
|
||||
context.getString(R.string.part), totalSegmentsUploaded));
|
||||
context.getString(R.string.send_google_track_part_label), totalSegmentsUploaded));
|
||||
}
|
||||
totalSegmentsUploaded++;
|
||||
Log.d(TAG,
|
||||
@@ -357,7 +362,7 @@ public class SendToMyMaps implements Runnable {
|
||||
* Prepares a buffer of locations for transmission to google maps.
|
||||
*
|
||||
* @param track the original track with meta data
|
||||
* @param buffer a buffer of locations on the track
|
||||
* @param locations a buffer of locations on the track
|
||||
* @return an array of tracks each with a sub section of the points in the
|
||||
* original buffer
|
||||
*/
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.backup;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracks;
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.MyTracks;
|
||||
import com.google.android.apps.mytracks.util.FileUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
@@ -74,19 +74,19 @@ public class BackupActivityHelper {
|
||||
*/
|
||||
public void writeBackup() {
|
||||
if (!fileUtils.isSdCardAvailable()) {
|
||||
showToast(R.string.io_no_external_storage_found);
|
||||
showToast(R.string.sd_card_error_no_storage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!backup.isBackupsDirectoryAvailable(true)) {
|
||||
showToast(R.string.io_create_dir_failed);
|
||||
showToast(R.string.sd_card_error_create_dir);
|
||||
return;
|
||||
}
|
||||
|
||||
final ProgressDialog progressDialog = ProgressDialog.show(
|
||||
activity,
|
||||
activity.getString(R.string.progress_title),
|
||||
activity.getString(R.string.backup_write_progress_message),
|
||||
activity.getString(R.string.generic_progress_title),
|
||||
activity.getString(R.string.settings_backup_now_progress_message),
|
||||
true);
|
||||
|
||||
// Do the writing in another thread
|
||||
@@ -95,10 +95,10 @@ public class BackupActivityHelper {
|
||||
public void run() {
|
||||
try {
|
||||
backup.writeToDefaultFile();
|
||||
showToast(R.string.io_write_finished);
|
||||
showToast(R.string.sd_card_success_write_file);
|
||||
} catch (IOException e) {
|
||||
Log.e(Constants.TAG, "Failed to write backup", e);
|
||||
showToast(R.string.io_write_failed);
|
||||
showToast(R.string.sd_card_error_write_file);
|
||||
} finally {
|
||||
dismissDialog(progressDialog);
|
||||
}
|
||||
@@ -114,25 +114,25 @@ public class BackupActivityHelper {
|
||||
public void restoreBackup() {
|
||||
// Get the list of existing backups
|
||||
if (!fileUtils.isSdCardAvailable()) {
|
||||
showToast(R.string.io_no_external_storage_found);
|
||||
showToast(R.string.sd_card_error_no_storage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!backup.isBackupsDirectoryAvailable(false)) {
|
||||
showToast(R.string.no_backups);
|
||||
showToast(R.string.settings_backup_restore_no_backup);
|
||||
return;
|
||||
}
|
||||
|
||||
final Date[] backupDates = backup.getAvailableBackups();
|
||||
if (backupDates == null || backupDates.length == 0) {
|
||||
showToast(R.string.no_backups);
|
||||
showToast(R.string.settings_backup_restore_no_backup);
|
||||
return;
|
||||
}
|
||||
Arrays.sort(backupDates, REVERSE_DATE_ORDER);
|
||||
|
||||
// Show a confirmation dialog
|
||||
Builder confirmationDialogBuilder = new AlertDialog.Builder(activity);
|
||||
confirmationDialogBuilder.setMessage(R.string.restore_overwrites_warning);
|
||||
confirmationDialogBuilder.setMessage(R.string.settings_backup_restore_confirm_message);
|
||||
confirmationDialogBuilder.setCancelable(true);
|
||||
confirmationDialogBuilder.setPositiveButton(android.R.string.yes,
|
||||
new OnClickListener() {
|
||||
@@ -148,7 +148,6 @@ public class BackupActivityHelper {
|
||||
/**
|
||||
* Shows a backup list for the user to pick, then restores it.
|
||||
*
|
||||
* @param backupDir the backup directory
|
||||
* @param backupDates the list of available backup files
|
||||
*/
|
||||
private void pickBackupForRestore(final Date[] backupDates) {
|
||||
@@ -167,7 +166,7 @@ public class BackupActivityHelper {
|
||||
// Show a dialog for the user to pick which backup to restore
|
||||
Builder dialogBuilder = new AlertDialog.Builder(activity);
|
||||
dialogBuilder.setCancelable(true);
|
||||
dialogBuilder.setTitle(R.string.select_backup_to_restore);
|
||||
dialogBuilder.setTitle(R.string.settings_backup_restore_select_title);
|
||||
dialogBuilder.setItems(backupDateStrs, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
@@ -179,16 +178,16 @@ public class BackupActivityHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a progress dialog, then starts restoring the backup osynchronously.
|
||||
* Shows a progress dialog, then starts restoring the backup asynchronously.
|
||||
*
|
||||
* @param inputFile the file to restore from
|
||||
* @param date the date
|
||||
*/
|
||||
private void restoreFromDateAsync(final Date date) {
|
||||
// Show a progress dialog
|
||||
ProgressDialog.show(
|
||||
activity,
|
||||
activity.getString(R.string.progress_title),
|
||||
activity.getString(R.string.backup_import_progress_message),
|
||||
activity.getString(R.string.generic_progress_title),
|
||||
activity.getString(R.string.settings_backup_restore_progress_message),
|
||||
true);
|
||||
|
||||
// Do the actual importing in another thread (don't block the UI)
|
||||
@@ -197,10 +196,10 @@ public class BackupActivityHelper {
|
||||
public void run() {
|
||||
try {
|
||||
backup.restoreFromDate(date);
|
||||
showToast(R.string.io_read_finished);
|
||||
showToast(R.string.sd_card_success_read_file);
|
||||
} catch (IOException e) {
|
||||
Log.e(Constants.TAG, "Failed to restore backup", e);
|
||||
showToast(R.string.io_read_failed);
|
||||
showToast(R.string.sd_card_error_read_file);
|
||||
} finally {
|
||||
// Data may have been restored, "reboot" the app to catch it
|
||||
restartApplication();
|
||||
|
||||
+1
-51
@@ -15,63 +15,13 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.backup;
|
||||
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
|
||||
import android.app.backup.BackupManager;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
|
||||
/**
|
||||
* Shared preferences listener which notifies the backup system about new data
|
||||
* being available for backup.
|
||||
* This class is API-version-safe and will provide a dummy implementation if
|
||||
* the device doesn't support backup services.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public abstract class BackupPreferencesListener
|
||||
implements OnSharedPreferenceChangeListener {
|
||||
|
||||
/**
|
||||
* Real implementation of the listener, which calls the {@link BackupManager}.
|
||||
*/
|
||||
private static class BackupPreferencesListenerImpl
|
||||
extends BackupPreferencesListener {
|
||||
private final BackupManager backupManager;
|
||||
|
||||
public BackupPreferencesListenerImpl(Context context) {
|
||||
this.backupManager = new BackupManager(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(
|
||||
SharedPreferences sharedPreferences, String key) {
|
||||
backupManager.dataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy implementation of the listener which does nothing.
|
||||
*/
|
||||
private static class DummyBackupPreferencesListener
|
||||
extends BackupPreferencesListener {
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(
|
||||
SharedPreferences sharedPreferences, String key) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a proper instance of the listener for this device.
|
||||
*/
|
||||
public static BackupPreferencesListener create(
|
||||
Context context, ApiFeatures apiFeatures) {
|
||||
if (apiFeatures.hasBackup()) {
|
||||
return new BackupPreferencesListenerImpl(context);
|
||||
} else {
|
||||
return new DummyBackupPreferencesListener();
|
||||
}
|
||||
}
|
||||
public interface BackupPreferencesListener extends OnSharedPreferenceChangeListener {
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2011 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.backup;
|
||||
|
||||
import android.app.backup.BackupManager;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
/**
|
||||
* Implementation of {@link BackupPreferencesListener} that calls the
|
||||
* {@link BackupManager}.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class BackupPreferencesListenerImpl implements BackupPreferencesListener {
|
||||
|
||||
private final BackupManager backupManager;
|
||||
|
||||
public BackupPreferencesListenerImpl(Context context) {
|
||||
this.backupManager = new BackupManager(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
backupManager.dataChanged();
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import com.google.wireless.gdata.parser.ParseException;
|
||||
import com.google.wireless.gdata2.client.AuthenticationException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.format.DateFormat;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
@@ -44,7 +45,6 @@ import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@@ -275,25 +275,22 @@ public class DocsHelper {
|
||||
public void addTrackRow(Context context, AuthManager trixAuth,
|
||||
String spreadsheetId, String worksheetId, Track track,
|
||||
boolean metricUnits) throws IOException {
|
||||
|
||||
String worksheetUri = String.format(DOCS_SPREADSHEET_URL_FORMAT,
|
||||
spreadsheetId, worksheetId);
|
||||
TripStatistics stats = track.getStatistics();
|
||||
|
||||
String distanceUnit = context.getString(metricUnits ?
|
||||
R.string.kilometer : R.string.mile);
|
||||
R.string.unit_kilometer : R.string.unit_mile);
|
||||
String speedUnit = context.getString(metricUnits ?
|
||||
R.string.kilometer_per_hour : R.string.mile_per_hour);
|
||||
R.string.unit_kilometer_per_hour : R.string.unit_mile_per_hour);
|
||||
String elevationUnit = context.getString(metricUnits ?
|
||||
R.string.meter : R.string.feet);
|
||||
|
||||
DateFormat trackDateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
|
||||
R.string.unit_meter : R.string.unit_feet);
|
||||
|
||||
// Prepare the Post-Text we are going to send.
|
||||
DocsTagBuilder tagBuilder = new DocsTagBuilder(metricUnits)
|
||||
.append("name", track.getName())
|
||||
.append("description", track.getDescription())
|
||||
.append("date", trackDateFormat.format(new Date(stats.getStartTime())))
|
||||
.append("date", getDisplayDate(context, stats.getStartTime()))
|
||||
.append("totaltime", StringUtils.formatTimeAlwaysShowingHours(
|
||||
stats.getTotalTime()))
|
||||
.append("movingtime", StringUtils.formatTimeAlwaysShowingHours(
|
||||
@@ -333,6 +330,21 @@ public class DocsHelper {
|
||||
Log.i(Constants.TAG, "Post finished.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display string for a time based on the phone's setting.
|
||||
*
|
||||
* @param context the context to obtain the phone's setting.
|
||||
* @param time the time
|
||||
* @return the display string of the time
|
||||
*/
|
||||
protected String getDisplayDate(Context context, long time) {
|
||||
java.text.DateFormat dateFormat = DateFormat.getDateFormat(context);
|
||||
java.text.DateFormat timeFormat = DateFormat.getTimeFormat(context);
|
||||
Date startTime = new Date(time);
|
||||
String dateString = dateFormat.format(startTime) + " " + timeFormat.format(startTime);
|
||||
return dateString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes spreadsheet row data to the indicated worksheet.
|
||||
*
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.docs;
|
||||
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
|
||||
@@ -45,8 +46,9 @@ import java.util.Locale;
|
||||
* @author Matthew Simmons
|
||||
*/
|
||||
class DocsTagBuilder {
|
||||
|
||||
private static final DecimalFormatSymbols FORMAT_SYMBOLS =
|
||||
DecimalFormatSymbols.getInstance(Locale.ENGLISH);
|
||||
ApiFeatures.getInstance().getApiAdapter().getDecimalFormatSymbols(Locale.ENGLISH);
|
||||
private static final NumberFormat LARGE_UNIT_FORMAT =
|
||||
new DecimalFormat("#,###,###.00", FORMAT_SYMBOLS);
|
||||
private static final NumberFormat SMALL_UNIT_FORMAT =
|
||||
|
||||
@@ -17,56 +17,21 @@ package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.ImportAllTracks;
|
||||
import com.google.android.apps.mytracks.util.UriUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.AlertDialog.Builder;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ContentUris;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Helper activity which imports tracks from a file.
|
||||
* An activity that imports a track from a file and displays the track in My Tracks.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class ImportActivity extends Activity {
|
||||
|
||||
private static final int PROGRESS_DIALOG = 1;
|
||||
private static final int SUCCESS_DIALOG = 2;
|
||||
private static final int FAILURE_DIALOG = 3;
|
||||
|
||||
private MyTracksProviderUtils providerUtils;
|
||||
|
||||
private ProgressDialog progressDialog;
|
||||
private int resultMessage;
|
||||
private long importedTrackIds[];
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedState) {
|
||||
super.onCreate(savedState);
|
||||
|
||||
providerUtils = MyTracksProviderUtils.Factory.get(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
@@ -74,143 +39,20 @@ public class ImportActivity extends Activity {
|
||||
Intent intent = getIntent();
|
||||
String action = intent.getAction();
|
||||
Uri data = intent.getData();
|
||||
if (!(Intent.ACTION_VIEW.equals(action) || Intent.ACTION_ATTACH_DATA.equals(action))
|
||||
|| !UriUtils.isFileUri(data)) {
|
||||
Log.e(TAG, "Received an intent with unsupported action or data: " + intent);
|
||||
if (!(Intent.ACTION_VIEW.equals(action) || Intent.ACTION_ATTACH_DATA.equals(action))) {
|
||||
Log.e(TAG, "Received an intent with unsupported action: " + intent);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i(TAG, "Importing GPX file at " + data);
|
||||
startTrackImport(data.getPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int id) {
|
||||
switch (id) {
|
||||
case PROGRESS_DIALOG:
|
||||
progressDialog = new ProgressDialog(this);
|
||||
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
|
||||
progressDialog.setTitle(R.string.progress_title);
|
||||
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||
progressDialog.setMessage(getString(R.string.import_progress_message));
|
||||
return progressDialog;
|
||||
case SUCCESS_DIALOG:
|
||||
final Builder dialogBuilder = new AlertDialog.Builder(this);
|
||||
dialogBuilder.setCancelable(true);
|
||||
dialogBuilder.setPositiveButton(android.R.string.ok, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface arg0, int arg1) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
dialogBuilder.setNeutralButton(R.string.import_show_track, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface arg0, int arg1) {
|
||||
showImportedTrack();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
return dialogBuilder.create();
|
||||
case FAILURE_DIALOG:
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setNeutralButton(R.string.ok, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface arg0, int arg1) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
builder.setTitle(R.string.error);
|
||||
return builder.create();
|
||||
|
||||
|
||||
if (!UriUtils.isFileUri(data)) {
|
||||
Log.e(TAG, "Received an intent with unsupported data: " + intent);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPrepareDialog(int id, Dialog dialog) {
|
||||
super.onPrepareDialog(id, dialog);
|
||||
|
||||
switch (id) {
|
||||
case SUCCESS_DIALOG:
|
||||
AlertDialog successDialog = (AlertDialog) dialog;
|
||||
successDialog.setMessage(getString(R.string.import_success, importedTrackIds.length));
|
||||
break;
|
||||
case FAILURE_DIALOG:
|
||||
AlertDialog failureDialog = (AlertDialog) dialog;
|
||||
failureDialog.setMessage(getString(resultMessage));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void showImportedTrack() {
|
||||
long lastTrackId = importedTrackIds[importedTrackIds.length - 1];
|
||||
Uri trackUri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, lastTrackId);
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setDataAndType(trackUri, TracksColumns.CONTENT_ITEMTYPE);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void startTrackImport(final String fileName) {
|
||||
showDialog(PROGRESS_DIALOG);
|
||||
|
||||
Thread t = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
resultMessage = R.string.success;
|
||||
|
||||
importedTrackIds = null;
|
||||
|
||||
try {
|
||||
try {
|
||||
InputStream is = new FileInputStream(fileName);
|
||||
importedTrackIds = GpxImporter.importGPXFile(is, providerUtils);
|
||||
} catch (SAXException e) {
|
||||
Log.e(TAG, "Caught an unexpected exception.", e);
|
||||
resultMessage = R.string.error_generic;
|
||||
} catch (ParserConfigurationException e) {
|
||||
Log.e(TAG, "Caught an unexpected exception.", e);
|
||||
resultMessage = R.string.error_generic;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Caught an unexpected exception.", e);
|
||||
resultMessage = R.string.error_unable_to_read_file;
|
||||
} catch (NullPointerException e) {
|
||||
Log.e(TAG, "Caught an unexpected exception.", e);
|
||||
resultMessage = R.string.error_invalid_gpx_format;
|
||||
} catch (OutOfMemoryError e) {
|
||||
Log.e(TAG, "Caught an unexpected exception.", e);
|
||||
resultMessage = R.string.error_out_of_memory;
|
||||
}
|
||||
|
||||
boolean success = (importedTrackIds != null && importedTrackIds.length > 0);
|
||||
showImportResult(success);
|
||||
} finally {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
dismissDialog(PROGRESS_DIALOG);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void showImportResult(boolean success) {
|
||||
final int dialogToShow = success ? SUCCESS_DIALOG : FAILURE_DIALOG;
|
||||
|
||||
// Show a dialog telling the user about the import, and asking if he wishes
|
||||
// to open the track right away.
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showDialog(dialogToShow);
|
||||
}
|
||||
});
|
||||
|
||||
String path = data.getPath();
|
||||
Log.i(TAG, "Importing GPX file at " + path);
|
||||
new ImportAllTracks(this, path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,9 +74,9 @@ public class SaveActivity extends Activity {
|
||||
String action = intent.getAction();
|
||||
String type = intent.getType();
|
||||
Uri data = intent.getData();
|
||||
if (!getString(R.string.save_intent_action).equals(action) ||
|
||||
!TracksColumns.CONTENT_ITEMTYPE.equals(type) ||
|
||||
!UriUtils.matchesContentUri(data, TracksColumns.CONTENT_URI)) {
|
||||
if (!getString(R.string.track_action_save).equals(action)
|
||||
|| !TracksColumns.CONTENT_ITEMTYPE.equals(type)
|
||||
|| !UriUtils.matchesContentUri(data, TracksColumns.CONTENT_URI)) {
|
||||
Log.e(TAG, "Got bad save intent: " + intent);
|
||||
finish();
|
||||
return;
|
||||
@@ -132,15 +132,16 @@ public class SaveActivity extends Activity {
|
||||
// Share the file.
|
||||
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
||||
shareIntent.putExtra(Intent.EXTRA_SUBJECT,
|
||||
getResources().getText(R.string.send_track_subject).toString());
|
||||
getResources().getText(R.string.share_track_subject).toString());
|
||||
shareIntent.putExtra(Intent.EXTRA_TEXT,
|
||||
getResources().getText(R.string.send_track_body_format)
|
||||
getResources().getText(R.string.share_track_file_body_format)
|
||||
.toString());
|
||||
shareIntent.setType(format.getMimeType());
|
||||
Uri u = Uri.fromFile(new File(writer.getAbsolutePath()));
|
||||
shareIntent.putExtra(Intent.EXTRA_STREAM, u);
|
||||
shareIntent.putExtra(getString(R.string.track_id_broadcast_extra), trackId);
|
||||
startActivity(Intent.createChooser(shareIntent,
|
||||
getResources().getText(R.string.share_track).toString()));
|
||||
getResources().getText(R.string.share_track_picker_title).toString()));
|
||||
}
|
||||
|
||||
private void showResultDialog() {
|
||||
@@ -168,7 +169,7 @@ public class SaveActivity extends Activity {
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setMessage(writer.getErrorMessage());
|
||||
builder.setNeutralButton(R.string.ok, new OnClickListener() {
|
||||
builder.setPositiveButton(R.string.generic_ok, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int arg1) {
|
||||
dialog.dismiss();
|
||||
@@ -184,7 +185,7 @@ public class SaveActivity extends Activity {
|
||||
});
|
||||
builder.setIcon(success ? android.R.drawable.ic_dialog_info :
|
||||
android.R.drawable.ic_dialog_alert);
|
||||
builder.setTitle(success ? R.string.success : R.string.error);
|
||||
builder.setTitle(success ? R.string.generic_success_title : R.string.generic_error_title);
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
@@ -227,7 +228,7 @@ public class SaveActivity extends Activity {
|
||||
Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
|
||||
|
||||
Intent intent = new Intent(ctx, SaveActivity.class);
|
||||
intent.setAction(ctx.getString(R.string.save_intent_action));
|
||||
intent.setAction(ctx.getString(R.string.track_action_save));
|
||||
intent.setDataAndType(uri, TracksColumns.CONTENT_ITEMTYPE);
|
||||
intent.putExtra(EXTRA_FILE_FORMAT, exportFormat.ordinal());
|
||||
intent.putExtra(EXTRA_SHARE_FILE, shareFile);
|
||||
|
||||
@@ -17,6 +17,8 @@ package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.util.FileUtils;
|
||||
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -51,11 +53,9 @@ public class TempFileCleaner {
|
||||
}
|
||||
|
||||
private void cleanTmpDirectory(String name) {
|
||||
String sep = System.getProperty("file.separator");
|
||||
cleanTmpDirectory(
|
||||
new File(
|
||||
Environment.getExternalStorageDirectory() + sep + name + sep
|
||||
+ "tmp"));
|
||||
FileUtils fileUtils = new FileUtils();
|
||||
String dirName = fileUtils.buildExternalDirectoryPath(name, "tmp");
|
||||
cleanTmpDirectory(new File(dirName));
|
||||
}
|
||||
|
||||
// @VisibleForTesting
|
||||
|
||||
@@ -114,7 +114,7 @@ class TrackWriterImpl implements TrackWriter {
|
||||
private void doWriteTrack() {
|
||||
// Open the input and output
|
||||
success = false;
|
||||
errorMessage = R.string.error_track_does_not_exist;
|
||||
errorMessage = R.string.export_error;
|
||||
if (track != null) {
|
||||
if (openFile()) {
|
||||
try {
|
||||
@@ -127,7 +127,7 @@ class TrackWriterImpl implements TrackWriter {
|
||||
}
|
||||
}
|
||||
success = false;
|
||||
errorMessage = R.string.error_operation_cancelled;
|
||||
errorMessage = R.string.export_canceled;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,7 +208,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.io_write_failed;
|
||||
errorMessage = R.string.sd_card_error_write_file;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -226,12 +226,12 @@ class TrackWriterImpl implements TrackWriter {
|
||||
|
||||
if (!fileUtils.isSdCardAvailable()) {
|
||||
Log.i(Constants.TAG, "Could not find SD card.");
|
||||
errorMessage = R.string.io_no_external_storage_found;
|
||||
errorMessage = R.string.sd_card_error_no_storage;
|
||||
return false;
|
||||
}
|
||||
if (!fileUtils.ensureDirectoryExists(directory)) {
|
||||
Log.i(Constants.TAG, "Could not create export directory.");
|
||||
errorMessage = R.string.io_create_dir_failed;
|
||||
errorMessage = R.string.sd_card_error_create_dir;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ class TrackWriterImpl implements TrackWriter {
|
||||
writer.close();
|
||||
success = true;
|
||||
Log.d(Constants.TAG, "Done writing track.");
|
||||
errorMessage = R.string.io_write_finished;
|
||||
errorMessage = R.string.sd_card_success_write_file;
|
||||
}
|
||||
|
||||
private void writeLocations() throws InterruptedException {
|
||||
|
||||
@@ -79,9 +79,9 @@ class WriteProgressController {
|
||||
public ProgressDialog createProgressDialog() {
|
||||
dialog = new ProgressDialog(activity);
|
||||
dialog.setIcon(android.R.drawable.ic_dialog_info);
|
||||
dialog.setTitle(activity.getString(R.string.progress_title));
|
||||
dialog.setTitle(activity.getString(R.string.generic_progress_title));
|
||||
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
dialog.setMessage(activity.getString(R.string.write_progress_message));
|
||||
dialog.setMessage(activity.getString(R.string.export_progress_message));
|
||||
dialog.setIndeterminate(true);
|
||||
dialog.setOnCancelListener(dialogCancelListener);
|
||||
return dialog;
|
||||
|
||||
@@ -23,9 +23,17 @@ import com.google.wireless.gdata.parser.ParseException;
|
||||
import com.google.wireless.gdata.serializer.GDataSerializer;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
@@ -39,15 +47,6 @@ import org.apache.http.entity.ByteArrayEntity;
|
||||
import org.apache.http.entity.InputStreamEntity;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* Implementation of a GDataClient using GoogleHttpClient to make HTTP requests.
|
||||
* Always issues GETs and POSTs, using the X-HTTP-Method-Override header when a
|
||||
@@ -58,8 +57,7 @@ public class AndroidGDataClient implements GDataClient {
|
||||
|
||||
private static final String TAG = "GDataClient";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
|
||||
|
||||
|
||||
private static final String X_HTTP_METHOD_OVERRIDE = "X-HTTP-Method-Override";
|
||||
|
||||
private static final int MAX_REDIRECTS = 10;
|
||||
@@ -196,7 +194,7 @@ public class AndroidGDataClient implements GDataClient {
|
||||
if (!TextUtils.isEmpty(authToken)) {
|
||||
request.addHeader("Authorization", "GoogleLogin auth=" + authToken);
|
||||
}
|
||||
if (LOCAL_LOGV) {
|
||||
if (DEBUG) {
|
||||
for (Header h : request.getAllHeaders()) {
|
||||
Log.v(TAG, h.getName() + ": " + h.getValue());
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* handling. After a query is run, the wrapper can be queried about the error
|
||||
* that occurred.
|
||||
*
|
||||
* @param C the GData service client
|
||||
* @param <C> the GData service client
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class GDataWrapper<C> {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.google.android.apps.mytracks.io.mymaps;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.io.AuthManager;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.maps.GeoPoint;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import com.google.wireless.gdata.client.HttpException;
|
||||
@@ -119,7 +120,7 @@ public class MapsFacade {
|
||||
MyMapsMapMetadata metaData = new MyMapsMapMetadata();
|
||||
metaData.setTitle(title);
|
||||
metaData.setDescription(description + " - "
|
||||
+ category + " - " + context.getString(R.string.new_map_description));
|
||||
+ category + " - " + StringUtils.getCreatedByMyTracks(context, false));
|
||||
metaData.setSearchable(isPublic);
|
||||
Entry entry = MyMapsGDataConverter.getMapEntryForMetadata(metaData);
|
||||
Log.d(MyMapsConstants.TAG, "Title: " + entry.getTitle());
|
||||
@@ -138,7 +139,7 @@ public class MapsFacade {
|
||||
* @param mapId ID of the map to upload to
|
||||
* @param trackName name of the track being started/ended
|
||||
* @param trackDescription description of the track being started/ended
|
||||
* @param location the location of the marker
|
||||
* @param loc the location of the marker
|
||||
* @param isStart true to add a start marker, false to add an end marker
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
@@ -185,7 +186,9 @@ public class MapsFacade {
|
||||
/**
|
||||
* Builds a placemark MyMapsFeature from a track.
|
||||
*
|
||||
* @param track the track
|
||||
* @param trackName the track
|
||||
* @param trackDescription the track description
|
||||
* @param geoPoint the geo point
|
||||
* @param isStart true if it's the start of the track, or false for end
|
||||
* @return a MyMapsFeature
|
||||
*/
|
||||
@@ -199,16 +202,19 @@ public class MapsFacade {
|
||||
iconUrl = END_ICON_URL;
|
||||
}
|
||||
String title = trackName + " "
|
||||
+ (isStart ? context.getString(R.string.start)
|
||||
: context.getString(R.string.end));
|
||||
+ (isStart ? context.getString(R.string.marker_label_start)
|
||||
: context.getString(R.string.marker_label_end));
|
||||
String description = isStart ? "" : trackDescription;
|
||||
return buildMyMapsPlacemarkFeature(title, description, iconUrl, geoPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a MyMapsFeature from a track.
|
||||
*
|
||||
* @param wpt the waypoint
|
||||
* Builds a MyMapsFeature from a waypoint.
|
||||
*
|
||||
* @param title the title
|
||||
* @param description the description
|
||||
* @param iconUrl the icon url
|
||||
* @param geoPoint the waypoint
|
||||
* @return a MyMapsFeature
|
||||
*/
|
||||
private static MyMapsFeature buildMyMapsPlacemarkFeature(
|
||||
@@ -336,7 +342,8 @@ public class MapsFacade {
|
||||
/**
|
||||
* Builds a MyMapsFeature from a track.
|
||||
*
|
||||
* @param track the track
|
||||
* @param trackName the track name
|
||||
* @param locations locations on the track
|
||||
* @return a MyMapsFeature
|
||||
*/
|
||||
private static MyMapsFeature buildMyMapsLineFeature(String trackName,
|
||||
|
||||
+3
-3
@@ -12,12 +12,12 @@ import com.google.wireless.gdata.serializer.xml.XmlEntryGDataSerializer;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
/**
|
||||
* Factory of Xml parsers for gdata maps data.
|
||||
*/
|
||||
@@ -39,7 +39,7 @@ class XmlMapsGDataParserFactory implements GDataParserFactory {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public GDataParser createParser(Class cls, InputStream is)
|
||||
throws ParseException {
|
||||
|
||||
@@ -60,7 +60,11 @@ class XmlMapsGDataSerializer extends XmlEntryGDataSerializer {
|
||||
declareEntryNamespaces(serializer);
|
||||
serializer.startTag(XmlGDataParser.NAMESPACE_ATOM_URI, "entry");
|
||||
|
||||
stream = MapsClient.LOG_COMMUNICATION ? printStream : out;
|
||||
if (MapsClient.LOG_COMMUNICATION) {
|
||||
stream = printStream;
|
||||
} else {
|
||||
stream = out;
|
||||
}
|
||||
serializeEntryContents(serializer, format);
|
||||
|
||||
serializer.endTag(XmlGDataParser.NAMESPACE_ATOM_URI, "entry");
|
||||
|
||||
+4
-4
@@ -72,16 +72,16 @@ public class ResultDialogFactory {
|
||||
.setView(makeDialogContent(activity, results, success));
|
||||
|
||||
if (success) {
|
||||
builder.setTitle(R.string.success);
|
||||
builder.setTitle(R.string.generic_success_title);
|
||||
builder.setIcon(android.R.drawable.ic_dialog_info);
|
||||
} else {
|
||||
builder.setTitle(R.string.error);
|
||||
builder.setTitle(R.string.generic_error_title);
|
||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
}
|
||||
|
||||
builder.setPositiveButton(activity.getString(R.string.ok), onOkClickListener);
|
||||
builder.setPositiveButton(activity.getString(R.string.generic_ok), onOkClickListener);
|
||||
if (onShareClickListener != null) {
|
||||
builder.setNeutralButton(activity.getString(R.string.share_track),
|
||||
builder.setNegativeButton(activity.getString(R.string.send_google_result_share_url),
|
||||
onShareClickListener);
|
||||
}
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ public class SendActivity extends Activity implements ProgressIndicator {
|
||||
|
||||
tracker = GoogleAnalyticsTracker.getInstance();
|
||||
// Start the tracker in manual dispatch mode...
|
||||
tracker.start(getString(R.string.google_analytics_id),
|
||||
tracker.start(getString(R.string.my_tracks_analytics_id),
|
||||
getApplicationContext());
|
||||
tracker.setProductVersion("android-mytracks",
|
||||
SystemUtils.getMyTracksVersion(this));
|
||||
@@ -392,7 +392,7 @@ public class SendActivity extends Activity implements ProgressIndicator {
|
||||
progressDialog = new ProgressDialog(this);
|
||||
progressDialog.setCancelable(false);
|
||||
progressDialog.setIcon(android.R.drawable.ic_dialog_info);
|
||||
progressDialog.setTitle(R.string.progress_title);
|
||||
progressDialog.setTitle(R.string.generic_progress_title);
|
||||
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
progressDialog.setMax(100);
|
||||
progressDialog.setProgress(0);
|
||||
@@ -403,8 +403,7 @@ public class SendActivity extends Activity implements ProgressIndicator {
|
||||
private SendState authenticateToGoogleMaps() {
|
||||
Log.d(TAG, "SendActivity.authenticateToGoogleMaps");
|
||||
progressDialog.setProgress(0);
|
||||
progressDialog.setMessage(getString(
|
||||
R.string.progress_message_authenticating_mymaps));
|
||||
progressDialog.setMessage(getAuthenticatingProgressMessage(SendType.MYMAPS));
|
||||
authenticate(Constants.AUTHENTICATE_TO_MY_MAPS, MyMapsConstants.SERVICE_NAME);
|
||||
// AUTHENTICATE_TO_MY_MAPS callback calls sendToGoogleMaps
|
||||
return SendState.NOT_READY;
|
||||
@@ -429,9 +428,9 @@ public class SendActivity extends Activity implements ProgressIndicator {
|
||||
|
||||
SendToMyMaps.OnSendCompletedListener onCompletion = new SendToMyMaps.OnSendCompletedListener() {
|
||||
@Override
|
||||
public void onSendCompleted(String mapId, boolean success, int statusMessage) {
|
||||
public void onSendCompleted(String mapId, boolean success, String statusMessage) {
|
||||
// TODO: Use this message
|
||||
sendToMyMapsMessage = getString(statusMessage);
|
||||
sendToMyMapsMessage = statusMessage;
|
||||
sendToMyMapsSuccess = success;
|
||||
if (sendToMyMapsSuccess) {
|
||||
sendToMyMapsMapId = mapId;
|
||||
@@ -479,8 +478,7 @@ public class SendActivity extends Activity implements ProgressIndicator {
|
||||
|
||||
private SendState authenticateToFusionTables() {
|
||||
progressDialog.setProgress(0);
|
||||
progressDialog.setMessage(getString(
|
||||
R.string.progress_message_authenticating_fusiontables));
|
||||
progressDialog.setMessage(getAuthenticatingProgressMessage(SendType.FUSION_TABLES));
|
||||
authenticate(Constants.AUTHENTICATE_TO_FUSION_TABLES, SendToFusionTables.SERVICE_ID);
|
||||
// AUTHENTICATE_TO_FUSION_TABLES callback calls sendToFusionTables
|
||||
return SendState.NOT_READY;
|
||||
@@ -491,10 +489,9 @@ public class SendActivity extends Activity implements ProgressIndicator {
|
||||
|
||||
OnSendCompletedListener onCompletion = new OnSendCompletedListener() {
|
||||
@Override
|
||||
public void onSendCompleted(String tableId, boolean success,
|
||||
int statusMessage) {
|
||||
public void onSendCompleted(String tableId, boolean success, String statusMessage) {
|
||||
// TODO: Use this message
|
||||
sendToFusionTablesMessage = getString(statusMessage);
|
||||
sendToFusionTablesMessage = statusMessage;
|
||||
sendToFusionTablesSuccess = success;
|
||||
if (sendToFusionTablesSuccess) {
|
||||
sendToFusionTablesTableId = tableId;
|
||||
@@ -536,8 +533,7 @@ public class SendActivity extends Activity implements ProgressIndicator {
|
||||
|
||||
private SendState authenticateToGoogleDocs() {
|
||||
setProgressValue(0);
|
||||
setProgressMessage(
|
||||
R.string.progress_message_authenticating_docs);
|
||||
setProgressMessage(getAuthenticatingProgressMessage(SendType.DOCS));
|
||||
authenticate(Constants.AUTHENTICATE_TO_DOCLIST, SendToDocs.GDATA_SERVICE_NAME_DOCLIST);
|
||||
// AUTHENTICATE_TO_DOCLIST callback calls authenticateToGoogleTrix
|
||||
return SendState.NOT_READY;
|
||||
@@ -545,8 +541,7 @@ public class SendActivity extends Activity implements ProgressIndicator {
|
||||
|
||||
private SendState authenticateToGoogleTrix() {
|
||||
setProgressValue(30);
|
||||
setProgressMessage(
|
||||
R.string.progress_message_authenticating_docs);
|
||||
setProgressMessage(getAuthenticatingProgressMessage(SendType.DOCS));
|
||||
authenticate(Constants.AUTHENTICATE_TO_TRIX, SendToDocs.GDATA_SERVICE_NAME_TRIX);
|
||||
// AUTHENTICATE_TO_TRIX callback calls sendToGoogleDocs
|
||||
return SendState.NOT_READY;
|
||||
@@ -557,7 +552,9 @@ public class SendActivity extends Activity implements ProgressIndicator {
|
||||
tracker.trackPageView("/send/docs");
|
||||
|
||||
setProgressValue(50);
|
||||
setProgressMessage(R.string.progress_message_sending_docs);
|
||||
String format = getString(R.string.send_google_progress_sending);
|
||||
String serviceName = getString(SendType.DOCS.getServiceName());
|
||||
setProgressMessage(String.format(format, serviceName));
|
||||
final SendToDocs sender = new SendToDocs(this,
|
||||
authMap.get(SendToDocs.GDATA_SERVICE_NAME_TRIX),
|
||||
authMap.get(SendToDocs.GDATA_SERVICE_NAME_DOCLIST),
|
||||
@@ -692,15 +689,15 @@ public class SendActivity extends Activity implements ProgressIndicator {
|
||||
boolean shareUrlOnly = sharedPreferences.getBoolean(
|
||||
getString(R.string.share_url_only_key), false);
|
||||
String msg = shareUrlOnly ? url : String.format(
|
||||
getResources().getText(R.string.share_map_body_format).toString(), url);
|
||||
getResources().getText(R.string.share_track_url_body_format).toString(), url);
|
||||
|
||||
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
||||
shareIntent.setType("text/plain");
|
||||
shareIntent.putExtra(Intent.EXTRA_SUBJECT,
|
||||
getResources().getText(R.string.share_map_subject).toString());
|
||||
getResources().getText(R.string.share_track_subject).toString());
|
||||
shareIntent.putExtra(Intent.EXTRA_TEXT, msg);
|
||||
startActivity(Intent.createChooser(shareIntent,
|
||||
getResources().getText(R.string.share_map).toString()));
|
||||
getResources().getText(R.string.share_track_picker_title).toString()));
|
||||
}
|
||||
|
||||
protected String getFusionTablesUrl(long trackId) {
|
||||
@@ -883,12 +880,24 @@ public class SendActivity extends Activity implements ProgressIndicator {
|
||||
sendToFusionTablesTableId = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a progress message indicating My Tracks is authenticating to a
|
||||
* service.
|
||||
*
|
||||
* @param type the type of service
|
||||
*/
|
||||
private String getAuthenticatingProgressMessage(SendType type) {
|
||||
String format = getString(R.string.send_google_progress_authenticating);
|
||||
String serviceName = getString(type.getServiceName());
|
||||
return String.format(format, serviceName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgressMessage(final int resId) {
|
||||
public void setProgressMessage(final String message) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if (progressDialog != null) {
|
||||
progressDialog.setMessage(getString(resId));
|
||||
progressDialog.setMessage(message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -45,7 +45,6 @@ public class SendDialog extends Dialog {
|
||||
private CheckBox sendToMyMapsCheckBox;
|
||||
private CheckBox sendToFusionTablesCheckBox;
|
||||
private CheckBox sendToDocsCheckBox;
|
||||
private RadioButton sendStatsAndPointsRadioButton;
|
||||
private OnClickListener clickListener;
|
||||
|
||||
public SendDialog(Context context) {
|
||||
@@ -69,9 +68,6 @@ public class SendDialog extends Dialog {
|
||||
(RadioButton) findViewById(R.id.sendtogoogle_create_new_map);
|
||||
pickMapRadioButton =
|
||||
(RadioButton) findViewById(R.id.sendtogoogle_pick_existing_map);
|
||||
RadioButton sendStatsRadioButton = (RadioButton) findViewById(R.id.sendtogoogle_send_stats);
|
||||
sendStatsAndPointsRadioButton = (RadioButton) findViewById(
|
||||
R.id.sendtogoogle_send_stats_and_points);
|
||||
|
||||
Button cancel = (Button) findViewById(R.id.sendtogoogle_cancel);
|
||||
cancel.setOnClickListener(new View.OnClickListener() {
|
||||
@@ -124,14 +120,6 @@ public class SendDialog extends Dialog {
|
||||
createNewMapRadioButton.setChecked(
|
||||
!prefs.getBoolean(
|
||||
getContext().getString(R.string.pick_existing_map_key), false));
|
||||
sendStatsAndPointsRadioButton.setChecked(
|
||||
prefs.getBoolean(
|
||||
getContext().getString(R.string.send_stats_and_points_key),
|
||||
false));
|
||||
sendStatsRadioButton.setChecked(
|
||||
!prefs.getBoolean(
|
||||
getContext().getString(R.string.send_stats_and_points_key),
|
||||
false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,9 +142,6 @@ public class SendDialog extends Dialog {
|
||||
editor.putBoolean(
|
||||
getContext().getString(R.string.pick_existing_map_key),
|
||||
pickMapRadioButton.isChecked());
|
||||
editor.putBoolean(
|
||||
getContext().getString(R.string.send_stats_and_points_key),
|
||||
sendStatsAndPointsRadioButton.isChecked());
|
||||
editor.commit();
|
||||
}
|
||||
}
|
||||
@@ -182,8 +167,4 @@ public class SendDialog extends Dialog {
|
||||
public boolean getCreateNewMap() {
|
||||
return createNewMapRadioButton.isChecked();
|
||||
}
|
||||
|
||||
public boolean getSendStatsAndPoints() {
|
||||
return sendStatsAndPointsRadioButton.isChecked();
|
||||
}
|
||||
}
|
||||
@@ -23,12 +23,12 @@ import com.google.android.maps.mytracks.R;
|
||||
* @author Matthew Simmons
|
||||
*/
|
||||
public enum SendType {
|
||||
MYMAPS(R.string.sendtogoogle_google_mymaps,
|
||||
R.string.sendtogoogle_google_mymaps_url),
|
||||
FUSION_TABLES(R.string.sendtogoogle_google_fusiontables,
|
||||
R.string.sendtogoogle_google_fusiontables_url),
|
||||
DOCS(R.string.sendtogoogle_google_docs,
|
||||
R.string.sendtogoogle_google_docs_url);
|
||||
MYMAPS(R.string.send_google_my_maps,
|
||||
R.string.send_google_my_maps_url),
|
||||
FUSION_TABLES(R.string.send_google_fusion_tables,
|
||||
R.string.send_google_fusion_tables_url),
|
||||
DOCS(R.string.send_google_docs,
|
||||
R.string.send_google_docs_url);
|
||||
|
||||
private int serviceName;
|
||||
private int serviceUrl;
|
||||
|
||||
@@ -57,7 +57,7 @@ public class SingleColorTrackPathPainter implements TrackPathPainter {
|
||||
final Point pt = new Point();
|
||||
// Loop over track points.
|
||||
int numPoints = points.size();
|
||||
path = new Path();
|
||||
path = newPath();
|
||||
path.incReserve(numPoints);
|
||||
|
||||
for (int i = startLocationIdx; i < numPoints ; ++i) {
|
||||
@@ -104,4 +104,9 @@ public class SingleColorTrackPathPainter implements TrackPathPainter {
|
||||
public Path getLastPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
// Visible for testing
|
||||
public Path newPath() {
|
||||
return new Path();
|
||||
}
|
||||
}
|
||||
@@ -49,12 +49,13 @@ public class TrackPathPainterFactory {
|
||||
String colorMode = prefs.getString(context.getString(R.string.track_color_mode_key), null);
|
||||
Log.i(TAG, "Creating track path painter of type: " + colorMode);
|
||||
|
||||
if (colorMode == null || colorMode.equals(context.getString(R.string.track_color_mode_none))) {
|
||||
if (colorMode == null
|
||||
|| colorMode.equals(context.getString(R.string.display_track_color_value_none))) {
|
||||
return new SingleColorTrackPathPainter(context);
|
||||
} else if (colorMode.equals(context.getString(R.string.track_color_mode_fixed))) {
|
||||
} else if (colorMode.equals(context.getString(R.string.display_track_color_value_fixed))) {
|
||||
return new DynamicSpeedTrackPathPainter(context,
|
||||
new FixedSpeedTrackPathDescriptor(context));
|
||||
} else if (colorMode.equals(context.getString(R.string.track_color_mode_dynamic))) {
|
||||
} else if (colorMode.equals(context.getString(R.string.display_track_color_value_dynamic))) {
|
||||
return new DynamicSpeedTrackPathPainter(context,
|
||||
new DynamicSpeedTrackPathDescriptor(context));
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2011 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.services;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.widgets.TrackWidgetProvider;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* A service to control starting and stopping of a recording. This service,
|
||||
* through the AndroidManifest.xml, is configured to only allow components of
|
||||
* the same application to invoke it. Thus this service can be used my MyTracks
|
||||
* app widget, {@link TrackWidgetProvider}, but not by other applications. This
|
||||
* application delegates starting and stopping a recording to
|
||||
* {@link TrackRecordingService} using RPC calls.
|
||||
*
|
||||
* @author jshih@google.com (Jimmy Shih)
|
||||
*/
|
||||
public class ControlRecordingService extends IntentService implements ServiceConnection {
|
||||
|
||||
private ITrackRecordingService trackRecordingService;
|
||||
private boolean connected = false;
|
||||
|
||||
public ControlRecordingService() {
|
||||
super(ControlRecordingService.class.getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
Intent newIntent = new Intent(this, TrackRecordingService.class);
|
||||
startService(newIntent);
|
||||
bindService(newIntent, this, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
trackRecordingService = ITrackRecordingService.Stub.asInterface(service);
|
||||
notifyConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
connected = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all threads that connection to {@link TrackRecordingService} is
|
||||
* available.
|
||||
*/
|
||||
private synchronized void notifyConnected() {
|
||||
connected = true;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until the connection to {@link TrackRecordingService} is available.
|
||||
*/
|
||||
private synchronized void waitConnected() {
|
||||
while (!connected) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
|
||||
// can safely ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
waitConnected();
|
||||
String action = intent.getAction();
|
||||
if (action != null) {
|
||||
try {
|
||||
if (action.equals(getString(R.string.track_action_start))) {
|
||||
trackRecordingService.startNewTrack();
|
||||
} else if (action.equals(getString(R.string.track_action_end))) {
|
||||
trackRecordingService.endCurrentTrack();
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "ControlRecordingService onHandleIntent RemoteException", e);
|
||||
}
|
||||
}
|
||||
unbindService(this);
|
||||
connected = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (connected) {
|
||||
unbindService(this);
|
||||
connected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ class DefaultTrackNameFactory {
|
||||
SimpleDateFormat formatter = new SimpleDateFormat(TIMESTAMP_DATE_FORMAT);
|
||||
return formatter.format(new Date(startTime));
|
||||
} else {
|
||||
return String.format(context.getString(R.string.new_track), trackId);
|
||||
return String.format(context.getString(R.string.track_name_format), trackId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+105
-65
@@ -37,7 +37,7 @@ import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
import com.google.android.apps.mytracks.util.ApiPlatformAdapter;
|
||||
import com.google.android.apps.mytracks.util.ApiLevelAdapter;
|
||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
@@ -56,11 +56,13 @@ import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Timer;
|
||||
@@ -229,6 +231,13 @@ public class TrackRecordingService extends Service {
|
||||
* Application lifetime events:
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note that this service, through the AndroidManifest.xml, is configured to
|
||||
* allow both MyTracks and third party apps to invoke it. For the onCreate
|
||||
* callback, we cannot tell whether the caller is MyTracks or a third party
|
||||
* app, thus it cannot start/stop a recording or write/update MyTracks
|
||||
* database. However, it can resume a recording.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
@@ -268,49 +277,41 @@ public class TrackRecordingService extends Service {
|
||||
showNotification();
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that this service, through the AndroidManifest.xml, is configured to
|
||||
* allow both MyTracks and third party apps to invoke it. For the onStart
|
||||
* callback, we cannot tell whether the caller is MyTracks or a third party
|
||||
* app, thus it cannot start/stop a recording or write/update MyTracks
|
||||
* database. However, it can resume a recording.
|
||||
*/
|
||||
@Override
|
||||
public void onStart(Intent intent, int startId) {
|
||||
handleStartCommand(intent, startId);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that this service, through the AndroidManifest.xml, is configured to
|
||||
* allow both MyTracks and third party apps to invoke it. For the
|
||||
* onStartCommand callback, we cannot tell whether the caller is MyTracks or a
|
||||
* third party app, thus it cannot start/stop a recording or write/update
|
||||
* MyTracks database. However, it can resume a recording.
|
||||
*/
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
handleStartCommand(intent, startId);
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
|
||||
private void handleStartCommand(Intent intent, int startId) {
|
||||
Log.d(TAG,
|
||||
"TrackRecordingService.handleStartCommand: " + startId);
|
||||
Log.d(TAG, "TrackRecordingService.handleStartCommand: " + startId);
|
||||
|
||||
if (intent == null)
|
||||
if (intent == null) {
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// Check if called on phone reboot with resume intent.
|
||||
if (intent.getBooleanExtra(RESUME_TRACK_EXTRA_NAME, false)) {
|
||||
resumeTrack(startId);
|
||||
} else {
|
||||
// Process actions for controlling the service.
|
||||
processStartStopIntent(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private void processStartStopIntent(Intent intent) {
|
||||
String action = intent.getAction();
|
||||
|
||||
if (isNewTrackAction(action)) {
|
||||
if (!isTrackInProgress()) {
|
||||
boolean selectNewTrack = intent.getBooleanExtra(getString(R.string.select_new_track_extra), false);
|
||||
|
||||
startNewTrack();
|
||||
if (selectNewTrack) {
|
||||
prefManager.setSelectedTrack(recordingTrackId);
|
||||
}
|
||||
}
|
||||
} else if (isEndTrackAction(action)) {
|
||||
if (isTrackInProgress()) {
|
||||
endCurrentTrack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,14 +319,6 @@ public class TrackRecordingService extends Service {
|
||||
return recordingTrackId != -1 || isRecording;
|
||||
}
|
||||
|
||||
private boolean isNewTrackAction(String action) {
|
||||
return getString(R.string.start_new_track_action).equals(action);
|
||||
}
|
||||
|
||||
private boolean isEndTrackAction(String action) {
|
||||
return getString(R.string.end_current_track_action).equals(action);
|
||||
}
|
||||
|
||||
private void resumeTrack(int startId) {
|
||||
Log.d(TAG, "TrackRecordingService: requested resume");
|
||||
|
||||
@@ -492,8 +485,8 @@ public class TrackRecordingService extends Service {
|
||||
* Shows the notification message and icon in the notification bar.
|
||||
*/
|
||||
private void showNotification() {
|
||||
final ApiPlatformAdapter apiPlatformAdapter =
|
||||
ApiFeatures.getInstance().getApiPlatformAdapter();
|
||||
final ApiLevelAdapter apiLevelAdapter =
|
||||
ApiFeatures.getInstance().getApiAdapter();
|
||||
if (isRecording) {
|
||||
Notification notification = new Notification(
|
||||
R.drawable.arrow_320, null /* tickerText */,
|
||||
@@ -501,13 +494,13 @@ public class TrackRecordingService extends Service {
|
||||
PendingIntent contentIntent = PendingIntent.getActivity(
|
||||
this, 0 /* requestCode */, new Intent(this, MyTracks.class),
|
||||
0 /* flags */);
|
||||
notification.setLatestEventInfo(this, getString(R.string.app_name),
|
||||
getString(R.string.recording_your_track), contentIntent);
|
||||
notification.setLatestEventInfo(this, getString(R.string.my_tracks_app_name),
|
||||
getString(R.string.track_record_notification), contentIntent);
|
||||
notification.flags += Notification.FLAG_NO_CLEAR;
|
||||
apiPlatformAdapter.startForeground(this, notificationManager, 1,
|
||||
apiLevelAdapter.startForeground(this, notificationManager, 1,
|
||||
notification);
|
||||
} else {
|
||||
apiPlatformAdapter.stopForeground(this, notificationManager, 1);
|
||||
apiLevelAdapter.stopForeground(this, notificationManager, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,15 +559,20 @@ public class TrackRecordingService extends Service {
|
||||
Log.d(TAG,
|
||||
"Location listener now unregistered w/ TrackRecordingService.");
|
||||
}
|
||||
|
||||
private String getDefaultActivityType(Context context) {
|
||||
SharedPreferences prefs = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||
return prefs.getString(context.getString(R.string.default_activity_key), "");
|
||||
}
|
||||
|
||||
/*
|
||||
* Recording lifecycle.
|
||||
*/
|
||||
|
||||
public long startNewTrack() {
|
||||
private long startNewTrack() {
|
||||
Log.d(TAG, "TrackRecordingService.startNewTrack");
|
||||
if (isTrackInProgress()) {
|
||||
throw new IllegalStateException("A track is already in progress!");
|
||||
return -1L;
|
||||
}
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
@@ -589,6 +587,7 @@ public class TrackRecordingService extends Service {
|
||||
track.setId(recordingTrackId);
|
||||
track.setName(new DefaultTrackNameFactory(this).newTrackName(
|
||||
recordingTrackId, startTime));
|
||||
track.setCategory(getDefaultActivityType(this));
|
||||
isRecording = true;
|
||||
isMoving = true;
|
||||
|
||||
@@ -964,12 +963,12 @@ public class TrackRecordingService extends Service {
|
||||
private void buildMarker(Waypoint wpt, WaypointCreationRequest request) {
|
||||
wpt.setType(Waypoint.TYPE_WAYPOINT);
|
||||
if (request.getIconUrl() == null) {
|
||||
wpt.setIcon(getString(R.string.waypoint_icon_url));
|
||||
wpt.setIcon(getString(R.string.marker_waypoint_icon_url));
|
||||
} else {
|
||||
wpt.setIcon(request.getIconUrl());
|
||||
}
|
||||
if (request.getName() == null) {
|
||||
wpt.setName(getString(R.string.waypoint));
|
||||
wpt.setName(getString(R.string.marker_type_waypoint));
|
||||
} else {
|
||||
wpt.setName(request.getName());
|
||||
}
|
||||
@@ -982,8 +981,7 @@ public class TrackRecordingService extends Service {
|
||||
* Build a statistics marker.
|
||||
* A statistics marker holds the stats for the* last segment up to this marker.
|
||||
*
|
||||
* @param Waypoint The waypoint which will be populated with stats data.
|
||||
* @return the unique id of the inserted marker
|
||||
* @param waypoint The waypoint which will be populated with stats data.
|
||||
*/
|
||||
private void buildStatisticsMarker(Waypoint waypoint) {
|
||||
StringUtils utils = new StringUtils(TrackRecordingService.this);
|
||||
@@ -998,10 +996,10 @@ public class TrackRecordingService extends Service {
|
||||
|
||||
// Set the rest of the waypoint data
|
||||
waypoint.setType(Waypoint.TYPE_STATISTICS);
|
||||
waypoint.setName(getString(R.string.statistics));
|
||||
waypoint.setName(getString(R.string.marker_type_statistics));
|
||||
waypoint.setStatistics(waypointStatsBuilder.getStatistics());
|
||||
waypoint.setDescription(utils.generateWaypointDescription(waypoint));
|
||||
waypoint.setIcon(getString(R.string.stats_icon_url));
|
||||
waypoint.setIcon(getString(R.string.marker_statistics_icon_url));
|
||||
|
||||
waypoint.setStartId(providerUtils.getLastLocationId(recordingTrackId));
|
||||
|
||||
@@ -1012,7 +1010,7 @@ public class TrackRecordingService extends Service {
|
||||
private void endCurrentTrack() {
|
||||
Log.d(TAG, "TrackRecordingService.endCurrentTrack");
|
||||
if (!isTrackInProgress()) {
|
||||
throw new IllegalStateException("No recording track in progress!");
|
||||
return;
|
||||
}
|
||||
|
||||
announcementExecutor.shutdown();
|
||||
@@ -1053,12 +1051,15 @@ public class TrackRecordingService extends Service {
|
||||
}
|
||||
|
||||
private void sendTrackBroadcast(int actionResId, long trackId) {
|
||||
Intent broadcastIntent =
|
||||
new Intent()
|
||||
.setAction(getString(actionResId))
|
||||
.putExtra(getString(R.string.track_id_broadcast_extra), trackId);
|
||||
sendBroadcast(broadcastIntent,
|
||||
getString(R.string.broadcast_notifications_permission));
|
||||
Intent broadcastIntent = new Intent()
|
||||
.setAction(getString(actionResId))
|
||||
.putExtra(getString(R.string.track_id_broadcast_extra), trackId);
|
||||
sendBroadcast(broadcastIntent, getString(R.string.permission_notification_value));
|
||||
|
||||
SharedPreferences sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||
if (sharedPreferences.getBoolean(getString(R.string.allow_access_key), false)) {
|
||||
sendBroadcast(broadcastIntent, getString(R.string.broadcast_notifications_permission));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1190,29 +1191,58 @@ public class TrackRecordingService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the service is available. If not, throws an
|
||||
* {@link IllegalStateException}.
|
||||
*/
|
||||
private void checkService() {
|
||||
if (service == null) {
|
||||
throw new IllegalStateException("The service has been already detached!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the RPC caller is from the same application or if the
|
||||
* "Allow access" setting indicates that another app can invoke this service's
|
||||
* RPCs.
|
||||
*/
|
||||
private boolean canAccess() {
|
||||
|
||||
// As a precondition for access, must check if the service is available.
|
||||
checkService();
|
||||
|
||||
if (Process.myPid() == Binder.getCallingPid()) {
|
||||
return true;
|
||||
} else {
|
||||
SharedPreferences sharedPreferences = service.getSharedPreferences(
|
||||
Constants.SETTINGS_NAME, 0);
|
||||
return sharedPreferences.getBoolean(service.getString(R.string.allow_access_key), false);
|
||||
}
|
||||
}
|
||||
|
||||
// Service method delegates.
|
||||
|
||||
@Override
|
||||
public boolean isRecording() {
|
||||
checkService();
|
||||
if (!canAccess()) {
|
||||
return false;
|
||||
}
|
||||
return service.isRecording();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRecordingTrackId() {
|
||||
checkService();
|
||||
if (!canAccess()) {
|
||||
return -1L;
|
||||
}
|
||||
return service.recordingTrackId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long startNewTrack() {
|
||||
checkService();
|
||||
if (!canAccess()) {
|
||||
return -1L;
|
||||
}
|
||||
return service.startNewTrack();
|
||||
}
|
||||
|
||||
@@ -1223,25 +1253,33 @@ public class TrackRecordingService extends Service {
|
||||
* @return the unique ID of the inserted marker
|
||||
*/
|
||||
public long insertWaypoint(WaypointCreationRequest request) {
|
||||
checkService();
|
||||
if (!canAccess()) {
|
||||
return -1L;
|
||||
}
|
||||
return service.insertWaypoint(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endCurrentTrack() {
|
||||
checkService();
|
||||
if (!canAccess()) {
|
||||
return;
|
||||
}
|
||||
service.endCurrentTrack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordLocation(Location loc) {
|
||||
checkService();
|
||||
if (!canAccess()) {
|
||||
return;
|
||||
}
|
||||
service.locationListener.onLocationChanged(loc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getSensorData() {
|
||||
checkService();
|
||||
if (!canAccess()) {
|
||||
return null;
|
||||
}
|
||||
if (service.sensorManager == null) {
|
||||
Log.d(TAG, "No sensor manager for data.");
|
||||
return null;
|
||||
@@ -1255,7 +1293,9 @@ public class TrackRecordingService extends Service {
|
||||
|
||||
@Override
|
||||
public int getSensorState() {
|
||||
checkService();
|
||||
if (!canAccess()) {
|
||||
return Sensor.SensorState.NONE.getNumber();
|
||||
}
|
||||
if (service.sensorManager == null) {
|
||||
Log.d(TAG, "No sensor manager for data.");
|
||||
return Sensor.SensorState.NONE.getNumber();
|
||||
|
||||
+25
-17
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
@@ -68,8 +69,8 @@ public class BluetoothConnectionManager {
|
||||
/**
|
||||
* Constructor. Prepares a new BluetoothSensor session.
|
||||
*
|
||||
* @param context The UI Activity Context
|
||||
* @param handler A Handler to send messages back to the UI Activity
|
||||
* @param parser A message parser
|
||||
*/
|
||||
public BluetoothConnectionManager(Handler handler, MessageParser parser) {
|
||||
this.adapter = BluetoothAdapter.getDefaultAdapter();
|
||||
@@ -261,22 +262,29 @@ public class BluetoothConnectionManager {
|
||||
}
|
||||
|
||||
private BluetoothSocket getSocket() throws IOException {
|
||||
try {
|
||||
Class<? extends BluetoothDevice> c = device.getClass();
|
||||
Method insecure = c.getMethod("createInsecureRfcommSocket",
|
||||
Integer.class);
|
||||
insecure.setAccessible(true);
|
||||
return (BluetoothSocket) insecure.invoke(device, 1);
|
||||
} catch (SecurityException e) {
|
||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||
if (ApiFeatures.getInstance().hasBluetoothDeviceCreateInsecureRfcommSocketToServiceRecord()) {
|
||||
try {
|
||||
return device.createInsecureRfcommSocketToServiceRecord(SPP_UUID);
|
||||
} catch (IOException e) {
|
||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
Class<? extends BluetoothDevice> c = device.getClass();
|
||||
Method insecure = c.getMethod("createInsecureRfcommSocket", Integer.class);
|
||||
insecure.setAccessible(true);
|
||||
return (BluetoothSocket) insecure.invoke(device, 1);
|
||||
} catch (SecurityException e) {
|
||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||
}
|
||||
}
|
||||
return device.createRfcommSocketToServiceRecord(SPP_UUID);
|
||||
}
|
||||
|
||||
+52
-5
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
@@ -24,10 +26,13 @@ import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Manage the connection to a bluetooth sensor.
|
||||
*
|
||||
@@ -36,8 +41,8 @@ import android.widget.Toast;
|
||||
public class BluetoothSensorManager extends SensorManager {
|
||||
|
||||
// Local Bluetooth adapter
|
||||
private BluetoothAdapter bluetoothAdapter = null;
|
||||
|
||||
private static final BluetoothAdapter bluetoothAdapter = getDefaultBluetoothAdapter();
|
||||
|
||||
// Member object for the sensor threads and connections.
|
||||
private BluetoothConnectionManager connectionManager = null;
|
||||
|
||||
@@ -54,8 +59,6 @@ public class BluetoothSensorManager extends SensorManager {
|
||||
Context context, MessageParser parser) {
|
||||
this.context = context;
|
||||
this.parser = parser;
|
||||
// Get local Bluetooth adapter
|
||||
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
// If BT is not available or not enabled quit.
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
@@ -71,6 +74,50 @@ public class BluetoothSensorManager extends SensorManager {
|
||||
connectionManager = new BluetoothConnectionManager(messageHandler, parser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Code for assigning the local bluetooth adapter
|
||||
*
|
||||
* @return The default bluetooth adapter, if one is available, NULL if it isn't.
|
||||
*/
|
||||
private static BluetoothAdapter getDefaultBluetoothAdapter() {
|
||||
// Check if the calling thread is the main application thread,
|
||||
// if it is, do it directly.
|
||||
if (Thread.currentThread().equals(Looper.getMainLooper().getThread())) {
|
||||
return BluetoothAdapter.getDefaultAdapter();
|
||||
}
|
||||
|
||||
// If the calling thread, isn't the main application thread,
|
||||
// then get the main application thread to return the default adapter.
|
||||
final ArrayList<BluetoothAdapter> adapters = new ArrayList<BluetoothAdapter>(1);
|
||||
final Object mutex = new Object();
|
||||
|
||||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adapters.add(BluetoothAdapter.getDefaultAdapter());
|
||||
synchronized (mutex) {
|
||||
mutex.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
while (adapters.isEmpty()) {
|
||||
synchronized (mutex) {
|
||||
try {
|
||||
mutex.wait(1000L);
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Interrupted while waiting for default bluetooth adapter", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (adapters.get(0) == null) {
|
||||
Log.w(TAG, "No bluetooth adapter found!");
|
||||
}
|
||||
return adapters.get(0);
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return bluetoothAdapter != null && bluetoothAdapter.isEnabled();
|
||||
}
|
||||
@@ -125,7 +172,7 @@ public class BluetoothSensorManager extends SensorManager {
|
||||
}
|
||||
|
||||
// The Handler that gets information back from the BluetoothSensorService
|
||||
private final Handler messageHandler = new Handler() {
|
||||
private final Handler messageHandler = new Handler(Looper.getMainLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
|
||||
+4
-4
@@ -48,8 +48,8 @@ public class PolarMessageParser implements MessageParser {
|
||||
* offset 2 = check byte, 255 - packet length.
|
||||
* offset 3 = sequence byte, range from 0 to 15.
|
||||
*
|
||||
* @param an array of bytes to parse
|
||||
* @param buffer offset to beginning of packet.
|
||||
* @param buffer an array of bytes to parse
|
||||
* @param i buffer offset to beginning of packet.
|
||||
* @return whether buffer has a valid packet at offset i
|
||||
*/
|
||||
private boolean packetValid (byte[] buffer, int i) {
|
||||
@@ -100,7 +100,7 @@ public class PolarMessageParser implements MessageParser {
|
||||
/**
|
||||
* Applies packet validation rules to buffer
|
||||
*
|
||||
* @param an array of bytes to parse
|
||||
* @param buffer an array of bytes to parse
|
||||
* @return whether buffer has a valid packet starting at index zero
|
||||
*/
|
||||
@Override
|
||||
@@ -124,7 +124,7 @@ public class PolarMessageParser implements MessageParser {
|
||||
/**
|
||||
* Searches buffer for the beginning of a valid packet.
|
||||
*
|
||||
* @param an array of bytes to parse
|
||||
* @param buffer an array of bytes to parse
|
||||
* @return index to beginning of good packet, or -1 if none found.
|
||||
*/
|
||||
@Override
|
||||
|
||||
+4
-4
@@ -53,13 +53,13 @@ public class SensorManagerFactory {
|
||||
|
||||
if (sensor == null) {
|
||||
return null;
|
||||
} else if (sensor.equals(context.getString(R.string.ant_sensor_type))) {
|
||||
} else if (sensor.equals(context.getString(R.string.sensor_type_value_ant))) {
|
||||
return new AntDirectSensorManager(context);
|
||||
} else if (sensor.equals(context.getString(R.string.srm_ant_bridge_sensor_type))) {
|
||||
} else if (sensor.equals(context.getString(R.string.sensor_type_value_srm_ant_bridge))) {
|
||||
return new AntSRMSensorManager(context);
|
||||
} else if (sensor.equals(context.getString(R.string.zephyr_sensor_type))) {
|
||||
} else if (sensor.equals(context.getString(R.string.sensor_type_value_zephyr))) {
|
||||
return new ZephyrSensorManager(context);
|
||||
} else if (sensor.equals(context.getString(R.string.polar_sensor_type))) {
|
||||
} else if (sensor.equals(context.getString(R.string.sensor_type_value_polar))) {
|
||||
return new PolarSensorManager(context);
|
||||
} else {
|
||||
Log.w(Constants.TAG, "Unable to find sensor type: " + sensor);
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* A collection of methods for message parsers.
|
||||
*
|
||||
@@ -58,12 +58,12 @@ public class SensorUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns CRC8 (polynomial 0x8C) from byte array buffer[start] until
|
||||
* (including) buffer[end]
|
||||
* Returns CRC8 (polynomial 0x8C) from byte array buffer[start] to
|
||||
* (excluding) buffer[start + length]
|
||||
*
|
||||
* @param buffer the byte array of data (payload)
|
||||
* @param start the position in the byte array where the payload begins
|
||||
* @param end the position in the byte array where the payload ends
|
||||
* @param length the length
|
||||
* @return CRC8 value
|
||||
*/
|
||||
public static byte getCrc8(byte[] buffer, int start, int length) {
|
||||
@@ -99,15 +99,15 @@ public class SensorUtils {
|
||||
public static String getStateAsString(Sensor.SensorState state, Context c) {
|
||||
switch (state) {
|
||||
case NONE:
|
||||
return c.getString(R.string.none);
|
||||
return c.getString(R.string.sensor_type_value_none);
|
||||
case CONNECTING:
|
||||
return c.getString(R.string.connecting);
|
||||
return c.getString(R.string.sensor_state_connecting);
|
||||
case CONNECTED:
|
||||
return c.getString(R.string.connected);
|
||||
return c.getString(R.string.sensor_state_connected);
|
||||
case DISCONNECTED:
|
||||
return c.getString(R.string.disconnected);
|
||||
return c.getString(R.string.sensor_state_disconnected);
|
||||
case SENDING:
|
||||
return c.getString(R.string.sending);
|
||||
return c.getString(R.string.sensor_state_sending);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
+4
-3
@@ -16,6 +16,7 @@
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -23,7 +24,7 @@ import java.util.Arrays;
|
||||
* An implementation of a Sensor MessageParser for Zephyr.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
* @author Dominik Ršttsches
|
||||
* @author Dominik Rttsches
|
||||
*/
|
||||
public class ZephyrMessageParser implements MessageParser {
|
||||
|
||||
@@ -61,8 +62,8 @@ public class ZephyrMessageParser implements MessageParser {
|
||||
// 0x1A00316550003162 produces erroneous values for Cadence and needs
|
||||
// a workaround based on the stride counter.
|
||||
// Firmware values range from field 3 to 10 (inclusive) of the byte buffer.
|
||||
byte[] hardwareFirmwareId = Arrays.copyOfRange(buffer, 3, 11);
|
||||
|
||||
byte[] hardwareFirmwareId = ApiFeatures.getInstance().getApiAdapter()
|
||||
.copyByteArray(buffer, 3, 11);
|
||||
Sensor.SensorData.Builder cadence = Sensor.SensorData.newBuilder();
|
||||
|
||||
if (Arrays.equals(hardwareFirmwareId, CADENCE_BUG_FW_ID)) {
|
||||
|
||||
+59
-33
@@ -22,6 +22,7 @@ import com.dsi.ant.AntInterface;
|
||||
import com.dsi.ant.AntInterfaceIntent;
|
||||
import com.dsi.ant.AntMesg;
|
||||
import com.dsi.ant.exception.AntInterfaceException;
|
||||
import com.dsi.ant.exception.AntServiceNotConnectedException;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
||||
import com.google.android.apps.mytracks.services.sensors.SensorManager;
|
||||
@@ -66,10 +67,6 @@ public abstract class AntSensorManager extends SensorManager {
|
||||
|
||||
private AntInterface antReceiver;
|
||||
|
||||
// Flag to know if the ANT App was interrupted
|
||||
// TODO: This code path is not used but probably should be.
|
||||
private boolean antInterrupted;
|
||||
|
||||
/**
|
||||
* The data from the sensors.
|
||||
*/
|
||||
@@ -125,30 +122,19 @@ public abstract class AntSensorManager extends SensorManager {
|
||||
|
||||
public AntSensorManager(Context context) {
|
||||
this.context = context;
|
||||
|
||||
// We register for ANT intents early because we want to have a record of
|
||||
// the status intents in the log as we start up.
|
||||
registerForAntIntents();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Log.i(TAG, "destroying AntSensorManager");
|
||||
try {
|
||||
context.unregisterReceiver(statusReceiver);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.w(TAG, "Failed to unregister ANT status receiver", e);
|
||||
}
|
||||
|
||||
try {
|
||||
context.unregisterReceiver(dataReceiver);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.w(TAG, "Failed to unregister ANT data receiver", e);
|
||||
}
|
||||
|
||||
try {
|
||||
antReceiver.releaseInterface();
|
||||
} catch (AntInterfaceException e) {
|
||||
Log.e(TAG, "failed to release ANT interface", e);
|
||||
}
|
||||
|
||||
antReceiver.destroy();
|
||||
|
||||
cleanAntInterface();
|
||||
unregisterForAntIntents();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -173,16 +159,18 @@ public abstract class AntSensorManager extends SensorManager {
|
||||
*/
|
||||
@Override
|
||||
protected final void setupChannel() {
|
||||
setup();
|
||||
}
|
||||
|
||||
private synchronized void setup() {
|
||||
// We handle this unpleasantly because the UI should've checked for ANT
|
||||
// support before it even instantiated this class.
|
||||
if (!AntInterface.hasAntSupport(context)) {
|
||||
throw new IllegalStateException("device does not have ANT support");
|
||||
}
|
||||
|
||||
// We register for ANT intents early because we want to have a record of
|
||||
// the status intents in the log as we start up.
|
||||
registerForAntIntents();
|
||||
|
||||
|
||||
cleanAntInterface();
|
||||
|
||||
antReceiver = AntInterface.getInstance(context, antServiceListener);
|
||||
|
||||
if (antReceiver == null) {
|
||||
@@ -193,6 +181,29 @@ public abstract class AntSensorManager extends SensorManager {
|
||||
setSensorState(Sensor.SensorState.CONNECTING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the ANT+ receiver interface, by releasing the interface
|
||||
* and destroying it.
|
||||
*/
|
||||
private void cleanAntInterface()
|
||||
{
|
||||
Log.i(TAG, "Destroying AntSensorManager");
|
||||
|
||||
if (antReceiver != null) {
|
||||
try {
|
||||
antReceiver.releaseInterface();
|
||||
} catch (AntServiceNotConnectedException e) {
|
||||
Log.i(TAG, "ANT service not connected", e);
|
||||
} catch (AntInterfaceException e) {
|
||||
Log.e(TAG, "failed to release ANT interface", e);
|
||||
}
|
||||
|
||||
antReceiver.destroy();
|
||||
|
||||
antReceiver = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked via the ServiceListener when we're connected to
|
||||
* the ANT service. If we're just starting up, this is our first opportunity
|
||||
@@ -210,10 +221,8 @@ public abstract class AntSensorManager extends SensorManager {
|
||||
if (!antReceiver.isEnabled()) {
|
||||
// Make sure not to call AntInterface.enable() again, if it has been
|
||||
// already called before
|
||||
if (antInterrupted == false) {
|
||||
Log.i(TAG, "Powering on Radio");
|
||||
antReceiver.enable();
|
||||
}
|
||||
Log.i(TAG, "Powering on Radio");
|
||||
antReceiver.enable();
|
||||
} else {
|
||||
Log.i(TAG, "Radio already enabled");
|
||||
}
|
||||
@@ -236,7 +245,7 @@ public abstract class AntSensorManager extends SensorManager {
|
||||
/**
|
||||
* Process a raw ANT message.
|
||||
* @param antMessage the ANT message, including the size and message ID bytes
|
||||
* @deprecated Use {@link #handleMessage(int, byte[])} instead.
|
||||
* @deprecated Use {@link #handleMessage(byte, byte[])} instead.
|
||||
*/
|
||||
protected void handleMessage(byte[] antMessage) {
|
||||
int len = antMessage[0];
|
||||
@@ -333,6 +342,23 @@ public abstract class AntSensorManager extends SensorManager {
|
||||
dataIntentFilter.addAction(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION);
|
||||
context.registerReceiver(dataReceiver, dataIntentFilter);
|
||||
}
|
||||
|
||||
private void unregisterForAntIntents()
|
||||
{
|
||||
Log.i(TAG, "Unregistering ANT Intents.");
|
||||
|
||||
try {
|
||||
context.unregisterReceiver(statusReceiver);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.w(TAG, "Failed to unregister ANT status receiver", e);
|
||||
}
|
||||
|
||||
try {
|
||||
context.unregisterReceiver(dataReceiver);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.w(TAG, "Failed to unregister ANT data receiver", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String messageToString(byte[] message) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
|
||||
+1
-5
@@ -37,11 +37,7 @@ public class StatusAnnouncerFactory implements PeriodicTaskFactory {
|
||||
@Override
|
||||
public PeriodicTask create(Context context) {
|
||||
if (hasTts) {
|
||||
if (ApiFeatures.getInstance().isAudioFocusSupported()) {
|
||||
return new FroyoStatusAnnouncerTask(context);
|
||||
} else {
|
||||
return new StatusAnnouncerTask(context);
|
||||
}
|
||||
return ApiFeatures.getInstance().getApiAdapter().getStatusAnnouncerTask(context);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
+48
-23
@@ -24,6 +24,7 @@ import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
@@ -53,11 +54,6 @@ public class StatusAnnouncerTask implements PeriodicTask {
|
||||
*/
|
||||
private final Context context;
|
||||
|
||||
/**
|
||||
* String utilities.
|
||||
*/
|
||||
private final StringUtils stringUtils;
|
||||
|
||||
/**
|
||||
* The interface to the text to speech engine.
|
||||
*/
|
||||
@@ -93,14 +89,8 @@ public class StatusAnnouncerTask implements PeriodicTask {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public StatusAnnouncerTask(Context context) {
|
||||
this(context, new StringUtils(context));
|
||||
}
|
||||
|
||||
public StatusAnnouncerTask(Context context, StringUtils stringUtils) {
|
||||
this.context = context;
|
||||
this.stringUtils = stringUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,29 +166,29 @@ public class StatusAnnouncerTask implements PeriodicTask {
|
||||
double d = stats.getTotalDistance() / 1000;
|
||||
double s = stats.getAverageMovingSpeed() * 3.6;
|
||||
if (d == 0) {
|
||||
return context.getString(R.string.announce_no_distance);
|
||||
return context.getString(R.string.voice_no_distance);
|
||||
}
|
||||
|
||||
int speedLabel;
|
||||
if (metricUnits) {
|
||||
if (reportSpeed) {
|
||||
speedLabel = R.string.kilometer_per_hour_long;
|
||||
speedLabel = R.string.voice_kilometer_per_hour;
|
||||
} else {
|
||||
speedLabel = R.string.per_kilometer;
|
||||
speedLabel = R.string.voice_per_kilometer;
|
||||
}
|
||||
} else {
|
||||
s *= UnitConversions.KMH_TO_MPH;
|
||||
d *= UnitConversions.KM_TO_MI;
|
||||
if (reportSpeed) {
|
||||
speedLabel = R.string.mile_per_hour_long;
|
||||
speedLabel = R.string.voice_mile_per_hour;
|
||||
} else {
|
||||
speedLabel = R.string.per_mile;
|
||||
speedLabel = R.string.voice_per_mile;
|
||||
}
|
||||
}
|
||||
|
||||
String speed = null;
|
||||
if ((s == 0) || Double.isNaN(s)) {
|
||||
speed = context.getString(R.string.unknown);
|
||||
speed = context.getString(R.string.value_unknown);
|
||||
} else {
|
||||
if (reportSpeed) {
|
||||
speed = String.format("%.1f", s);
|
||||
@@ -206,17 +196,16 @@ public class StatusAnnouncerTask implements PeriodicTask {
|
||||
double pace = 3600000.0 / s;
|
||||
Log.w(Constants.TAG,
|
||||
"Converted speed: " + s + " to pace: " + pace);
|
||||
speed = stringUtils.formatTimeLong((long) pace);
|
||||
speed = getAnnounceTime((long) pace);
|
||||
}
|
||||
}
|
||||
|
||||
return context.getString(R.string.announce_template,
|
||||
context.getString(R.string.total_distance_label),
|
||||
return context.getString(R.string.voice_template,
|
||||
d,
|
||||
context.getString(metricUnits
|
||||
? R.string.kilometers_long
|
||||
: R.string.miles_long),
|
||||
stringUtils.formatTimeLong(stats.getMovingTime()),
|
||||
? R.string.voice_kilometers
|
||||
: R.string.voice_miles),
|
||||
getAnnounceTime(stats.getMovingTime()),
|
||||
speed,
|
||||
context.getString(speedLabel));
|
||||
}
|
||||
@@ -333,4 +322,40 @@ public class StatusAnnouncerTask implements PeriodicTask {
|
||||
public static int getVolumeStream() {
|
||||
return TextToSpeech.Engine.DEFAULT_STREAM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string to announce the time.
|
||||
*
|
||||
* @param time the time
|
||||
*/
|
||||
@VisibleForTesting
|
||||
String getAnnounceTime(long time) {
|
||||
int[] parts = StringUtils.getTimeParts(time);
|
||||
String secLabel =
|
||||
context.getString(parts[0] == 1 ? R.string.voice_second : R.string.voice_seconds);
|
||||
String minLabel =
|
||||
context.getString(parts[1] == 1 ? R.string.voice_minute : R.string.voice_minutes);
|
||||
String hourLabel =
|
||||
context.getString(parts[2] == 1 ? R.string.voice_hour : R.string.voice_hours);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (parts[2] != 0) {
|
||||
sb.append(parts[2]);
|
||||
sb.append(" ");
|
||||
sb.append(hourLabel);
|
||||
sb.append(" ");
|
||||
sb.append(parts[1]);
|
||||
sb.append(" ");
|
||||
sb.append(minLabel);
|
||||
} else {
|
||||
sb.append(parts[1]);
|
||||
sb.append(" ");
|
||||
sb.append(minLabel);
|
||||
sb.append(" ");
|
||||
sb.append(parts[0]);
|
||||
sb.append(" ");
|
||||
sb.append(secLabel);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.google.android.apps.mytracks.util;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
@@ -30,17 +29,17 @@ import android.util.Log;
|
||||
public class ApiFeatures {
|
||||
|
||||
/**
|
||||
* The API level of the Android version we're being run under.
|
||||
* The API level of the Android version we are being run under.
|
||||
*/
|
||||
public static final int ANDROID_API_LEVEL = Integer.parseInt(
|
||||
private static final int ANDROID_API_LEVEL = Integer.parseInt(
|
||||
Build.VERSION.SDK);
|
||||
|
||||
private static ApiFeatures instance;
|
||||
|
||||
/**
|
||||
* The API platform adapter supported by this system.
|
||||
* The API level adapter for the Android version we are being run under.
|
||||
*/
|
||||
private ApiPlatformAdapter apiPlatformAdapter;
|
||||
private ApiLevelAdapter apiLevelAdapter;
|
||||
|
||||
/**
|
||||
* Returns the singleton instance of this class.
|
||||
@@ -67,52 +66,33 @@ public class ApiFeatures {
|
||||
// It is safe to import unsupported classes as long as we only actually
|
||||
// load the class when supported.
|
||||
if (getApiLevel() >= 9) {
|
||||
apiPlatformAdapter = new GingerbreadPlatformAdapter();
|
||||
apiLevelAdapter = new ApiLevel9Adapter();
|
||||
} else if (getApiLevel() >= 8) {
|
||||
apiLevelAdapter = new ApiLevel8Adapter();
|
||||
} else if (getApiLevel() >= 5) {
|
||||
apiPlatformAdapter = new EclairPlatformAdapter();
|
||||
apiLevelAdapter = new ApiLevel5Adapter();
|
||||
} else {
|
||||
apiPlatformAdapter = new CupcakePlatformAdapter();
|
||||
apiLevelAdapter = new ApiLevel3Adapter();
|
||||
}
|
||||
|
||||
Log.i(Constants.TAG, "Using platform adapter " + apiPlatformAdapter.getClass());
|
||||
Log.i(Constants.TAG, "Using API level adapter " + apiLevelAdapter.getClass());
|
||||
}
|
||||
|
||||
public ApiPlatformAdapter getApiPlatformAdapter() {
|
||||
return apiPlatformAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether cloud backup (a.k.a. Froyo backup) is available.
|
||||
*/
|
||||
public boolean hasBackup() {
|
||||
return getApiLevel() >= 8;
|
||||
public ApiLevelAdapter getApiAdapter() {
|
||||
return apiLevelAdapter;
|
||||
}
|
||||
|
||||
// API Level 4 Changes
|
||||
|
||||
/**
|
||||
* Returns whether text-to-speech is available.
|
||||
*/
|
||||
public boolean hasTextToSpeech() {
|
||||
if (getApiLevel() < 4) return false;
|
||||
|
||||
try {
|
||||
Class.forName("android.speech.tts.TextToSpeech");
|
||||
} catch (ClassNotFoundException ex) {
|
||||
return false;
|
||||
} catch (LinkageError er) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean hasStrictMode() {
|
||||
return getApiLevel() >= 9;
|
||||
}
|
||||
|
||||
public boolean isAudioFocusSupported() {
|
||||
return getApiLevel() >= 8;
|
||||
return getApiLevel() >= 4;
|
||||
}
|
||||
|
||||
// API Level 5 Changes
|
||||
|
||||
/**
|
||||
* There's a bug (#1587) in Cupcake and Donut which prevents you from
|
||||
* using a SQLiteQueryBuilder twice. That is, if you call buildQuery
|
||||
@@ -122,18 +102,19 @@ public class ApiFeatures {
|
||||
* up. Specifically, it'll add extra parens which don't belong.
|
||||
*/
|
||||
public boolean canReuseSQLiteQueryBuilder() {
|
||||
return getApiLevel() > 4;
|
||||
return getApiLevel() >= 5;
|
||||
}
|
||||
|
||||
// API Level 10 changes
|
||||
|
||||
/**
|
||||
* Returns true if com.google.api.client.javanet.NetHttpTransport should be
|
||||
* used rather than com.google.api.client.apache.ApacheHttpTransport. See
|
||||
* {@link HttpTransport} for more info.
|
||||
* Returns true if BluetoothDevice.createInsecureRfcommSocketToServiceRecord
|
||||
* is available.
|
||||
*/
|
||||
public boolean useNetHttpTransport() {
|
||||
return getApiLevel() >= 9;
|
||||
public boolean hasBluetoothDeviceCreateInsecureRfcommSocketToServiceRecord() {
|
||||
return getApiLevel() >= 10;
|
||||
}
|
||||
|
||||
|
||||
// Visible for testing.
|
||||
protected int getApiLevel() {
|
||||
return ANDROID_API_LEVEL;
|
||||
|
||||
+46
-4
@@ -17,22 +17,31 @@ package com.google.android.apps.mytracks.util;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
||||
import com.google.android.apps.mytracks.services.tasks.PeriodicTask;
|
||||
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerTask;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.http.apache.ApacheHttpTransport;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* The Cupcake (API level 3) specific implementation of the
|
||||
* {@link ApiPlatformAdapter}.
|
||||
*
|
||||
* API level 3 specific implementation of the {@link ApiLevelAdapter}.
|
||||
*
|
||||
* @author Bartlomiej Niechwiej
|
||||
*/
|
||||
public class CupcakePlatformAdapter implements ApiPlatformAdapter {
|
||||
public class ApiLevel3Adapter implements ApiLevelAdapter {
|
||||
|
||||
@Override
|
||||
public void startForeground(Service service,
|
||||
@@ -51,6 +60,21 @@ public class CupcakePlatformAdapter implements ApiPlatformAdapter {
|
||||
notificationManager.cancel(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PeriodicTask getStatusAnnouncerTask(Context context) {
|
||||
return new StatusAnnouncerTask(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BackupPreferencesListener getBackupPreferencesListener(Context context) {
|
||||
return new BackupPreferencesListener() {
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
// Do nothing
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void setServiceForeground(Service service, boolean foreground) {
|
||||
// setForeground has been completely removed in API level 11, so we use reflection.
|
||||
@@ -79,4 +103,22 @@ public class CupcakePlatformAdapter implements ApiPlatformAdapter {
|
||||
public void enableStrictMode() {
|
||||
// Not supported
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] copyByteArray(byte[] input, int start, int end) {
|
||||
int length = end - start;
|
||||
byte[] output = new byte[length];
|
||||
System.arraycopy(input, start, output, 0, length);
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecimalFormatSymbols getDecimalFormatSymbols(Locale locale) {
|
||||
return new DecimalFormatSymbols(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpTransport getHttpTransport() {
|
||||
return new ApacheHttpTransport();
|
||||
}
|
||||
}
|
||||
+3
-15
@@ -18,15 +18,13 @@ package com.google.android.apps.mytracks.util;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
|
||||
/**
|
||||
* The Eclair (API level 5) specific implementation of the
|
||||
* {@link ApiPlatformAdapter}.
|
||||
*
|
||||
* API level 5 specific implementation of the {@link ApiLevelAdapter}.
|
||||
*
|
||||
* @author Bartlomiej Niechwiej
|
||||
*/
|
||||
public class EclairPlatformAdapter implements ApiPlatformAdapter {
|
||||
public class ApiLevel5Adapter extends ApiLevel3Adapter {
|
||||
|
||||
@Override
|
||||
public void startForeground(Service service,
|
||||
@@ -40,14 +38,4 @@ public class EclairPlatformAdapter implements ApiPlatformAdapter {
|
||||
NotificationManager notificationManager, int id) {
|
||||
service.stopForeground(id != -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyPreferenceChanges(Editor editor) {
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableStrictMode() {
|
||||
// Not supported
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.google.android.apps.mytracks.util;
|
||||
|
||||
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
||||
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListenerImpl;
|
||||
import com.google.android.apps.mytracks.services.tasks.FroyoStatusAnnouncerTask;
|
||||
import com.google.android.apps.mytracks.services.tasks.PeriodicTask;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* API level 8 specific implementation of the {@link ApiLevelAdapter}.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class ApiLevel8Adapter extends ApiLevel5Adapter {
|
||||
|
||||
@Override
|
||||
public PeriodicTask getStatusAnnouncerTask(Context context) {
|
||||
return new FroyoStatusAnnouncerTask(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BackupPreferencesListener getBackupPreferencesListener(Context context) {
|
||||
return new BackupPreferencesListenerImpl(context);
|
||||
}
|
||||
}
|
||||
+24
-3
@@ -1,18 +1,24 @@
|
||||
package com.google.android.apps.mytracks.util;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.http.javanet.NetHttpTransport;
|
||||
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.os.StrictMode;
|
||||
import android.util.Log;
|
||||
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* The Gingerbread (API level 9) specific implememntation of the
|
||||
* {@link ApiPlatformAdapter}.
|
||||
* API level 9 specific implementation of the {@link ApiLevelAdapter}.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class GingerbreadPlatformAdapter extends EclairPlatformAdapter {
|
||||
public class ApiLevel9Adapter extends ApiLevel8Adapter {
|
||||
|
||||
@Override
|
||||
public void applyPreferenceChanges(Editor editor) {
|
||||
// Apply asynchronously
|
||||
@@ -32,4 +38,19 @@ public class GingerbreadPlatformAdapter extends EclairPlatformAdapter {
|
||||
.penaltyLog()
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] copyByteArray(byte[] input, int start, int end) {
|
||||
return Arrays.copyOfRange(input, start, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecimalFormatSymbols getDecimalFormatSymbols(Locale locale) {
|
||||
return DecimalFormatSymbols.getInstance(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpTransport getHttpTransport() {
|
||||
return new NetHttpTransport();
|
||||
}
|
||||
}
|
||||
+65
-2
@@ -15,21 +15,31 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.util;
|
||||
|
||||
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
||||
import com.google.android.apps.mytracks.services.tasks.PeriodicTask;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* A set of methods that may be implemented in a platform specific way.
|
||||
* A set of methods that may be implemented differently depending on the Android API level.
|
||||
*
|
||||
* @author Bartlomiej Niechwiej
|
||||
*/
|
||||
public interface ApiPlatformAdapter {
|
||||
public interface ApiLevelAdapter {
|
||||
|
||||
/**
|
||||
* Puts the specified service into foreground.
|
||||
*
|
||||
* Due to changes in API level 5.
|
||||
*
|
||||
* @param service the service to be put in foreground.
|
||||
* @param notificationManager the notification manager used to post the given
|
||||
* notification.
|
||||
@@ -41,6 +51,9 @@ public interface ApiPlatformAdapter {
|
||||
|
||||
/**
|
||||
* Puts the given service into background.
|
||||
*
|
||||
* Due to changes in API level 5.
|
||||
*
|
||||
* @param service the service to put into background.
|
||||
* @param notificationManager the notification manager to user when removing
|
||||
* notifications.
|
||||
@@ -50,14 +63,64 @@ public interface ApiPlatformAdapter {
|
||||
void stopForeground(Service service, NotificationManager notificationManager,
|
||||
int id);
|
||||
|
||||
/**
|
||||
* Gets a status announcer task.
|
||||
*
|
||||
* Due to changes in API level 8.
|
||||
*/
|
||||
PeriodicTask getStatusAnnouncerTask(Context context);
|
||||
|
||||
/**
|
||||
* Gets a {@link BackupPreferencesListener}.
|
||||
*
|
||||
* Due to changes in API level 8.
|
||||
*/
|
||||
BackupPreferencesListener getBackupPreferencesListener(Context context);
|
||||
|
||||
/**
|
||||
* Applies all changes done to the given preferences editor.
|
||||
* Changes may or may not be applied immediately.
|
||||
*
|
||||
* Due to changes in API level 9.
|
||||
*/
|
||||
void applyPreferenceChanges(SharedPreferences.Editor editor);
|
||||
|
||||
/**
|
||||
* Enables strict mode where supported, only if this is a development build.
|
||||
*
|
||||
* Due to changes in API level 9.
|
||||
*/
|
||||
void enableStrictMode();
|
||||
|
||||
/**
|
||||
* Copies elements from the input byte array into a new byte array, from
|
||||
* indexes start (inclusive) to end (exclusive). The end index must be less
|
||||
* than or equal to input.length.
|
||||
*
|
||||
* Due to changes in API level 9.
|
||||
*
|
||||
* @param input the input byte array
|
||||
* @param start the start index
|
||||
* @param end the end index
|
||||
* @return a new array containing elements from the input byte array
|
||||
*/
|
||||
byte[] copyByteArray(byte[] input, int start, int end);
|
||||
|
||||
|
||||
/**
|
||||
* Gets an instance of {@link DecimalFormatSymbols} for a locale.
|
||||
*
|
||||
* Due to changes in API level 9.
|
||||
*
|
||||
* @param locale the locale
|
||||
* @return a new instance of {@link DecimalFormatSymbols}
|
||||
*/
|
||||
DecimalFormatSymbols getDecimalFormatSymbols(Locale locale);
|
||||
|
||||
/**
|
||||
* Gets a {@link HttpTransport}.
|
||||
*
|
||||
* Due to changes in API level 9.
|
||||
*/
|
||||
HttpTransport getHttpTransport();
|
||||
}
|
||||
@@ -58,7 +58,7 @@ public class ChartURLGenerator {
|
||||
}
|
||||
|
||||
return getChartUrl(distances, elevations, track,
|
||||
context.getString(R.string.elevation_label), metricUnits);
|
||||
context.getString(R.string.stat_elevation), metricUnits);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -221,34 +221,6 @@ public class StringUtils implements DescriptionGenerator {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public String formatTimeLong(long time) {
|
||||
int[] parts = getTimeParts(time);
|
||||
String secLabel =
|
||||
context.getString(parts[0] == 1 ? R.string.second : R.string.seconds);
|
||||
String minLabel =
|
||||
context.getString(parts[1] == 1 ? R.string.minute : R.string.minutes);
|
||||
String hourLabel =
|
||||
context.getString(parts[2] == 1 ? R.string.hour : R.string.hours);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (parts[2] != 0) {
|
||||
sb.append(parts[2]);
|
||||
sb.append(" ");
|
||||
sb.append(hourLabel);
|
||||
sb.append(" ");
|
||||
sb.append(parts[1]);
|
||||
sb.append(minLabel);
|
||||
} else {
|
||||
sb.append(parts[1]);
|
||||
sb.append(" ");
|
||||
sb.append(minLabel);
|
||||
sb.append(" ");
|
||||
sb.append(parts[0]);
|
||||
sb.append(secLabel);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a description for a track (with information about the
|
||||
* statistics).
|
||||
@@ -292,7 +264,7 @@ public class StringUtils implements DescriptionGenerator {
|
||||
minGrade = Math.round(trackMinGrade * 100);
|
||||
}
|
||||
|
||||
String category = context.getString(R.string.unknown);
|
||||
String category = context.getString(R.string.value_unknown);
|
||||
String trackCategory = track.getCategory();
|
||||
if (trackCategory != null && trackCategory.length() > 0) {
|
||||
category = trackCategory;
|
||||
@@ -300,20 +272,20 @@ public class StringUtils implements DescriptionGenerator {
|
||||
|
||||
String averageSpeed =
|
||||
getSpeedString(trackStats.getAverageSpeed(),
|
||||
R.string.average_speed_label,
|
||||
R.string.average_pace_label,
|
||||
R.string.stat_average_speed,
|
||||
R.string.stat_average_pace,
|
||||
displaySpeed);
|
||||
|
||||
String averageMovingSpeed =
|
||||
getSpeedString(trackStats.getAverageMovingSpeed(),
|
||||
R.string.average_moving_speed_label,
|
||||
R.string.average_moving_pace_label,
|
||||
R.string.stat_average_moving_speed,
|
||||
R.string.stat_average_moving_pace,
|
||||
displaySpeed);
|
||||
|
||||
String maxSpeed =
|
||||
getSpeedString(trackStats.getMaxSpeed(),
|
||||
R.string.max_speed_label,
|
||||
R.string.min_pace_label,
|
||||
R.string.stat_max_speed,
|
||||
R.string.stat_min_pace,
|
||||
displaySpeed);
|
||||
|
||||
return String.format("%s<p>"
|
||||
@@ -331,56 +303,72 @@ public class StringUtils implements DescriptionGenerator {
|
||||
+ "<img border=\"0\" src=\"%s\"/>",
|
||||
|
||||
// Line 1
|
||||
context.getString(R.string.fusiontable_link),
|
||||
getCreatedByMyTracks(context, true),
|
||||
|
||||
// Line 2
|
||||
context.getString(R.string.total_distance_label),
|
||||
distanceInKm, context.getString(R.string.kilometer),
|
||||
distanceInMiles, context.getString(R.string.mile),
|
||||
context.getString(R.string.stat_total_distance),
|
||||
distanceInKm, context.getString(R.string.unit_kilometer),
|
||||
distanceInMiles, context.getString(R.string.unit_mile),
|
||||
|
||||
// Line 3
|
||||
context.getString(R.string.total_time_label),
|
||||
context.getString(R.string.stat_total_time),
|
||||
StringUtils.formatTime(trackStats.getTotalTime()),
|
||||
|
||||
// Line 4
|
||||
context.getString(R.string.moving_time_label),
|
||||
context.getString(R.string.stat_moving_time),
|
||||
StringUtils.formatTime(trackStats.getMovingTime()),
|
||||
|
||||
// Line 5
|
||||
averageSpeed, averageMovingSpeed, maxSpeed,
|
||||
|
||||
// Line 6
|
||||
context.getString(R.string.min_elevation_label),
|
||||
minElevationInMeters, context.getString(R.string.meter),
|
||||
minElevationInFeet, context.getString(R.string.feet),
|
||||
context.getString(R.string.stat_min_elevation),
|
||||
minElevationInMeters, context.getString(R.string.unit_meter),
|
||||
minElevationInFeet, context.getString(R.string.unit_feet),
|
||||
|
||||
// Line 7
|
||||
context.getString(R.string.max_elevation_label),
|
||||
maxElevationInMeters, context.getString(R.string.meter),
|
||||
maxElevationInFeet, context.getString(R.string.feet),
|
||||
context.getString(R.string.stat_max_elevation),
|
||||
maxElevationInMeters, context.getString(R.string.unit_meter),
|
||||
maxElevationInFeet, context.getString(R.string.unit_feet),
|
||||
|
||||
// Line 8
|
||||
context.getString(R.string.elevation_gain_label),
|
||||
elevationGainInMeters, context.getString(R.string.meter),
|
||||
elevationGainInFeet, context.getString(R.string.feet),
|
||||
context.getString(R.string.stat_elevation_gain),
|
||||
elevationGainInMeters, context.getString(R.string.unit_meter),
|
||||
elevationGainInFeet, context.getString(R.string.unit_feet),
|
||||
|
||||
// Line 9
|
||||
context.getString(R.string.max_grade_label), maxGrade,
|
||||
context.getString(R.string.stat_max_grade), maxGrade,
|
||||
|
||||
// Line 10
|
||||
context.getString(R.string.min_grade_label), minGrade,
|
||||
context.getString(R.string.stat_min_grade), minGrade,
|
||||
|
||||
// Line 11
|
||||
context.getString(R.string.recorded_date),
|
||||
context.getString(R.string.send_google_recorded),
|
||||
new Date(trackStats.getStartTime()),
|
||||
|
||||
// Line 12
|
||||
context.getString(R.string.category), category,
|
||||
context.getString(R.string.track_detail_activity_type_hint), category,
|
||||
|
||||
// Line 13
|
||||
ChartURLGenerator.getChartUrl(distances, elevations, track, context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 'Created by My Tracks on Android' string.
|
||||
*
|
||||
* @param context the context
|
||||
* @param addLink true to add a link to the My Tracks web site
|
||||
*/
|
||||
public static String getCreatedByMyTracks(Context context, boolean addLink) {
|
||||
String format = context.getString(R.string.send_google_by_my_tracks);
|
||||
if (addLink) {
|
||||
String url = context.getString(R.string.my_tracks_web_url);
|
||||
return String.format(format, "<a href='http://" + url + "'>", "</a>");
|
||||
} else {
|
||||
return String.format(format, "", "");
|
||||
}
|
||||
}
|
||||
|
||||
private String getSpeedString(double speed, int speedLabel, int paceLabel,
|
||||
boolean displaySpeed) {
|
||||
double speedInKph = speed * 3.6;
|
||||
@@ -388,8 +376,8 @@ public class StringUtils implements DescriptionGenerator {
|
||||
if (displaySpeed) {
|
||||
return String.format("%s: %.2f %s (%.1f %s)<br>",
|
||||
context.getString(speedLabel),
|
||||
speedInKph, context.getString(R.string.kilometer_per_hour),
|
||||
speedInMph, context.getString(R.string.mile_per_hour));
|
||||
speedInKph, context.getString(R.string.unit_kilometer_per_hour),
|
||||
speedInMph, context.getString(R.string.unit_mile_per_hour));
|
||||
} else {
|
||||
double paceInKm;
|
||||
double paceInMi;
|
||||
@@ -402,8 +390,8 @@ public class StringUtils implements DescriptionGenerator {
|
||||
}
|
||||
return String.format("%s: %.2f %s (%.1f %s)<br>",
|
||||
context.getString(paceLabel),
|
||||
paceInKm, context.getString(R.string.min_per_kilometer),
|
||||
paceInMi, context.getString(R.string.min_per_mile));
|
||||
paceInKm, context.getString(R.string.unit_minute_per_kilometer),
|
||||
paceInMi, context.getString(R.string.unit_minute_per_mile));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,34 +450,34 @@ public class StringUtils implements DescriptionGenerator {
|
||||
+ "%s: %d %s (%d %s)\n"
|
||||
+ "%s: %d %s\n"
|
||||
+ "%s: %d %s\n",
|
||||
context.getString(R.string.distance_label),
|
||||
distanceInKm, context.getString(R.string.kilometer),
|
||||
distanceInMiles, context.getString(R.string.mile),
|
||||
context.getString(R.string.time_label),
|
||||
context.getString(R.string.stat_total_distance),
|
||||
distanceInKm, context.getString(R.string.unit_kilometer),
|
||||
distanceInMiles, context.getString(R.string.unit_mile),
|
||||
context.getString(R.string.stat_total_time),
|
||||
StringUtils.formatTime(stats.getTotalTime()),
|
||||
context.getString(R.string.moving_time_label),
|
||||
context.getString(R.string.stat_moving_time),
|
||||
StringUtils.formatTime(stats.getMovingTime()),
|
||||
context.getString(R.string.average_speed_label),
|
||||
averageSpeedInKmh, context.getString(R.string.kilometer_per_hour),
|
||||
averageSpeedInMph, context.getString(R.string.mile_per_hour),
|
||||
context.getString(R.string.average_moving_speed_label),
|
||||
movingSpeedInKmh, context.getString(R.string.kilometer_per_hour),
|
||||
movingSpeedInMph, context.getString(R.string.mile_per_hour),
|
||||
context.getString(R.string.max_speed_label),
|
||||
maxSpeedInKmh, context.getString(R.string.kilometer_per_hour),
|
||||
maxSpeedInMph, context.getString(R.string.mile_per_hour),
|
||||
context.getString(R.string.min_elevation_label),
|
||||
minElevationInMeters, context.getString(R.string.meter),
|
||||
minElevationInFeet, context.getString(R.string.feet),
|
||||
context.getString(R.string.max_elevation_label),
|
||||
maxElevationInMeters, context.getString(R.string.meter),
|
||||
maxElevationInFeet, context.getString(R.string.feet),
|
||||
context.getString(R.string.elevation_gain_label),
|
||||
elevationGainInMeters, context.getString(R.string.meter),
|
||||
elevationGainInFeet, context.getString(R.string.feet),
|
||||
context.getString(R.string.max_grade_label),
|
||||
context.getString(R.string.stat_average_speed),
|
||||
averageSpeedInKmh, context.getString(R.string.unit_kilometer_per_hour),
|
||||
averageSpeedInMph, context.getString(R.string.unit_mile_per_hour),
|
||||
context.getString(R.string.stat_average_moving_speed),
|
||||
movingSpeedInKmh, context.getString(R.string.unit_kilometer_per_hour),
|
||||
movingSpeedInMph, context.getString(R.string.unit_mile_per_hour),
|
||||
context.getString(R.string.stat_max_speed),
|
||||
maxSpeedInKmh, context.getString(R.string.unit_kilometer_per_hour),
|
||||
maxSpeedInMph, context.getString(R.string.unit_mile_per_hour),
|
||||
context.getString(R.string.stat_min_elevation),
|
||||
minElevationInMeters, context.getString(R.string.unit_meter),
|
||||
minElevationInFeet, context.getString(R.string.unit_feet),
|
||||
context.getString(R.string.stat_max_elevation),
|
||||
maxElevationInMeters, context.getString(R.string.unit_meter),
|
||||
maxElevationInFeet, context.getString(R.string.unit_feet),
|
||||
context.getString(R.string.stat_elevation_gain),
|
||||
elevationGainInMeters, context.getString(R.string.unit_meter),
|
||||
elevationGainInFeet, context.getString(R.string.unit_feet),
|
||||
context.getString(R.string.stat_max_grade),
|
||||
theMaxGrade, percent,
|
||||
context.getString(R.string.min_grade_label),
|
||||
context.getString(R.string.stat_min_grade),
|
||||
theMinGrade, percent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,16 @@ package com.google.android.apps.mytracks.widgets;
|
||||
import static com.google.android.apps.mytracks.Constants.SETTINGS_NAME;
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracks;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.services.ControlRecordingService;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
@@ -32,16 +42,6 @@ import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracks;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.services.TrackRecordingService;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
/**
|
||||
* An AppWidgetProvider for displaying key track statistics (distance, time,
|
||||
* speed) from the current or most recent track.
|
||||
@@ -85,14 +85,14 @@ public class TrackWidgetProvider
|
||||
selectedTrackId = -1;
|
||||
}
|
||||
|
||||
private void initialize(Context context) {
|
||||
private void initialize(Context aContext) {
|
||||
if (this.context != null) {
|
||||
return;
|
||||
}
|
||||
this.context = context;
|
||||
this.context = aContext;
|
||||
trackObserver = new TrackObserver();
|
||||
providerUtils = MyTracksProviderUtils.Factory.get(context);
|
||||
unknown = context.getString(R.string.unknown);
|
||||
unknown = context.getString(R.string.value_unknown);
|
||||
|
||||
sharedPreferences = context.getSharedPreferences(SETTINGS_NAME, 0);
|
||||
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
|
||||
@@ -105,9 +105,9 @@ public class TrackWidgetProvider
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
super.onReceive(context, intent);
|
||||
initialize(context);
|
||||
public void onReceive(Context aContext, Intent intent) {
|
||||
super.onReceive(aContext, intent);
|
||||
initialize(aContext);
|
||||
|
||||
selectedTrackId = intent.getLongExtra(
|
||||
context.getString(R.string.track_id_broadcast_extra), selectedTrackId);
|
||||
@@ -124,9 +124,9 @@ public class TrackWidgetProvider
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisabled(Context context) {
|
||||
public void onDisabled(Context aContext) {
|
||||
if (trackObserver != null) {
|
||||
context.getContentResolver().unregisterContentObserver(trackObserver);
|
||||
aContext.getContentResolver().unregisterContentObserver(trackObserver);
|
||||
}
|
||||
if (sharedPreferences != null) {
|
||||
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
|
||||
@@ -154,7 +154,7 @@ public class TrackWidgetProvider
|
||||
views.setOnClickPendingIntent(R.id.appwidget_track_statistics, pendingIntent);
|
||||
|
||||
if (action != null) {
|
||||
updateViewButton(views, context, action);
|
||||
updateViewButton(views, action);
|
||||
}
|
||||
updateViewTrackStatistics(views, track);
|
||||
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(widget);
|
||||
@@ -167,22 +167,17 @@ public class TrackWidgetProvider
|
||||
* Update the widget's button with the appropriate intent and icon.
|
||||
*
|
||||
* @param views The RemoteViews containing the button
|
||||
* @param context The Context of the AppWidget
|
||||
* @param action The action broadcast from the track service
|
||||
*/
|
||||
private void updateViewButton(RemoteViews views, Context context, String action) {
|
||||
private void updateViewButton(RemoteViews views, String action) {
|
||||
if (TRACK_STARTED_ACTION.equals(action)) {
|
||||
// If a new track is started by this appwidget or elsewhere,
|
||||
// toggle the button to active and have it disable the track if pressed.
|
||||
setButtonIntent(
|
||||
views, context, R.string.end_current_track_action, R.drawable.appwidget_button_enabled,
|
||||
-1);
|
||||
setButtonIntent(views, R.string.track_action_end, R.drawable.appwidget_button_enabled);
|
||||
} else {
|
||||
// If a track is stopped by this appwidget or elsewhere,
|
||||
// toggle the button to inactive and have it start a new track if pressed.
|
||||
setButtonIntent(
|
||||
views, context, R.string.start_new_track_action, R.drawable.appwidget_button_disabled,
|
||||
R.string.select_new_track_extra);
|
||||
setButtonIntent(views, R.string.track_action_start, R.drawable.appwidget_button_disabled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,18 +185,12 @@ public class TrackWidgetProvider
|
||||
* Set up the main widget button.
|
||||
*
|
||||
* @param views The widget views
|
||||
* @param context The widget context
|
||||
* @param action The resource id of the action to fire when the button is pressed
|
||||
* @param icon The resource id of the icon to show for the button
|
||||
* @param extra Optional resource id of a boolean extra on the intent
|
||||
*/
|
||||
private void setButtonIntent(
|
||||
RemoteViews views, Context context, int action, int icon, int extra) {
|
||||
Intent intent = new Intent(context, TrackRecordingService.class);
|
||||
private void setButtonIntent(RemoteViews views, int action, int icon) {
|
||||
Intent intent = new Intent(context, ControlRecordingService.class);
|
||||
intent.setAction(context.getString(action));
|
||||
if (extra != -1) {
|
||||
intent.putExtra(context.getString(extra), true);
|
||||
}
|
||||
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
|
||||
intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
views.setOnClickPendingIntent(R.id.appwidget_button, pendingIntent);
|
||||
@@ -261,9 +250,11 @@ public class TrackWidgetProvider
|
||||
String metricUnitsKey = context.getString(R.string.metric_units_key);
|
||||
if (key == null || key.equals(metricUnitsKey)) {
|
||||
isMetric = prefs.getBoolean(metricUnitsKey, true);
|
||||
distanceLabel = context.getString(isMetric ? R.string.kilometer : R.string.mile);
|
||||
speedLabel = context.getString(isMetric ? R.string.kilometer_per_hour : R.string.mile_per_hour);
|
||||
paceLabel = context.getString(isMetric ? R.string.min_per_kilometer : R.string.min_per_mile);
|
||||
distanceLabel = context.getString(isMetric ? R.string.unit_kilometer : R.string.unit_mile);
|
||||
speedLabel = context.getString(
|
||||
isMetric ? R.string.unit_kilometer_per_hour : R.string.unit_mile_per_hour);
|
||||
paceLabel = context.getString(
|
||||
isMetric ? R.string.unit_minute_per_kilometer : R.string.unit_minute_per_mile);
|
||||
}
|
||||
|
||||
String reportSpeedKey = context.getString(R.string.report_speed_key);
|
||||
|
||||
@@ -153,7 +153,7 @@ public class SpreadsheetsClient extends GDataServiceClient {
|
||||
* @return a parser for the indicated feed
|
||||
* @throws ParseException if the response from the server could not be parsed
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public GDataParser getParserForFeed(
|
||||
Class feedEntryClass, String feedUri, String authToken)
|
||||
@@ -227,7 +227,7 @@ public class SpreadsheetsClient extends GDataServiceClient {
|
||||
* Converts an HTTP exception which happened while writing to the equivalent
|
||||
* local exception.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@SuppressWarnings("unchecked")
|
||||
private void convertHttpExceptionForWrites(
|
||||
Class entryClass, String message, HttpException cause)
|
||||
throws ParseException, IOException {
|
||||
@@ -253,7 +253,7 @@ public class SpreadsheetsClient extends GDataServiceClient {
|
||||
/**
|
||||
* Parses one entry from the input stream.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@SuppressWarnings("unchecked")
|
||||
private Entry parseEntry(Class entryClass, InputStream is)
|
||||
throws ParseException, IOException {
|
||||
GDataParser parser = null;
|
||||
|
||||
@@ -48,7 +48,7 @@ public class XmlDocsGDataParserFactory implements GDataParserFactory {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public GDataParser createParser(Class cls, InputStream is)
|
||||
throws ParseException {
|
||||
|
||||
Reference in New Issue
Block a user