forked from upstream-mirrors/OpenTracks
Fix Stats view.
- when paused, do not update current location - handle possible null pointer for getActivity In MyTraksProviderUtils, change to getLastValidLocation
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* A DialogFragment to show information about My Tracks.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class AboutDialogFragment extends DialogFragment {
|
||||
|
||||
public static final String ABOUT_DIALOG_TAG = "aboutDialog";
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
View view = getActivity().getLayoutInflater().inflate(R.layout.about, null);
|
||||
TextView aboutVersion = (TextView) view.findViewById(R.id.about_version);
|
||||
aboutVersion.setText(SystemUtils.getMyTracksVersion(getActivity()));
|
||||
return new AlertDialog.Builder(getActivity())
|
||||
.setNegativeButton(R.string.about_license, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
EulaDialogFragment.newInstance(true).show(
|
||||
getActivity().getSupportFragmentManager(), EulaDialogFragment.EULA_DIALOG_TAG);
|
||||
}
|
||||
})
|
||||
.setPositiveButton(R.string.generic_ok, null)
|
||||
.setTitle(R.string.help_about)
|
||||
.setView(view)
|
||||
.create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,511 @@
|
||||
/*
|
||||
* Copyright 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.ChartView;
|
||||
import com.google.android.apps.mytracks.TrackDetailActivity;
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub;
|
||||
import com.google.android.apps.mytracks.content.TrackDataListener;
|
||||
import com.google.android.apps.mytracks.content.TrackDataType;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
|
||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.widget.ZoomControls;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* A fragment to display track chart to the user.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
|
||||
public static final String CHART_FRAGMENT_TAG = "chartFragment";
|
||||
|
||||
private final ArrayList<double[]> pendingPoints = new ArrayList<double[]>();
|
||||
|
||||
private TrackDataHub trackDataHub;
|
||||
|
||||
// Stats gathered from the received data
|
||||
private TripStatisticsBuilder tripStatisticsBuilder;
|
||||
private long startTime;
|
||||
|
||||
private boolean metricUnits = PreferencesUtils.METRIC_UNITS_DEFAULT;
|
||||
private boolean reportSpeed = PreferencesUtils.REPORT_SPEED_DEFAULT;
|
||||
private int minRecordingDistance = PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT;
|
||||
|
||||
// Modes of operation
|
||||
private boolean chartByDistance = true;
|
||||
private boolean[] chartShow = new boolean[] { true, true, true, true, true, true };
|
||||
|
||||
// UI elements
|
||||
private ChartView chartView;
|
||||
private ZoomControls zoomControls;
|
||||
|
||||
/**
|
||||
* A runnable that will enable/disable zoom controls and orange pointer as
|
||||
* appropriate and redraw.
|
||||
*/
|
||||
private final Runnable updateChart = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (trackDataHub == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
zoomControls.setIsZoomInEnabled(chartView.canZoomIn());
|
||||
zoomControls.setIsZoomOutEnabled(chartView.canZoomOut());
|
||||
chartView.setShowPointer(isSelectedTrackRecording());
|
||||
chartView.invalidate();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
/*
|
||||
* Create a chartView here to store data thus won't need to reload all the
|
||||
* data on every onStart or onResume.
|
||||
*/
|
||||
chartView = new ChartView(getActivity());
|
||||
};
|
||||
|
||||
@Override
|
||||
public View onCreateView(
|
||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.chart, container, false);
|
||||
zoomControls = (ZoomControls) view.findViewById(R.id.chart_zoom_controls);
|
||||
zoomControls.setOnZoomInClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
zoomIn();
|
||||
}
|
||||
});
|
||||
zoomControls.setOnZoomOutClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
zoomOut();
|
||||
}
|
||||
});
|
||||
return view;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
ViewGroup layout = (ViewGroup) getActivity().findViewById(R.id.chart_view_layout);
|
||||
LayoutParams layoutParams = new LayoutParams(
|
||||
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
|
||||
layout.addView(chartView, layoutParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
resumeTrackDataHub();
|
||||
checkChartSettings();
|
||||
getActivity().runOnUiThread(updateChart);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
pauseTrackDataHub();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
ViewGroup layout = (ViewGroup) getActivity().findViewById(R.id.chart_view_layout);
|
||||
layout.removeView(chartView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationStateChanged(LocationState state) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(Location loc) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHeadingChanged(double heading) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectedTrackChanged(Track track) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackUpdated(Track track) {
|
||||
if (track == null || track.getTripStatistics() == null) {
|
||||
startTime = -1L;
|
||||
return;
|
||||
}
|
||||
startTime = track.getTripStatistics().getStartTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTrackPoints() {
|
||||
tripStatisticsBuilder = startTime != -1L ? new TripStatisticsBuilder(startTime) : null;
|
||||
pendingPoints.clear();
|
||||
chartView.reset();
|
||||
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
chartView.resetScroll();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSampledInTrackPoint(Location location) {
|
||||
double[] data = new double[ChartView.NUM_SERIES + 1];
|
||||
fillDataPoint(location, data);
|
||||
pendingPoints.add(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSampledOutTrackPoint(Location location) {
|
||||
fillDataPoint(location, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSegmentSplit(Location location) {
|
||||
fillDataPoint(location, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewTrackPointsDone() {
|
||||
chartView.addDataPoints(pendingPoints);
|
||||
pendingPoints.clear();
|
||||
getActivity().runOnUiThread(updateChart);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWaypoints() {
|
||||
chartView.clearWaypoints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewWaypoint(Waypoint waypoint) {
|
||||
if (waypoint != null && LocationUtils.isValidLocation(waypoint.getLocation())) {
|
||||
chartView.addWaypoint(waypoint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewWaypointsDone() {
|
||||
getActivity().runOnUiThread(updateChart);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMetricUnitsChanged(boolean metric) {
|
||||
if (metricUnits == metric) {
|
||||
return false;
|
||||
}
|
||||
metricUnits = metric;
|
||||
chartView.setMetricUnits(metricUnits);
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
chartView.requestLayout();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onReportSpeedChanged(boolean speed) {
|
||||
if (reportSpeed == speed) {
|
||||
return false;
|
||||
}
|
||||
reportSpeed = speed;
|
||||
chartView.setReportSpeed(reportSpeed);
|
||||
boolean chartShowSpeed = PreferencesUtils.getBoolean(
|
||||
getActivity(), R.string.chart_show_speed_key, PreferencesUtils.CHART_SHOW_SPEED_DEFAULT);
|
||||
setSeriesEnabled(ChartView.SPEED_SERIES, chartShowSpeed && reportSpeed);
|
||||
setSeriesEnabled(ChartView.PACE_SERIES, chartShowSpeed && !reportSpeed);
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
chartView.requestLayout();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMinRecordingDistanceChanged(int value) {
|
||||
if (minRecordingDistance == value) {
|
||||
return false;
|
||||
}
|
||||
minRecordingDistance = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the chart settings.
|
||||
*/
|
||||
private void checkChartSettings() {
|
||||
boolean needUpdate = false;
|
||||
if (chartByDistance != PreferencesUtils.getBoolean(getActivity(),
|
||||
R.string.chart_by_distance_key, PreferencesUtils.CHART_BY_DISTANCE_DEFAULT)) {
|
||||
chartByDistance = !chartByDistance;
|
||||
chartView.setChartByDistance(chartByDistance);
|
||||
reloadTrackDataHub();
|
||||
needUpdate = true;
|
||||
}
|
||||
if (setSeriesEnabled(ChartView.ELEVATION_SERIES, PreferencesUtils.getBoolean(getActivity(),
|
||||
R.string.chart_show_elevation_key, PreferencesUtils.CHART_SHOW_ELEVATION_DEFAULT))) {
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
boolean chartShowSpeed = PreferencesUtils.getBoolean(
|
||||
getActivity(), R.string.chart_show_speed_key, PreferencesUtils.CHART_SHOW_SPEED_DEFAULT);
|
||||
if (setSeriesEnabled(ChartView.SPEED_SERIES, chartShowSpeed && reportSpeed)) {
|
||||
needUpdate = true;
|
||||
}
|
||||
if (setSeriesEnabled(ChartView.PACE_SERIES, chartShowSpeed && !reportSpeed)) {
|
||||
needUpdate = true;
|
||||
}
|
||||
if (setSeriesEnabled(ChartView.POWER_SERIES, PreferencesUtils.getBoolean(
|
||||
getActivity(), R.string.chart_show_power_key, PreferencesUtils.CHART_SHOW_POWER_DEFAULT))) {
|
||||
needUpdate = true;
|
||||
}
|
||||
if (setSeriesEnabled(ChartView.CADENCE_SERIES, PreferencesUtils.getBoolean(getActivity(),
|
||||
R.string.chart_show_cadence_key, PreferencesUtils.CHART_SHOW_CADENCE_DEFAULT))) {
|
||||
needUpdate = true;
|
||||
}
|
||||
if (setSeriesEnabled(ChartView.HEART_RATE_SERIES, PreferencesUtils.getBoolean(getActivity(),
|
||||
R.string.chart_show_heart_rate_key, PreferencesUtils.CHART_SHOW_HEART_RATE_DEFAULT))) {
|
||||
needUpdate = true;
|
||||
}
|
||||
if (needUpdate) {
|
||||
chartView.postInvalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the series enabled value.
|
||||
*
|
||||
* @param index the series index
|
||||
* @param value the value
|
||||
* @return true if changed
|
||||
*/
|
||||
private boolean setSeriesEnabled(int index, boolean value) {
|
||||
if (chartShow[index] != value) {
|
||||
chartShow[index] = value;
|
||||
chartView.setChartValueSeriesEnabled(index, value);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the trackDataHub. Needs to be synchronized because trackDataHub can
|
||||
* be accessed by multiple threads.
|
||||
*/
|
||||
private synchronized void resumeTrackDataHub() {
|
||||
trackDataHub = ((TrackDetailActivity) getActivity()).getTrackDataHub();
|
||||
trackDataHub.registerTrackDataListener(this, EnumSet.of(TrackDataType.SELECTED_TRACK,
|
||||
TrackDataType.TRACKS_TABLE, TrackDataType.WAYPOINTS_TABLE,
|
||||
TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE, TrackDataType.SAMPLED_OUT_TRACK_POINTS_TABLE,
|
||||
TrackDataType.PREFERENCE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the trackDataHub. Needs to be synchronized because trackDataHub can
|
||||
* be accessed by multiple threads.
|
||||
*/
|
||||
private synchronized void pauseTrackDataHub() {
|
||||
trackDataHub.unregisterTrackDataListener(this);
|
||||
trackDataHub = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the selected track is recording. Needs to be synchronized
|
||||
* because trackDataHub can be accessed by multiple threads.
|
||||
*/
|
||||
private synchronized boolean isSelectedTrackRecording() {
|
||||
return trackDataHub != null && trackDataHub.isSelectedTrackRecording();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the trackDataHub. Needs to be synchronized because trackDataHub can
|
||||
* be accessed by multiple threads.
|
||||
*/
|
||||
private synchronized void reloadTrackDataHub() {
|
||||
if (trackDataHub != null) {
|
||||
trackDataHub.reloadDataForListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To zoom in.
|
||||
*/
|
||||
private void zoomIn() {
|
||||
chartView.zoomIn();
|
||||
zoomControls.setIsZoomInEnabled(chartView.canZoomIn());
|
||||
zoomControls.setIsZoomOutEnabled(chartView.canZoomOut());
|
||||
}
|
||||
|
||||
/**
|
||||
* To zoom out.
|
||||
*/
|
||||
private void zoomOut() {
|
||||
chartView.zoomOut();
|
||||
zoomControls.setIsZoomInEnabled(chartView.canZoomIn());
|
||||
zoomControls.setIsZoomOutEnabled(chartView.canZoomOut());
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a location, fill in a data point, an array of double[]. <br>
|
||||
* data[0] = time/distance <br>
|
||||
* data[1] = elevation <br>
|
||||
* data[2] = speed <br>
|
||||
* data[3] = pace <br>
|
||||
* data[4] = heart rate <br>
|
||||
* data[5] = cadence <br>
|
||||
* data[6] = power <br>
|
||||
*
|
||||
* @param location the location
|
||||
* @param data the data point to fill in, can be null
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void fillDataPoint(Location location, double data[]) {
|
||||
double timeOrDistance = Double.NaN;
|
||||
double elevation = Double.NaN;
|
||||
double speed = Double.NaN;
|
||||
double pace = Double.NaN;
|
||||
double heartRate = Double.NaN;
|
||||
double cadence = Double.NaN;
|
||||
double power = Double.NaN;
|
||||
|
||||
if (tripStatisticsBuilder != null) {
|
||||
tripStatisticsBuilder.addLocation(location, minRecordingDistance);
|
||||
TripStatistics tripStatistics = tripStatisticsBuilder.getTripStatistics();
|
||||
if (chartByDistance) {
|
||||
double distance = tripStatistics.getTotalDistance() * UnitConversions.M_TO_KM;
|
||||
if (!metricUnits) {
|
||||
distance *= UnitConversions.KM_TO_MI;
|
||||
}
|
||||
timeOrDistance = distance;
|
||||
} else {
|
||||
timeOrDistance = tripStatistics.getTotalTime();
|
||||
}
|
||||
|
||||
elevation = tripStatisticsBuilder.getSmoothedElevation();
|
||||
if (!metricUnits) {
|
||||
elevation *= UnitConversions.M_TO_FT;
|
||||
}
|
||||
|
||||
speed = tripStatisticsBuilder.getSmoothedSpeed() * UnitConversions.MS_TO_KMH;
|
||||
if (!metricUnits) {
|
||||
speed *= UnitConversions.KM_TO_MI;
|
||||
}
|
||||
pace = speed == 0 ? 0.0 : 60.0 / speed;
|
||||
}
|
||||
if (location instanceof MyTracksLocation
|
||||
&& ((MyTracksLocation) location).getSensorDataSet() != null) {
|
||||
SensorDataSet sensorDataSet = ((MyTracksLocation) location).getSensorDataSet();
|
||||
if (sensorDataSet.hasHeartRate()
|
||||
&& sensorDataSet.getHeartRate().getState() == Sensor.SensorState.SENDING
|
||||
&& sensorDataSet.getHeartRate().hasValue()) {
|
||||
heartRate = sensorDataSet.getHeartRate().getValue();
|
||||
}
|
||||
if (sensorDataSet.hasCadence()
|
||||
&& sensorDataSet.getCadence().getState() == Sensor.SensorState.SENDING
|
||||
&& sensorDataSet.getCadence().hasValue()) {
|
||||
cadence = sensorDataSet.getCadence().getValue();
|
||||
}
|
||||
if (sensorDataSet.hasPower()
|
||||
&& sensorDataSet.getPower().getState() == Sensor.SensorState.SENDING
|
||||
&& sensorDataSet.getPower().hasValue()) {
|
||||
power = sensorDataSet.getPower().getValue();
|
||||
}
|
||||
}
|
||||
|
||||
if (data != null) {
|
||||
data[0] = timeOrDistance;
|
||||
data[1] = elevation;
|
||||
data[2] = speed;
|
||||
data[3] = pace;
|
||||
data[4] = heartRate;
|
||||
data[5] = cadence;
|
||||
data[6] = power;
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
ChartView getChartView() {
|
||||
return chartView;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setTripStatisticsBuilder(long time) {
|
||||
tripStatisticsBuilder = new TripStatisticsBuilder(time);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setChartView(ChartView view) {
|
||||
chartView = view;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setMetricUnits(boolean value) {
|
||||
metricUnits = value;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setReportSpeed(boolean value) {
|
||||
reportSpeed = value;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setChartByDistance(boolean value) {
|
||||
chartByDistance = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.TrackListActivity;
|
||||
import com.google.android.apps.mytracks.util.EulaUtils;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* A DialogFragment to check preferred units.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class CheckUnitsDialogFragment extends DialogFragment {
|
||||
|
||||
public static final String CHECK_UNITS_DIALOG_TAG = "checkUnitsDialog";
|
||||
|
||||
@Override
|
||||
public void onCancel(DialogInterface arg0) {
|
||||
onDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
Locale defaultLocale = Locale.getDefault();
|
||||
boolean defaultMetric = !defaultLocale.equals(Locale.US) && !defaultLocale.equals(Locale.UK);
|
||||
PreferencesUtils.setBoolean(getActivity(), R.string.metric_units_key, defaultMetric);
|
||||
final String metric = getString(R.string.settings_stats_units_metric);
|
||||
final String imperial = getString(R.string.settings_stats_units_imperial);
|
||||
final CharSequence[] items = defaultMetric ? new CharSequence[] { metric, imperial }
|
||||
: new CharSequence[] { imperial, metric };
|
||||
return new AlertDialog.Builder(getActivity())
|
||||
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
int position = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||
PreferencesUtils.setBoolean(
|
||||
getActivity(), R.string.metric_units_key, items[position].equals(metric));
|
||||
onDone();
|
||||
}
|
||||
})
|
||||
.setSingleChoiceItems(items, 0, null)
|
||||
.setTitle(R.string.settings_stats_units_title).create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tasks to perform when done.
|
||||
*/
|
||||
private void onDone() {
|
||||
EulaUtils.setShowCheckUnits(getActivity());
|
||||
TrackListActivity trackListActivity = (TrackListActivity) getActivity();
|
||||
trackListActivity.showStartupDialogs();
|
||||
}
|
||||
}
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
|
||||
import com.google.android.apps.mytracks.io.sendtogoogle.ConfirmSharingActivity;
|
||||
import com.google.android.apps.mytracks.util.IntentUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.ShareCompat;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A DialogFragment to choose an activity.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class ChooseActivityDialogFragment extends DialogFragment {
|
||||
|
||||
public static final String CHOOSE_ACTIVITY_DIALOG_TAG = "chooseActivityDialog";
|
||||
|
||||
private static final String KEY_TRACK_ID = "trackId";
|
||||
private static final String KEY_TRACK_URL = "trackUrl";
|
||||
|
||||
private PackageManager packageManager;
|
||||
|
||||
public static ChooseActivityDialogFragment newInstance(long trackId, String trackUrl) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putLong(KEY_TRACK_ID, trackId);
|
||||
bundle.putString(KEY_TRACK_URL, trackUrl);
|
||||
|
||||
ChooseActivityDialogFragment chooseActivityDialogFragment = new ChooseActivityDialogFragment();
|
||||
chooseActivityDialogFragment.setArguments(bundle);
|
||||
return chooseActivityDialogFragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
packageManager = getActivity().getPackageManager();
|
||||
List<DisplayInfo> displayInfos = getDisplayInfos();
|
||||
|
||||
ArrayAdapter<DisplayInfo> arrayAdapter = new ArrayAdapter<DisplayInfo>(getActivity(),
|
||||
R.layout.choose_activity_list_item, R.id.choose_activity_list_item_text1, displayInfos) {
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View view;
|
||||
if (convertView == null) {
|
||||
view = getActivity()
|
||||
.getLayoutInflater().inflate(R.layout.choose_activity_list_item, parent, false);
|
||||
} else {
|
||||
view = convertView;
|
||||
}
|
||||
DisplayInfo displayInfo = getItem(position);
|
||||
TextView text1 = (TextView) view.findViewById(R.id.choose_activity_list_item_text1);
|
||||
TextView text2 = (TextView) view.findViewById(R.id.choose_activity_list_item_text2);
|
||||
ImageView icon = (ImageView) view.findViewById(R.id.choose_activity_list_item_icon);
|
||||
text1.setText(displayInfo.primaryLabel);
|
||||
if (displayInfo.secondaryLabel != null) {
|
||||
text2.setVisibility(View.VISIBLE);
|
||||
text2.setText(displayInfo.secondaryLabel);
|
||||
} else {
|
||||
text2.setVisibility(View.GONE);
|
||||
}
|
||||
icon.setImageDrawable(displayInfo.icon);
|
||||
return view;
|
||||
}
|
||||
};
|
||||
return new AlertDialog.Builder(getActivity())
|
||||
.setSingleChoiceItems(arrayAdapter, 0, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
AlertDialog alertDialog = (AlertDialog) dialog;
|
||||
DisplayInfo displayInfo = (DisplayInfo) alertDialog.getListView()
|
||||
.getItemAtPosition(which);
|
||||
ActivityInfo activityInfo = displayInfo.resolveInfo.activityInfo;
|
||||
String packageName = activityInfo.applicationInfo.packageName;
|
||||
String className = activityInfo.name;
|
||||
|
||||
long trackId = getArguments().getLong(KEY_TRACK_ID);
|
||||
String trackUrl = getArguments().getString(KEY_TRACK_URL);
|
||||
if (trackUrl == null) {
|
||||
SendRequest sendRequest = new SendRequest(trackId);
|
||||
sendRequest.setSendMaps(true);
|
||||
sendRequest.setNewMap(true);
|
||||
sendRequest.setSharingAppPackageName(packageName);
|
||||
sendRequest.setSharingAppClassName(className);
|
||||
Intent intent = IntentUtils.newIntent(getActivity(), ConfirmSharingActivity.class)
|
||||
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
|
||||
startActivity(intent);
|
||||
dismiss();
|
||||
} else {
|
||||
Intent intent = IntentUtils.newShareUrlIntent(
|
||||
getActivity(), trackId, trackUrl, packageName, className);
|
||||
startActivity(intent);
|
||||
getActivity().finish();
|
||||
}
|
||||
}
|
||||
})
|
||||
.setTitle(R.string.share_track_picker_title)
|
||||
.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display info.
|
||||
*/
|
||||
private List<DisplayInfo> getDisplayInfos() {
|
||||
List<DisplayInfo> displayInfos = new ArrayList<DisplayInfo>();
|
||||
Intent intent = ShareCompat.IntentBuilder.from(getActivity())
|
||||
.setType(IntentUtils.TEXT_PLAIN_TYPE).getIntent();
|
||||
List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(
|
||||
intent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||
if (resolveInfos != null && resolveInfos.size() > 0) {
|
||||
int size = resolveInfos.size();
|
||||
ResolveInfo firstResolveInfo = resolveInfos.get(0);
|
||||
for (int i = 1; i < size; i++) {
|
||||
ResolveInfo resolveInfo = resolveInfos.get(i);
|
||||
if (firstResolveInfo.priority != resolveInfo.priority
|
||||
|| firstResolveInfo.isDefault != resolveInfo.isDefault) {
|
||||
while (i < size) {
|
||||
resolveInfos.remove(i);
|
||||
size--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (size > 1) {
|
||||
ResolveInfo.DisplayNameComparator displayNameComparator = new ResolveInfo.DisplayNameComparator(
|
||||
packageManager);
|
||||
Collections.sort(resolveInfos, displayNameComparator);
|
||||
}
|
||||
|
||||
firstResolveInfo = resolveInfos.get(0);
|
||||
int start = 0;
|
||||
CharSequence firstLabel = firstResolveInfo.loadLabel(packageManager);
|
||||
for (int i = 1; i < size; i++) {
|
||||
if (firstLabel == null) {
|
||||
firstLabel = firstResolveInfo.activityInfo.packageName;
|
||||
}
|
||||
ResolveInfo resolveInfo = resolveInfos.get(i);
|
||||
CharSequence label = resolveInfo.loadLabel(packageManager);
|
||||
if (label == null) {
|
||||
label = resolveInfo.activityInfo.packageName;
|
||||
}
|
||||
if (label.equals(firstLabel)) {
|
||||
continue;
|
||||
}
|
||||
processGroup(resolveInfos, displayInfos, start, i - 1);
|
||||
firstResolveInfo = resolveInfo;
|
||||
firstLabel = label;
|
||||
start = i;
|
||||
}
|
||||
// Process last group
|
||||
processGroup(resolveInfos, displayInfos, start, size - 1);
|
||||
}
|
||||
return displayInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains display info.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
private final class DisplayInfo {
|
||||
private ResolveInfo resolveInfo;
|
||||
private CharSequence primaryLabel;
|
||||
private CharSequence secondaryLabel;
|
||||
private Drawable icon;
|
||||
|
||||
public DisplayInfo(ResolveInfo resolveInfo, CharSequence primaryLabel,
|
||||
CharSequence secondaryLabel, Drawable icon) {
|
||||
this.resolveInfo = resolveInfo;
|
||||
this.primaryLabel = primaryLabel;
|
||||
this.secondaryLabel = secondaryLabel;
|
||||
this.icon = icon;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a group of items with the same label.
|
||||
*
|
||||
* @param resolveInfos list of resolve infos
|
||||
* @param displayInfos list of display infos
|
||||
* @param start start index
|
||||
* @param end end index
|
||||
*/
|
||||
private void processGroup(
|
||||
List<ResolveInfo> resolveInfos, List<DisplayInfo> displayInfos, int start, int end) {
|
||||
ResolveInfo startResolveInfo = resolveInfos.get(start);
|
||||
CharSequence primaryLabel = startResolveInfo.loadLabel(packageManager);
|
||||
Drawable icon = startResolveInfo.loadIcon(packageManager);
|
||||
|
||||
int num = end - start + 1;
|
||||
if (num == 1) {
|
||||
// Only one, set the secondary label to null
|
||||
displayInfos.add(new DisplayInfo(startResolveInfo, primaryLabel, null, icon));
|
||||
} else {
|
||||
// Decide package name or application name for the secondary label
|
||||
boolean usePackageName = false;
|
||||
CharSequence appName = startResolveInfo.activityInfo.applicationInfo.loadLabel(
|
||||
packageManager);
|
||||
if (appName == null) {
|
||||
usePackageName = true;
|
||||
} else {
|
||||
// Use HashSet to track duplicates
|
||||
HashSet<CharSequence> duplicates = new HashSet<CharSequence>();
|
||||
duplicates.add(appName);
|
||||
for (int i = start + 1; i <= end; i++) {
|
||||
ResolveInfo resolveInfo = resolveInfos.get(i);
|
||||
CharSequence name = resolveInfo.activityInfo.applicationInfo.loadLabel(packageManager);
|
||||
if ((name == null) || (duplicates.contains(name))) {
|
||||
usePackageName = true;
|
||||
break;
|
||||
} else {
|
||||
duplicates.add(name);
|
||||
}
|
||||
}
|
||||
// Clear HashSet for later use
|
||||
duplicates.clear();
|
||||
}
|
||||
for (int i = start; i <= end; i++) {
|
||||
ResolveInfo resolveInfo = resolveInfos.get(i);
|
||||
CharSequence secondaryLabel = usePackageName ? resolveInfo.activityInfo.packageName
|
||||
: resolveInfo.activityInfo.applicationInfo.loadLabel(packageManager);
|
||||
displayInfos.add(new DisplayInfo(resolveInfo, primaryLabel, secondaryLabel, icon));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.io.sendtogoogle.AccountChooserActivity;
|
||||
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
|
||||
import com.google.android.apps.mytracks.util.AnalyticsUtils;
|
||||
import com.google.android.apps.mytracks.util.IntentUtils;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.TableRow;
|
||||
import android.widget.Toast;
|
||||
|
||||
/**
|
||||
* A DialogFragment to choose upload service.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class ChooseUploadServiceDialogFragment extends DialogFragment {
|
||||
|
||||
public static final String CHOOSE_UPLOAD_SERVICE_DIALOG_TAG = "chooseUploadService";
|
||||
|
||||
private static final String KEY_SEND_REQUEST = "sendRequest";
|
||||
|
||||
public static ChooseUploadServiceDialogFragment newInstance(SendRequest sendRequest) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(KEY_SEND_REQUEST, sendRequest);
|
||||
|
||||
ChooseUploadServiceDialogFragment chooseUploadServiceDialogFragment =
|
||||
new ChooseUploadServiceDialogFragment();
|
||||
chooseUploadServiceDialogFragment.setArguments(bundle);
|
||||
return chooseUploadServiceDialogFragment;
|
||||
}
|
||||
|
||||
private SendRequest sendRequest;
|
||||
|
||||
private CheckBox mapsCheckBox;
|
||||
private CheckBox fusionTablesCheckBox;
|
||||
private CheckBox docsCheckBox;
|
||||
|
||||
private TableRow mapsOptionTableRow;
|
||||
private RadioButton existingMapRadioButton;
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
sendRequest = getArguments().getParcelable(KEY_SEND_REQUEST);
|
||||
View view = getActivity().getLayoutInflater().inflate(R.layout.choose_upload_service, null);
|
||||
|
||||
mapsCheckBox = (CheckBox) view.findViewById(R.id.choose_upload_service_maps);
|
||||
fusionTablesCheckBox = (CheckBox) view.findViewById(R.id.choose_upload_service_fusion_tables);
|
||||
docsCheckBox = (CheckBox) view.findViewById(R.id.choose_upload_service_docs);
|
||||
|
||||
mapsCheckBox.setChecked(PreferencesUtils.getBoolean(
|
||||
getActivity(), R.string.send_to_maps_key, PreferencesUtils.SEND_TO_MAPS_DEFAULT));
|
||||
fusionTablesCheckBox.setChecked(PreferencesUtils.getBoolean(
|
||||
getActivity(), R.string.send_to_fusion_tables_key,
|
||||
PreferencesUtils.SEND_TO_FUSION_TABLES_DEFAULT));
|
||||
docsCheckBox.setChecked(PreferencesUtils.getBoolean(
|
||||
getActivity(), R.string.send_to_docs_key, PreferencesUtils.SEND_TO_DOCS_DEFAULT));
|
||||
|
||||
mapsCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
|
||||
public void onCheckedChanged(CompoundButton button, boolean checked) {
|
||||
updateMapsOption();
|
||||
}
|
||||
});
|
||||
|
||||
mapsOptionTableRow = (TableRow) view.findViewById(R.id.choose_upload_service_maps_options);
|
||||
|
||||
RadioButton newMapRadioButton = (RadioButton) view.findViewById(
|
||||
R.id.choose_upload_service_new_map);
|
||||
boolean defaultMapPublic = PreferencesUtils.getBoolean(getActivity(),
|
||||
R.string.default_map_public_key, PreferencesUtils.DEFAULT_MAP_PUBLIC_DEFAULT);
|
||||
newMapRadioButton.setText(defaultMapPublic ? R.string.send_google_new_public_map
|
||||
: R.string.send_google_new_unlisted_map);
|
||||
|
||||
existingMapRadioButton = (RadioButton) view.findViewById(
|
||||
R.id.choose_upload_service_existing_map);
|
||||
|
||||
updateMapsOption();
|
||||
if (PreferencesUtils.getBoolean(getActivity(), R.string.pick_existing_map_key,
|
||||
PreferencesUtils.PICK_EXISTING_MAP_DEFAULT)) {
|
||||
existingMapRadioButton.setChecked(true);
|
||||
} else {
|
||||
newMapRadioButton.setChecked(true);
|
||||
}
|
||||
|
||||
return new AlertDialog.Builder(getActivity()).setNegativeButton(R.string.generic_cancel, null)
|
||||
.setPositiveButton(R.string.send_google_send_now, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
PreferencesUtils.setBoolean(
|
||||
getActivity(), R.string.pick_existing_map_key, existingMapRadioButton.isChecked());
|
||||
PreferencesUtils.setBoolean(
|
||||
getActivity(), R.string.send_to_maps_key, mapsCheckBox.isChecked());
|
||||
PreferencesUtils.setBoolean(getActivity(), R.string.send_to_fusion_tables_key,
|
||||
fusionTablesCheckBox.isChecked());
|
||||
PreferencesUtils.setBoolean(
|
||||
getActivity(), R.string.send_to_docs_key, docsCheckBox.isChecked());
|
||||
if (mapsCheckBox.isChecked() || fusionTablesCheckBox.isChecked()
|
||||
|| docsCheckBox.isChecked()) {
|
||||
startNextActivity();
|
||||
} else {
|
||||
Toast.makeText(
|
||||
getActivity(), R.string.send_google_no_service_selected, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
})
|
||||
.setTitle(R.string.send_google_title)
|
||||
.setView(view)
|
||||
.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates map option.
|
||||
*/
|
||||
private void updateMapsOption() {
|
||||
mapsOptionTableRow.setVisibility(mapsCheckBox.isChecked() ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the next activity, {@link AccountChooserActivity}.
|
||||
*/
|
||||
private void startNextActivity() {
|
||||
sendRequest.setSendMaps(mapsCheckBox.isChecked());
|
||||
sendRequest.setSendFusionTables(fusionTablesCheckBox.isChecked());
|
||||
sendRequest.setSendDocs(docsCheckBox.isChecked());
|
||||
sendRequest.setNewMap(!existingMapRadioButton.isChecked());
|
||||
sendStats();
|
||||
Intent intent = IntentUtils.newIntent(getActivity(), AccountChooserActivity.class)
|
||||
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends stats to Google Analytics.
|
||||
*/
|
||||
private void sendStats() {
|
||||
if (sendRequest.isSendMaps()) {
|
||||
AnalyticsUtils.sendPageViews(getActivity(), "/send/maps");
|
||||
}
|
||||
if (sendRequest.isSendFusionTables()) {
|
||||
AnalyticsUtils.sendPageViews(getActivity(), "/send/fusion_tables");
|
||||
}
|
||||
if (sendRequest.isSendDocs()) {
|
||||
AnalyticsUtils.sendPageViews(getActivity(), "/send/docs");
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.util.DialogUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
|
||||
/**
|
||||
* A DialogFragment to delete all tracks.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class DeleteAllTrackDialogFragment extends DialogFragment {
|
||||
|
||||
public static final String DELETE_ALL_TRACK_DIALOG_TAG = "deleteAllTrackDialog";
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
return DialogUtils.createConfirmationDialog(getActivity(),
|
||||
R.string.track_list_delete_all_confirm_message, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MyTracksProviderUtils.Factory.get(getActivity()).deleteAllTracks();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.MarkerListActivity;
|
||||
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.util.DialogUtils;
|
||||
import com.google.android.apps.mytracks.util.IntentUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
|
||||
/**
|
||||
* A DialogFragment to delete one marker.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class DeleteOneMarkerDialogFragment extends DialogFragment {
|
||||
|
||||
public static final String DELETE_ONE_MARKER_DIALOG_TAG = "deleteOneMarkerDialog";
|
||||
private static final String KEY_MARKER_ID = "markerId";
|
||||
private static final String KEY_TRACK_ID = "trackId";
|
||||
|
||||
public static DeleteOneMarkerDialogFragment newInstance(long markerId, long trackId) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putLong(KEY_MARKER_ID, markerId);
|
||||
bundle.putLong(KEY_TRACK_ID, trackId);
|
||||
|
||||
DeleteOneMarkerDialogFragment deleteOneMarkerDialogFragment = new DeleteOneMarkerDialogFragment();
|
||||
deleteOneMarkerDialogFragment.setArguments(bundle);
|
||||
return deleteOneMarkerDialogFragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
return DialogUtils.createConfirmationDialog(getActivity(),
|
||||
R.string.marker_delete_one_marker_confirm_message, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MyTracksProviderUtils.Factory.get(getActivity()).deleteWaypoint(
|
||||
getArguments().getLong(KEY_MARKER_ID),
|
||||
new DescriptionGeneratorImpl(getActivity()));
|
||||
}
|
||||
}).start();
|
||||
Intent intent = IntentUtils.newIntent(getActivity(), MarkerListActivity.class)
|
||||
.putExtra(MarkerListActivity.EXTRA_TRACK_ID, getArguments().getLong(KEY_TRACK_ID));
|
||||
startActivity(intent);
|
||||
// Close the activity since its content can change after delete.
|
||||
getActivity().finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.TrackListActivity;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||
import com.google.android.apps.mytracks.util.DialogUtils;
|
||||
import com.google.android.apps.mytracks.util.IntentUtils;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
|
||||
/**
|
||||
* A DialogFragment to delete one track.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class DeleteOneTrackDialogFragment extends DialogFragment {
|
||||
|
||||
public static final String DELETE_ONE_TRACK_DIALOG_TAG = "deleteOneTrackDialog";
|
||||
private static final String KEY_TRACK_ID = "trackId";
|
||||
|
||||
/**
|
||||
* Interface for caller of this dialog fragment.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public interface DeleteOneTrackCaller {
|
||||
public TrackRecordingServiceConnection getTrackRecordingServiceConnection();
|
||||
}
|
||||
|
||||
private DeleteOneTrackCaller caller;
|
||||
|
||||
public static DeleteOneTrackDialogFragment newInstance(long trackId) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putLong(KEY_TRACK_ID, trackId);
|
||||
|
||||
DeleteOneTrackDialogFragment deleteOneTrackDialogFragment = new DeleteOneTrackDialogFragment();
|
||||
deleteOneTrackDialogFragment.setArguments(bundle);
|
||||
return deleteOneTrackDialogFragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
try {
|
||||
caller = (DeleteOneTrackCaller) activity;
|
||||
} catch (ClassCastException e) {
|
||||
throw new ClassCastException(activity.toString() + " must implement DeleteOneTrackCaller");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
return DialogUtils.createConfirmationDialog(getActivity(),
|
||||
R.string.track_detail_delete_confirm_message, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
final long trackId = getArguments().getLong(KEY_TRACK_ID);
|
||||
final Context context = getActivity();
|
||||
if (trackId == PreferencesUtils.getLong(context, R.string.recording_track_id_key)) {
|
||||
TrackRecordingServiceConnectionUtils.stopRecording(
|
||||
context, caller.getTrackRecordingServiceConnection(), false);
|
||||
}
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MyTracksProviderUtils.Factory.get(context).deleteTrack(trackId);
|
||||
}
|
||||
}).start();
|
||||
Intent intent = IntentUtils.newIntent(context, TrackListActivity.class);
|
||||
startActivity(intent);
|
||||
// Close the activity since its content can change after delete
|
||||
getActivity().finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.TrackListActivity;
|
||||
import com.google.android.apps.mytracks.util.EulaUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
|
||||
/**
|
||||
* A DialogFragment to show EULA.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class EulaDialogFragment extends DialogFragment {
|
||||
|
||||
public static final String EULA_DIALOG_TAG = "eulaDialog";
|
||||
private static final String KEY_HAS_ACCEPTED = "hasAccepted";
|
||||
private static final String GOOGLE_URL = "m.google.com";
|
||||
private static final String KOREAN = "ko";
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link EulaDialogFragment}.
|
||||
*
|
||||
* @param hasAccepted true if the user has accepted the eula.
|
||||
*/
|
||||
public static EulaDialogFragment newInstance(boolean hasAccepted) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putBoolean(KEY_HAS_ACCEPTED, hasAccepted);
|
||||
|
||||
EulaDialogFragment eulaDialogFragment = new EulaDialogFragment();
|
||||
eulaDialogFragment.setArguments(bundle);
|
||||
return eulaDialogFragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel(DialogInterface arg0) {
|
||||
if (!getArguments().getBoolean(KEY_HAS_ACCEPTED)) {
|
||||
exitApp();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
boolean hasAccepted = getArguments().getBoolean(KEY_HAS_ACCEPTED);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
|
||||
.setMessage(getEulaText())
|
||||
.setTitle(R.string.eula_title);
|
||||
|
||||
if (hasAccepted) {
|
||||
builder.setPositiveButton(R.string.generic_ok, null);
|
||||
} else {
|
||||
builder.setNegativeButton(R.string.eula_decline, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
exitApp();
|
||||
}
|
||||
})
|
||||
.setPositiveButton(R.string.eula_accept, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
EulaUtils.setAcceptEula(getActivity());
|
||||
TrackListActivity trackListActivity = (TrackListActivity) getActivity();
|
||||
trackListActivity.showStartupDialogs();
|
||||
}
|
||||
});
|
||||
}
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Exits the application.
|
||||
*/
|
||||
private void exitApp() {
|
||||
getActivity().finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the EULA text.
|
||||
*
|
||||
*/
|
||||
private String getEulaText() {
|
||||
String tos = getString(R.string.eula_date)
|
||||
+ "\n\n"
|
||||
+ getString(R.string.eula_body, GOOGLE_URL)
|
||||
+ "\n\n"
|
||||
+ getString(R.string.eula_footer, GOOGLE_URL)
|
||||
+ "\n\n"
|
||||
+ getString(R.string.eula_copyright_year);
|
||||
boolean isKorean = getResources().getConfiguration().locale.getLanguage().equals(KOREAN);
|
||||
if (isKorean) {
|
||||
tos += "\n\n" + getString(R.string.eula_korean);
|
||||
}
|
||||
return tos;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
|
||||
/**
|
||||
* A DialogFragment to configure frequency.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class FrequencyDialogFragment extends DialogFragment {
|
||||
|
||||
public static final String FREQUENCY_DIALOG_TAG = "frequencyDialog";
|
||||
|
||||
private static final String KEY_PREFERENCE_ID = "preferenceId";
|
||||
private static final String KEY_DEFAULT_VALUE = "defaultValue";
|
||||
private static final String KEY_TITLE_ID = "titleId";
|
||||
|
||||
public static FrequencyDialogFragment newInstance(
|
||||
int preferenceId, int defaultValue, int titleId) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(KEY_PREFERENCE_ID, preferenceId);
|
||||
bundle.putInt(KEY_DEFAULT_VALUE, defaultValue);
|
||||
bundle.putInt(KEY_TITLE_ID, titleId);
|
||||
|
||||
FrequencyDialogFragment frequencyDialogFragment = new FrequencyDialogFragment();
|
||||
frequencyDialogFragment.setArguments(bundle);
|
||||
return frequencyDialogFragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final int preferenceId = getArguments().getInt(KEY_PREFERENCE_ID);
|
||||
int defaultValue = getArguments().getInt(KEY_DEFAULT_VALUE);
|
||||
int titleId = getArguments().getInt(KEY_TITLE_ID);
|
||||
int frequencyValue = PreferencesUtils.getInt(getActivity(), preferenceId, defaultValue);
|
||||
|
||||
return new AlertDialog.Builder(getActivity())
|
||||
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
int listIndex = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||
PreferencesUtils.setInt(getActivity(), preferenceId, getFrequencyValue(listIndex));
|
||||
}
|
||||
})
|
||||
.setSingleChoiceItems(getFrequencyDisplayOptions(), getListIndex(frequencyValue), null)
|
||||
.setTitle(titleId)
|
||||
.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the frequency display options.
|
||||
*/
|
||||
private String[] getFrequencyDisplayOptions() {
|
||||
boolean metricUnits = PreferencesUtils.getBoolean(
|
||||
getActivity(), R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
|
||||
String[] values = getResources().getStringArray(R.array.frequency_values);
|
||||
String[] options = new String[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
int value = Integer.parseInt(values[i]);
|
||||
if (value == PreferencesUtils.FREQUENCY_OFF) {
|
||||
options[i] = getString(R.string.value_off);
|
||||
} else if (value < 0) {
|
||||
options[i] = getString(metricUnits ? R.string.value_integer_kilometer
|
||||
: R.string.value_integer_mile, Math.abs(value));
|
||||
} else {
|
||||
options[i] = getString(R.string.value_integer_minute, value);
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list index for a frequency value. Returns 0 if the value is not on
|
||||
* the list.
|
||||
*/
|
||||
private int getListIndex(int frequencyValue) {
|
||||
String[] values = getResources().getStringArray(R.array.frequency_values);
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (frequencyValue == Integer.parseInt(values[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the frequency value from a list index.
|
||||
*
|
||||
* @param listIndex the list index
|
||||
*/
|
||||
private int getFrequencyValue(int listIndex) {
|
||||
String[] values = getResources().getStringArray(R.array.frequency_values);
|
||||
return Integer.parseInt(values[listIndex]);
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.io.file.SaveActivity;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.widget.Toast;
|
||||
|
||||
/**
|
||||
* A DialogFragment to install Google Earth.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class InstallEarthDialogFragment extends DialogFragment {
|
||||
|
||||
public static final String INSTALL_EARTH_DIALOG_TAG = "installEarthDialog";
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
return new AlertDialog.Builder(getActivity())
|
||||
.setMessage(R.string.track_detail_install_earth_message)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Intent intent = new Intent().setData(Uri.parse(SaveActivity.GOOGLE_EARTH_MARKET_URL));
|
||||
try {
|
||||
startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(
|
||||
getActivity(), R.string.track_detail_install_earth_error, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.MapOverlay;
|
||||
import com.google.android.apps.mytracks.TrackDetailActivity;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub;
|
||||
import com.google.android.apps.mytracks.content.TrackDataListener;
|
||||
import com.google.android.apps.mytracks.content.TrackDataType;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||
import com.google.android.apps.mytracks.util.GeoRect;
|
||||
import com.google.android.apps.mytracks.util.GoogleLocationUtils;
|
||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||
import com.google.android.maps.GeoPoint;
|
||||
import com.google.android.maps.MapController;
|
||||
import com.google.android.maps.MapView;
|
||||
import com.google.android.maps.Overlay;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A fragment to display map to the user.
|
||||
*
|
||||
* @author Leif Hendrik Wilden
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class MapFragment extends Fragment
|
||||
implements View.OnTouchListener, View.OnClickListener, TrackDataListener {
|
||||
|
||||
public static final String MAP_FRAGMENT_TAG = "mapFragment";
|
||||
|
||||
private static final String KEY_CURRENT_LOCATION = "currentLocation";
|
||||
private static final String KEY_KEEP_MY_LOCATION_VISIBLE = "keepMyLocationVisible";
|
||||
|
||||
private TrackDataHub trackDataHub;
|
||||
|
||||
// True to keep my location visible.
|
||||
private boolean keepMyLocationVisible;
|
||||
|
||||
// True to zoom to my location. Only apply when keepMyLocationVisible is true.
|
||||
private boolean zoomToMyLocation;
|
||||
|
||||
// The track id of the marker to show.
|
||||
private long markerTrackId;
|
||||
|
||||
// The marker id to show
|
||||
private long markerId;
|
||||
|
||||
// The current selected track id. Set in onSelectedTrackChanged.
|
||||
private long currentSelectedTrackId;
|
||||
|
||||
// The current location. Set in onCurrentLocationChanged.
|
||||
private Location currentLocation;
|
||||
|
||||
// UI elements
|
||||
private View mapViewContainer;
|
||||
private MapView mapView;
|
||||
private MapOverlay mapOverlay;
|
||||
private ImageButton myLocationImageButton;
|
||||
private TextView messageTextView;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(
|
||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
mapViewContainer = ((TrackDetailActivity) getActivity()).getMapViewContainer();
|
||||
mapView = (MapView) mapViewContainer.findViewById(R.id.map_view);
|
||||
mapOverlay = new MapOverlay(getActivity());
|
||||
|
||||
List<Overlay> overlays = mapView.getOverlays();
|
||||
overlays.clear();
|
||||
overlays.add(mapOverlay);
|
||||
|
||||
mapView.requestFocus();
|
||||
mapView.setOnTouchListener(this);
|
||||
mapView.setBuiltInZoomControls(true);
|
||||
myLocationImageButton = (ImageButton) mapViewContainer.findViewById(R.id.map_my_location);
|
||||
myLocationImageButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showMyLocation();
|
||||
}
|
||||
});
|
||||
messageTextView = (TextView) mapViewContainer.findViewById(R.id.map_message);
|
||||
|
||||
ApiAdapterFactory.getApiAdapter().invalidMenu(getActivity());
|
||||
return mapViewContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
if (savedInstanceState != null) {
|
||||
keepMyLocationVisible = savedInstanceState.getBoolean(KEY_KEEP_MY_LOCATION_VISIBLE, false);
|
||||
currentLocation = (Location) savedInstanceState.getParcelable(KEY_CURRENT_LOCATION);
|
||||
if (currentLocation != null) {
|
||||
updateCurrentLocation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
resumeTrackDataHub();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putBoolean(KEY_KEEP_MY_LOCATION_VISIBLE, keepMyLocationVisible);
|
||||
if (currentLocation != null) {
|
||||
outState.putParcelable(KEY_CURRENT_LOCATION, currentLocation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
pauseTrackDataHub();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
ViewGroup parentViewGroup = (ViewGroup) mapViewContainer.getParent();
|
||||
if (parentViewGroup != null) {
|
||||
parentViewGroup.removeView(mapViewContainer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflator) {
|
||||
menuInflator.inflate(R.menu.map, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
int titleId = R.string.menu_satellite_mode;
|
||||
if (mapView != null) {
|
||||
titleId = mapView.isSatellite() ? R.string.menu_map_mode : R.string.menu_satellite_mode;
|
||||
}
|
||||
menu.findItem(R.id.map_satellite_mode).setTitle(titleId);
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem menuItem) {
|
||||
if (mapView != null && menuItem.getItemId() == R.id.map_satellite_mode) {
|
||||
mapView.setSatellite(!mapView.isSatellite());
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(menuItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows my location.
|
||||
*/
|
||||
private void showMyLocation() {
|
||||
updateTrackDataHub();
|
||||
keepMyLocationVisible = true;
|
||||
zoomToMyLocation = true;
|
||||
if (currentLocation != null) {
|
||||
updateCurrentLocation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the marker.
|
||||
*
|
||||
* @param id the marker id
|
||||
*/
|
||||
private void showMarker(long id) {
|
||||
MyTracksProviderUtils MyTracksProviderUtils = Factory.get(getActivity());
|
||||
Waypoint waypoint = MyTracksProviderUtils.getWaypoint(id);
|
||||
if (waypoint != null && waypoint.getLocation() != null) {
|
||||
keepMyLocationVisible = false;
|
||||
GeoPoint center = new GeoPoint((int) (waypoint.getLocation().getLatitude() * 1E6),
|
||||
(int) (waypoint.getLocation().getLongitude() * 1E6));
|
||||
mapView.getController().setCenter(center);
|
||||
mapView.getController().setZoom(mapView.getMaxZoomLevel());
|
||||
mapView.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the marker.
|
||||
*
|
||||
* @param trackId the track id
|
||||
* @param id the marker id
|
||||
*/
|
||||
public void showMarker(long trackId, long id) {
|
||||
/*
|
||||
* Synchronize to prevent race condition in changing markerTrackId and
|
||||
* markerId variables.
|
||||
*/
|
||||
synchronized (this) {
|
||||
if (trackId == currentSelectedTrackId) {
|
||||
showMarker(id);
|
||||
markerTrackId = -1L;
|
||||
markerId = -1L;
|
||||
return;
|
||||
}
|
||||
markerTrackId = trackId;
|
||||
markerId = id;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent event) {
|
||||
if (keepMyLocationVisible && event.getAction() == MotionEvent.ACTION_MOVE) {
|
||||
if (!isVisible(currentLocation)) {
|
||||
/*
|
||||
* Only set to false when no longer visible. Thus can keep showing the
|
||||
* current location with the next location update.
|
||||
*/
|
||||
keepMyLocationVisible = false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (v == messageTextView) {
|
||||
Intent intent = GoogleLocationUtils.isAvailable(getActivity()) ? new Intent(
|
||||
GoogleLocationUtils.ACTION_GOOGLE_LOCATION_SETTINGS)
|
||||
: new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationStateChanged(LocationState state) {
|
||||
final String message;
|
||||
final boolean isGpsDisabled;
|
||||
if (!isSelectedTrackRecording()) {
|
||||
message = null;
|
||||
isGpsDisabled = false;
|
||||
} else {
|
||||
switch (state) {
|
||||
case DISABLED:
|
||||
String setting = getString(
|
||||
GoogleLocationUtils.isAvailable(getActivity()) ? R.string.gps_google_location_settings
|
||||
: R.string.gps_location_access);
|
||||
message = getString(R.string.gps_disabled, setting);
|
||||
isGpsDisabled = true;
|
||||
break;
|
||||
case NO_FIX:
|
||||
message = getString(R.string.gps_wait_for_signal);
|
||||
isGpsDisabled = false;
|
||||
break;
|
||||
case BAD_FIX:
|
||||
message = getString(R.string.gps_wait_for_better_signal);
|
||||
isGpsDisabled = false;
|
||||
break;
|
||||
case GOOD_FIX:
|
||||
message = null;
|
||||
isGpsDisabled = false;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unexpected state: " + state);
|
||||
}
|
||||
}
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (message != null) {
|
||||
messageTextView.setText(message);
|
||||
messageTextView.setVisibility(View.VISIBLE);
|
||||
|
||||
if (isGpsDisabled) {
|
||||
Toast.makeText(getActivity(), R.string.gps_not_found, Toast.LENGTH_LONG).show();
|
||||
|
||||
// Click to show the location source settings
|
||||
messageTextView.setOnClickListener(MapFragment.this);
|
||||
} else {
|
||||
messageTextView.setOnClickListener(null);
|
||||
}
|
||||
} else {
|
||||
messageTextView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(Location location) {
|
||||
currentLocation = location;
|
||||
updateCurrentLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHeadingChanged(double heading) {
|
||||
if (mapOverlay.setHeading((float) heading)) {
|
||||
mapView.postInvalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectedTrackChanged(final Track track) {
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
boolean hasTrack = track != null;
|
||||
mapOverlay.setTrackDrawingEnabled(hasTrack);
|
||||
|
||||
if (hasTrack) {
|
||||
synchronized (this) {
|
||||
/*
|
||||
* Synchronize to prevent race condition in changing markerTrackId
|
||||
* and markerId variables.
|
||||
*/
|
||||
currentSelectedTrackId = track.getId();
|
||||
updateMap(track);
|
||||
}
|
||||
mapOverlay.setShowEndMarker(!isSelectedTrackRecording());
|
||||
}
|
||||
mapView.invalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackUpdated(Track track) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTrackPoints() {
|
||||
mapOverlay.clearPoints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSampledInTrackPoint(Location location) {
|
||||
mapOverlay.addLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSampledOutTrackPoint(Location location) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSegmentSplit(Location location) {
|
||||
mapOverlay.addSegmentSplit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewTrackPointsDone() {
|
||||
mapView.postInvalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWaypoints() {
|
||||
mapOverlay.clearWaypoints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewWaypoint(Waypoint waypoint) {
|
||||
if (waypoint != null && LocationUtils.isValidLocation(waypoint.getLocation())) {
|
||||
// TODO: Optimize locking inside addWaypoint
|
||||
mapOverlay.addWaypoint(waypoint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewWaypointsDone() {
|
||||
mapView.postInvalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMetricUnitsChanged(boolean metric) {
|
||||
// We don't care.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onReportSpeedChanged(boolean reportSpeed) {
|
||||
// We don't care.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMinRecordingDistanceChanged(int minRecordingDistance) {
|
||||
// We don't care.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the trackDataHub. Needs to be synchronized because trackDataHub can
|
||||
* be accessed by multiple threads.
|
||||
*/
|
||||
private synchronized void resumeTrackDataHub() {
|
||||
trackDataHub = ((TrackDetailActivity) getActivity()).getTrackDataHub();
|
||||
trackDataHub.registerTrackDataListener(this, EnumSet.of(TrackDataType.SELECTED_TRACK,
|
||||
TrackDataType.WAYPOINTS_TABLE, TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE,
|
||||
TrackDataType.LOCATION, TrackDataType.HEADING));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the trackDataHub. Needs to be synchronized because trackDataHub can
|
||||
* be accessed by multiple threads.
|
||||
*/
|
||||
private synchronized void pauseTrackDataHub() {
|
||||
trackDataHub.unregisterTrackDataListener(this);
|
||||
trackDataHub = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the trackDataHub. Needs to be synchronized because trackDataHub can
|
||||
* be accessed by multiple threads.
|
||||
*/
|
||||
private synchronized void updateTrackDataHub() {
|
||||
if (trackDataHub != null) {
|
||||
trackDataHub.forceUpdateLocation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the selected track is recording. Needs to be synchronized
|
||||
* because trackDataHub can be accessed by multiple threads.
|
||||
*/
|
||||
private synchronized boolean isSelectedTrackRecording() {
|
||||
return trackDataHub != null && trackDataHub.isSelectedTrackRecording();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the map by either zooming to the requested marker or showing the
|
||||
* track.
|
||||
*
|
||||
* @param track the track
|
||||
*/
|
||||
private void updateMap(Track track) {
|
||||
if (track.getId() == markerTrackId) {
|
||||
// Show the marker
|
||||
showMarker(markerId);
|
||||
|
||||
markerTrackId = -1L;
|
||||
markerId = -1L;
|
||||
} else {
|
||||
// Show the track
|
||||
showTrack(track);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the location is visible.
|
||||
*
|
||||
* @param location the location
|
||||
*/
|
||||
private boolean isVisible(Location location) {
|
||||
if (location == null || mapView == null) {
|
||||
return false;
|
||||
}
|
||||
GeoPoint mapCenter = mapView.getMapCenter();
|
||||
int latitudeSpan = mapView.getLatitudeSpan();
|
||||
int longitudeSpan = mapView.getLongitudeSpan();
|
||||
|
||||
/*
|
||||
* The bottom of the mapView is obscured by the zoom controls, subtract its
|
||||
* height from the visible area.
|
||||
*/
|
||||
GeoPoint zoomControlBottom = mapView.getProjection().fromPixels(0, mapView.getHeight());
|
||||
GeoPoint zoomControlTop = mapView.getProjection().fromPixels(
|
||||
0, mapView.getHeight() - mapView.getZoomButtonsController().getZoomControls().getHeight());
|
||||
int zoomControlMargin = Math.abs(
|
||||
zoomControlTop.getLatitudeE6() - zoomControlBottom.getLatitudeE6());
|
||||
GeoRect geoRect = new GeoRect(mapCenter, latitudeSpan, longitudeSpan);
|
||||
geoRect.top += zoomControlMargin;
|
||||
|
||||
GeoPoint geoPoint = LocationUtils.getGeoPoint(location);
|
||||
return geoRect.contains(geoPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current location and centers it if necessary.
|
||||
*/
|
||||
private void updateCurrentLocation() {
|
||||
if (mapOverlay == null || mapView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mapOverlay.setMyLocation(currentLocation);
|
||||
mapView.postInvalidate();
|
||||
|
||||
if (currentLocation != null && keepMyLocationVisible && !isVisible(currentLocation)) {
|
||||
GeoPoint geoPoint = LocationUtils.getGeoPoint(currentLocation);
|
||||
MapController mapController = mapView.getController();
|
||||
mapController.animateTo(geoPoint);
|
||||
if (zoomToMyLocation) {
|
||||
// Only zoom in the first time we show the location.
|
||||
zoomToMyLocation = false;
|
||||
if (mapView.getZoomLevel() < mapView.getMaxZoomLevel()) {
|
||||
mapController.setZoom(mapView.getMaxZoomLevel());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the track.
|
||||
*
|
||||
* @param track the track
|
||||
*/
|
||||
private void showTrack(Track track) {
|
||||
if (mapView == null || track == null || track.getNumberOfPoints() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
TripStatistics tripStatistics = track.getTripStatistics();
|
||||
int bottom = tripStatistics.getBottom();
|
||||
int left = tripStatistics.getLeft();
|
||||
int latitudeSpanE6 = tripStatistics.getTop() - bottom;
|
||||
int longitudeSpanE6 = tripStatistics.getRight() - left;
|
||||
if (latitudeSpanE6 > 0 && latitudeSpanE6 < 180E6 && longitudeSpanE6 > 0
|
||||
&& longitudeSpanE6 < 360E6) {
|
||||
keepMyLocationVisible = false;
|
||||
GeoPoint center = new GeoPoint(bottom + latitudeSpanE6 / 2, left + longitudeSpanE6 / 2);
|
||||
if (LocationUtils.isValidGeoPoint(center)) {
|
||||
mapView.getController().setCenter(center);
|
||||
mapView.getController().zoomToSpan(latitudeSpanE6, longitudeSpanE6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.TrackDetailActivity;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TrackDataHub;
|
||||
import com.google.android.apps.mytracks.content.TrackDataListener;
|
||||
import com.google.android.apps.mytracks.content.TrackDataType;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.StatsUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* A fragment to display track statistics to the user.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class StatsFragment extends Fragment implements TrackDataListener {
|
||||
|
||||
public static final String STATS_FRAGMENT_TAG = "statsFragment";
|
||||
|
||||
private static final String TAG = StatsFragment.class.getSimpleName();
|
||||
|
||||
private TrackDataHub trackDataHub;
|
||||
private UiUpdateThread uiUpdateThread;
|
||||
|
||||
private Location lastLocation = null;
|
||||
private TripStatistics lastTripStatistics = null;
|
||||
|
||||
// A runnable to update the total time field.
|
||||
private final Runnable updateTotalTime = new Runnable() {
|
||||
public void run() {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null && lastTripStatistics != null && isSelectedTrackRecording()
|
||||
&& !isSelectedTrackPaused()) {
|
||||
StatsUtils.setTotalTimeValue(activity, System.currentTimeMillis()
|
||||
- lastTripStatistics.getStopTime() + lastTripStatistics.getTotalTime());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A thread that updates the total time field every second.
|
||||
*/
|
||||
private class UiUpdateThread extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(TAG, "UI update thread started");
|
||||
while (isSelectedTrackRecording()) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null) {
|
||||
activity.runOnUiThread(updateTotalTime);
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1000L);
|
||||
} catch (InterruptedException e) {
|
||||
Log.d(TAG, "UI update thread caught exception", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "UI update thread finished");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(
|
||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.stats, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
updateUi(getActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
resumeTrackDataHub();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
pauseTrackDataHub();
|
||||
if (uiUpdateThread != null) {
|
||||
uiUpdateThread.interrupt();
|
||||
uiUpdateThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationStateChanged(LocationState state) {
|
||||
if (isResumed() && state != LocationState.GOOD_FIX) {
|
||||
final FragmentActivity activity = getActivity();
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
lastLocation = null;
|
||||
StatsUtils.setLocationValues(activity, lastLocation, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(final Location location) {
|
||||
if (isResumed()) {
|
||||
final FragmentActivity activity = getActivity();
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isSelectedTrackRecording() && !isSelectedTrackPaused()) {
|
||||
lastLocation = location;
|
||||
StatsUtils.setLocationValues(activity, location, true);
|
||||
} else {
|
||||
if (lastLocation != null) {
|
||||
lastLocation = null;
|
||||
StatsUtils.setLocationValues(activity, lastLocation, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHeadingChanged(double heading) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectedTrackChanged(Track track) {
|
||||
if (isResumed()) {
|
||||
if (uiUpdateThread != null) {
|
||||
uiUpdateThread.interrupt();
|
||||
uiUpdateThread = null;
|
||||
}
|
||||
if (isSelectedTrackRecording()) {
|
||||
uiUpdateThread = new UiUpdateThread();
|
||||
uiUpdateThread.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackUpdated(final Track track) {
|
||||
if (isResumed()) {
|
||||
final FragmentActivity activity = getActivity();
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
lastTripStatistics = track != null ? track.getTripStatistics() : null;
|
||||
updateUi(activity);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTrackPoints() {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSampledInTrackPoint(Location location) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSampledOutTrackPoint(Location location) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSegmentSplit(Location location) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewTrackPointsDone() {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWaypoints() {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewWaypoint(Waypoint wpt) {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewWaypointsDone() {
|
||||
// We don't care.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMetricUnitsChanged(final boolean metric) {
|
||||
if (isResumed()) {
|
||||
final FragmentActivity activity = getActivity();
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateUi(activity);
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onReportSpeedChanged(final boolean speed) {
|
||||
if (isResumed()) {
|
||||
final FragmentActivity activity = getActivity();
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateUi(activity);
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMinRecordingDistanceChanged(int minRecordingDistance) {
|
||||
// We don't care.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the trackDataHub. Needs to be synchronized because trackDataHub can
|
||||
* be accessed by multiple threads.
|
||||
*/
|
||||
private synchronized void resumeTrackDataHub() {
|
||||
trackDataHub = ((TrackDetailActivity) getActivity()).getTrackDataHub();
|
||||
trackDataHub.registerTrackDataListener(this, EnumSet.of(TrackDataType.SELECTED_TRACK,
|
||||
TrackDataType.TRACKS_TABLE, TrackDataType.LOCATION, TrackDataType.PREFERENCE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the trackDataHub. Needs to be synchronized because trackDataHub can
|
||||
* be accessed by multiple threads.
|
||||
*/
|
||||
private synchronized void pauseTrackDataHub() {
|
||||
trackDataHub.unregisterTrackDataListener(this);
|
||||
trackDataHub = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the selected track is recording. Needs to be synchronized
|
||||
* because trackDataHub can be accessed by multiple threads.
|
||||
*/
|
||||
private synchronized boolean isSelectedTrackRecording() {
|
||||
return trackDataHub != null && trackDataHub.isSelectedTrackRecording();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the selected track is paused. Needs to be synchronized
|
||||
* because trackDataHub can be accessed by multiple threads.
|
||||
*/
|
||||
private synchronized boolean isSelectedTrackPaused() {
|
||||
return trackDataHub != null && trackDataHub.isSelectedTrackPaused();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the UI.
|
||||
*/
|
||||
private void updateUi(FragmentActivity activity) {
|
||||
StatsUtils.setTripStatisticsValues(activity, lastTripStatistics);
|
||||
StatsUtils.setLocationValues(activity, lastLocation, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.fragments;
|
||||
|
||||
import com.google.android.apps.mytracks.TrackListActivity;
|
||||
import com.google.android.apps.mytracks.util.EulaUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
|
||||
/**
|
||||
* A DialogFrament to show the welcome info.
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class WelcomeDialogFragment extends DialogFragment {
|
||||
|
||||
public static final String WELCOME_DIALOG_TAG = "welcomeDialog";
|
||||
|
||||
@Override
|
||||
public void onCancel(DialogInterface arg0) {
|
||||
onDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
return new AlertDialog.Builder(getActivity())
|
||||
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
onDone();
|
||||
}
|
||||
})
|
||||
.setTitle(R.string.welcome_title)
|
||||
.setMessage(R.string.welcome_message)
|
||||
.create();
|
||||
}
|
||||
|
||||
private void onDone() {
|
||||
EulaUtils.setShowWelcome(getActivity());
|
||||
TrackListActivity trackListActivity = (TrackListActivity) getActivity();
|
||||
trackListActivity.showStartupDialogs();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user