2016-09-20 11:51:17 +00:00
|
|
|
/**
|
|
|
|
* MainActivityTrackFragment.java
|
|
|
|
* Implements the track fragment used in the track tab of the main activity
|
|
|
|
* This fragment displays a saved track
|
|
|
|
*
|
|
|
|
* This file is part of
|
|
|
|
* TRACKBOOK - Movement Recorder for Android
|
|
|
|
*
|
2018-01-12 16:42:47 +00:00
|
|
|
* Copyright (c) 2016-18 - Y20K.org
|
2016-09-20 11:51:17 +00:00
|
|
|
* Licensed under the MIT-License
|
|
|
|
* http://opensource.org/licenses/MIT
|
|
|
|
*
|
|
|
|
* Trackbook uses osmdroid - OpenStreetMap-Tools for Android
|
|
|
|
* https://github.com/osmdroid/osmdroid
|
|
|
|
*/
|
|
|
|
|
2016-09-16 15:45:10 +00:00
|
|
|
package org.y20k.trackbook;
|
|
|
|
|
2016-09-29 10:54:57 +00:00
|
|
|
import android.app.Activity;
|
2016-12-19 16:53:20 +00:00
|
|
|
import android.content.BroadcastReceiver;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Intent;
|
|
|
|
import android.content.IntentFilter;
|
2016-09-30 15:32:54 +00:00
|
|
|
import android.location.Location;
|
|
|
|
import android.os.AsyncTask;
|
2016-09-16 15:45:10 +00:00
|
|
|
import android.os.Bundle;
|
2016-12-05 14:10:24 +00:00
|
|
|
import android.support.annotation.NonNull;
|
2016-09-16 15:45:10 +00:00
|
|
|
import android.support.annotation.Nullable;
|
2017-12-19 15:52:01 +00:00
|
|
|
import android.support.constraint.ConstraintLayout;
|
2018-02-06 16:10:36 +00:00
|
|
|
import android.support.constraint.Group;
|
2016-09-29 10:54:57 +00:00
|
|
|
import android.support.design.widget.BottomSheetBehavior;
|
2017-05-17 13:43:53 +00:00
|
|
|
import android.support.v4.app.DialogFragment;
|
2016-09-16 15:45:10 +00:00
|
|
|
import android.support.v4.app.Fragment;
|
2017-05-17 13:43:53 +00:00
|
|
|
import android.support.v4.app.FragmentActivity;
|
2017-12-18 16:10:55 +00:00
|
|
|
import android.support.v4.content.ContextCompat;
|
2016-12-19 16:53:20 +00:00
|
|
|
import android.support.v4.content.LocalBroadcastManager;
|
2016-09-16 15:45:10 +00:00
|
|
|
import android.view.LayoutInflater;
|
2018-04-25 20:58:59 +00:00
|
|
|
import android.view.MotionEvent;
|
2016-09-16 15:45:10 +00:00
|
|
|
import android.view.View;
|
|
|
|
import android.view.ViewGroup;
|
2017-02-15 14:29:21 +00:00
|
|
|
import android.widget.AdapterView;
|
2017-02-21 12:29:04 +00:00
|
|
|
import android.widget.ImageButton;
|
2017-02-17 08:58:37 +00:00
|
|
|
import android.widget.LinearLayout;
|
2017-02-03 20:12:13 +00:00
|
|
|
import android.widget.Spinner;
|
2016-09-29 10:54:57 +00:00
|
|
|
import android.widget.TextView;
|
2018-02-06 16:10:36 +00:00
|
|
|
import android.widget.Toast;
|
2016-09-29 10:54:57 +00:00
|
|
|
|
2016-09-30 15:32:54 +00:00
|
|
|
import org.osmdroid.api.IMapController;
|
|
|
|
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
|
|
|
|
import org.osmdroid.util.GeoPoint;
|
|
|
|
import org.osmdroid.views.MapView;
|
|
|
|
import org.osmdroid.views.overlay.ItemizedIconOverlay;
|
|
|
|
import org.osmdroid.views.overlay.compass.CompassOverlay;
|
|
|
|
import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider;
|
2016-09-29 10:54:57 +00:00
|
|
|
import org.y20k.trackbook.core.Track;
|
2017-05-17 13:43:53 +00:00
|
|
|
import org.y20k.trackbook.helpers.DialogHelper;
|
2017-02-03 20:12:13 +00:00
|
|
|
import org.y20k.trackbook.helpers.DropdownAdapter;
|
2017-05-17 13:43:53 +00:00
|
|
|
import org.y20k.trackbook.helpers.ExportHelper;
|
2018-04-25 20:58:59 +00:00
|
|
|
import org.y20k.trackbook.helpers.LengthUnitHelper;
|
|
|
|
import org.y20k.trackbook.helpers.LocationHelper;
|
2016-09-30 15:32:54 +00:00
|
|
|
import org.y20k.trackbook.helpers.LogHelper;
|
|
|
|
import org.y20k.trackbook.helpers.MapHelper;
|
2016-09-29 10:54:57 +00:00
|
|
|
import org.y20k.trackbook.helpers.StorageHelper;
|
2016-09-30 15:32:54 +00:00
|
|
|
import org.y20k.trackbook.helpers.TrackbookKeys;
|
2016-09-16 15:45:10 +00:00
|
|
|
|
2017-02-15 14:29:21 +00:00
|
|
|
import java.io.File;
|
2016-10-05 11:53:31 +00:00
|
|
|
import java.text.DateFormat;
|
2017-01-23 11:32:27 +00:00
|
|
|
import java.util.Locale;
|
2016-10-05 11:53:31 +00:00
|
|
|
|
2016-09-20 11:51:17 +00:00
|
|
|
|
2016-09-16 15:45:10 +00:00
|
|
|
/**
|
2016-09-20 11:51:17 +00:00
|
|
|
* MainActivityTrackFragment class
|
2016-09-16 15:45:10 +00:00
|
|
|
*/
|
2017-02-15 14:29:21 +00:00
|
|
|
public class MainActivityTrackFragment extends Fragment implements AdapterView.OnItemSelectedListener, TrackbookKeys {
|
2016-09-16 15:45:10 +00:00
|
|
|
|
2016-09-20 11:51:17 +00:00
|
|
|
/* Define log tag */
|
|
|
|
private static final String LOG_TAG = MainActivityTrackFragment.class.getSimpleName();
|
|
|
|
|
2016-09-16 15:45:10 +00:00
|
|
|
|
|
|
|
/* Main class variables */
|
2017-05-17 13:43:53 +00:00
|
|
|
private FragmentActivity mActivity;
|
2016-09-16 15:45:10 +00:00
|
|
|
private View mRootView;
|
2016-09-30 15:32:54 +00:00
|
|
|
private MapView mMapView;
|
2017-02-17 08:58:37 +00:00
|
|
|
private LinearLayout mOnboardingView;
|
2016-09-30 15:32:54 +00:00
|
|
|
private IMapController mController;
|
|
|
|
private ItemizedIconOverlay mTrackOverlay;
|
2017-02-03 20:12:13 +00:00
|
|
|
private DropdownAdapter mDropdownAdapter;
|
2017-12-19 15:52:01 +00:00
|
|
|
private ConstraintLayout mTrackManagementLayout;
|
2017-02-03 20:12:13 +00:00
|
|
|
private Spinner mDropdown;
|
2017-08-21 09:48:17 +00:00
|
|
|
private View mStatisticsSheet;
|
2018-04-25 20:58:59 +00:00
|
|
|
private View mStatisticsView;
|
2016-09-29 10:54:57 +00:00
|
|
|
private TextView mDistanceView;
|
|
|
|
private TextView mStepsView;
|
|
|
|
private TextView mWaypointsView;
|
|
|
|
private TextView mDurationView;
|
|
|
|
private TextView mRecordingStartView;
|
|
|
|
private TextView mRecordingStopView;
|
2018-02-06 16:10:36 +00:00
|
|
|
private TextView mMaxAltitudeView;
|
|
|
|
private TextView mMinAltitudeView;
|
|
|
|
private TextView mPositiveElevationView;
|
|
|
|
private TextView mNegativeElevationView;
|
|
|
|
private Group mElevationDataViews;
|
2018-04-30 15:02:53 +00:00
|
|
|
private Group mStatisticsHeaderViews;
|
2016-09-29 10:54:57 +00:00
|
|
|
private BottomSheetBehavior mStatisticsSheetBehavior;
|
2017-02-15 14:29:21 +00:00
|
|
|
private int mCurrentTrack;
|
2016-09-29 10:54:57 +00:00
|
|
|
private Track mTrack;
|
2016-12-19 16:53:20 +00:00
|
|
|
private BroadcastReceiver mTrackSavedReceiver;
|
2016-09-29 10:54:57 +00:00
|
|
|
|
2016-09-16 15:45:10 +00:00
|
|
|
|
2017-11-28 21:02:45 +00:00
|
|
|
/* Return a new Instance of MainActivityTrackFragment */
|
|
|
|
public static MainActivityTrackFragment newInstance() {
|
|
|
|
return new MainActivityTrackFragment();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-16 15:45:10 +00:00
|
|
|
@Override
|
|
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
|
|
|
|
// action bar has options menu
|
|
|
|
setHasOptionsMenu(true);
|
2016-09-29 10:54:57 +00:00
|
|
|
|
|
|
|
// store activity
|
|
|
|
mActivity = getActivity();
|
2016-12-19 16:53:20 +00:00
|
|
|
|
2017-02-15 14:29:21 +00:00
|
|
|
// get current track
|
|
|
|
if (savedInstanceState != null) {
|
|
|
|
mCurrentTrack = savedInstanceState.getInt(INSTANCE_CURRENT_TRACK, 0);
|
|
|
|
} else {
|
|
|
|
mCurrentTrack = 0;
|
|
|
|
}
|
|
|
|
|
2017-02-03 20:12:13 +00:00
|
|
|
// create drop-down adapter
|
|
|
|
mDropdownAdapter = new DropdownAdapter(mActivity);
|
|
|
|
|
2017-01-10 14:57:03 +00:00
|
|
|
// listen for finished save operation
|
2016-12-19 16:53:20 +00:00
|
|
|
mTrackSavedReceiver = new BroadcastReceiver() {
|
|
|
|
@Override
|
|
|
|
public void onReceive(Context context, Intent intent) {
|
|
|
|
if (intent.hasExtra(EXTRA_SAVE_FINISHED) && intent.getBooleanExtra(EXTRA_SAVE_FINISHED, false)) {
|
2017-01-10 14:57:03 +00:00
|
|
|
LogHelper.v(LOG_TAG, "Save operation detected. Start loading the new track.");
|
2017-02-15 14:29:21 +00:00
|
|
|
|
2017-02-17 08:58:37 +00:00
|
|
|
// update dropdown menu (and load track in onItemSelected)
|
2017-02-15 14:29:21 +00:00
|
|
|
mDropdownAdapter.refresh();
|
|
|
|
mDropdownAdapter.notifyDataSetChanged();
|
2017-02-17 08:58:37 +00:00
|
|
|
mDropdown.setAdapter(mDropdownAdapter);
|
|
|
|
mDropdown.setSelection(0, true);
|
2017-05-22 12:39:28 +00:00
|
|
|
|
|
|
|
// remove onboarding if necessary
|
|
|
|
switchOnboardingLayout();
|
2016-12-19 16:53:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2017-01-10 14:57:03 +00:00
|
|
|
IntentFilter trackSavedReceiverIntentFilter = new IntentFilter(ACTION_TRACK_SAVE);
|
|
|
|
LocalBroadcastManager.getInstance(mActivity).registerReceiver(mTrackSavedReceiver, trackSavedReceiverIntentFilter);
|
2016-12-19 16:53:20 +00:00
|
|
|
|
2016-09-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Nullable
|
|
|
|
@Override
|
2018-01-16 13:27:50 +00:00
|
|
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
2016-09-16 15:45:10 +00:00
|
|
|
|
|
|
|
// inflate root view from xml
|
|
|
|
mRootView = inflater.inflate(R.layout.fragment_main_track, container, false);
|
|
|
|
|
2017-02-17 08:58:37 +00:00
|
|
|
// get reference to onboarding layout
|
|
|
|
mOnboardingView = (LinearLayout) mRootView.findViewById(R.id.track_tab_onboarding);
|
|
|
|
|
|
|
|
// get reference to basic map
|
2016-09-30 15:32:54 +00:00
|
|
|
mMapView = (MapView) mRootView.findViewById(R.id.track_map);
|
|
|
|
|
|
|
|
// get map controller
|
|
|
|
mController = mMapView.getController();
|
|
|
|
|
|
|
|
// basic map setup
|
|
|
|
mMapView.setTileSource(TileSourceFactory.MAPNIK);
|
|
|
|
mMapView.setTilesScaledToDpi(true);
|
|
|
|
|
|
|
|
// add multi-touch capability
|
|
|
|
mMapView.setMultiTouchControls(true);
|
|
|
|
|
2018-02-19 08:00:47 +00:00
|
|
|
// disable default zoom controls
|
|
|
|
mMapView.setBuiltInZoomControls(false);
|
|
|
|
|
2016-09-30 15:32:54 +00:00
|
|
|
// add compass to map
|
|
|
|
CompassOverlay compassOverlay = new CompassOverlay(mActivity, new InternalCompassOrientationProvider(mActivity), mMapView);
|
|
|
|
compassOverlay.enableCompass();
|
2017-02-15 14:29:21 +00:00
|
|
|
// move the compass overlay down a bit
|
2018-01-12 16:42:47 +00:00
|
|
|
compassOverlay.setCompassCenter(35.0f, 96.0f);
|
2016-09-30 15:32:54 +00:00
|
|
|
mMapView.getOverlays().add(compassOverlay);
|
|
|
|
|
|
|
|
// initiate map state
|
|
|
|
if (savedInstanceState != null) {
|
|
|
|
// restore saved instance of map
|
|
|
|
GeoPoint position = new GeoPoint(savedInstanceState.getDouble(INSTANCE_LATITUDE_TRACK_MAP, DEFAULT_LATITUDE), savedInstanceState.getDouble(INSTANCE_LONGITUDE_TRACK_MAP, DEFAULT_LONGITUDE));
|
|
|
|
mController.setCenter(position);
|
2018-03-10 21:32:14 +00:00
|
|
|
mController.setZoom(savedInstanceState.getDouble(INSTANCE_ZOOM_LEVEL_MAIN_MAP, 16f));
|
2016-09-30 15:32:54 +00:00
|
|
|
} else {
|
2018-03-10 21:32:14 +00:00
|
|
|
mController.setZoom(16f);
|
2016-09-30 15:32:54 +00:00
|
|
|
}
|
|
|
|
|
2017-02-03 20:12:13 +00:00
|
|
|
// get views for track selector
|
2017-12-19 15:52:01 +00:00
|
|
|
mTrackManagementLayout = (ConstraintLayout) mRootView.findViewById(R.id.track_management_layout);
|
2017-02-03 20:12:13 +00:00
|
|
|
mDropdown = (Spinner) mRootView.findViewById(R.id.track_selector);
|
2016-09-30 15:32:54 +00:00
|
|
|
|
2017-05-17 13:43:53 +00:00
|
|
|
// attach listeners to export and delete buttons
|
|
|
|
ImageButton exportButton = (ImageButton) mRootView.findViewById(R.id.export_button);
|
2017-02-21 12:29:04 +00:00
|
|
|
ImageButton deleteButton = (ImageButton) mRootView.findViewById(R.id.delete_button);
|
2017-05-17 13:43:53 +00:00
|
|
|
exportButton.setOnClickListener(getExportButtonListener());
|
2017-02-21 12:29:04 +00:00
|
|
|
deleteButton.setOnClickListener(getDeleteButtonListener());
|
|
|
|
|
2017-02-03 20:12:13 +00:00
|
|
|
// get views for statistics sheet
|
2018-04-25 20:58:59 +00:00
|
|
|
mStatisticsView = mRootView.findViewById(R.id.statistics_view);
|
2017-08-21 09:48:17 +00:00
|
|
|
mStatisticsSheet = mRootView.findViewById(R.id.statistics_sheet);
|
2016-09-29 10:54:57 +00:00
|
|
|
mDistanceView = (TextView) mRootView.findViewById(R.id.statistics_data_distance);
|
|
|
|
mStepsView = (TextView) mRootView.findViewById(R.id.statistics_data_steps);
|
|
|
|
mWaypointsView = (TextView) mRootView.findViewById(R.id.statistics_data_waypoints);
|
|
|
|
mDurationView = (TextView) mRootView.findViewById(R.id.statistics_data_duration);
|
|
|
|
mRecordingStartView = (TextView) mRootView.findViewById(R.id.statistics_data_recording_start);
|
|
|
|
mRecordingStopView = (TextView) mRootView.findViewById(R.id.statistics_data_recording_stop);
|
2018-02-06 16:10:36 +00:00
|
|
|
mMaxAltitudeView = (TextView) mRootView.findViewById(R.id.statistics_data_max_altitude);
|
|
|
|
mMinAltitudeView = (TextView) mRootView.findViewById(R.id.statistics_data_min_altitude);
|
|
|
|
mPositiveElevationView = (TextView) mRootView.findViewById(R.id.statistics_data_positive_elevation);
|
|
|
|
mNegativeElevationView = (TextView) mRootView.findViewById(R.id.statistics_data_negative_elevation);
|
|
|
|
mElevationDataViews = (Group) mRootView.findViewById(R.id.elevation_data);
|
2018-04-30 15:02:53 +00:00
|
|
|
mStatisticsHeaderViews = (Group) mRootView.findViewById(R.id.statistics_header);
|
2018-02-06 16:10:36 +00:00
|
|
|
|
2016-09-29 10:54:57 +00:00
|
|
|
|
2017-02-21 12:29:04 +00:00
|
|
|
// display map and statistics
|
2017-01-10 14:57:03 +00:00
|
|
|
if (savedInstanceState != null) {
|
|
|
|
// get track from saved instance and display map and statistics
|
|
|
|
mTrack = savedInstanceState.getParcelable(INSTANCE_TRACK_TRACK_MAP);
|
|
|
|
displayTrack();
|
|
|
|
} else if (mTrack == null) {
|
2017-02-17 08:58:37 +00:00
|
|
|
// load track and display map and statistics
|
2016-10-05 11:53:31 +00:00
|
|
|
LoadTrackAsyncHelper loadTrackAsyncHelper = new LoadTrackAsyncHelper();
|
|
|
|
loadTrackAsyncHelper.execute();
|
|
|
|
} else {
|
2016-10-25 14:38:27 +00:00
|
|
|
// just display map and statistics
|
2016-10-05 11:53:31 +00:00
|
|
|
displayTrack();
|
|
|
|
}
|
|
|
|
|
2017-02-21 12:29:04 +00:00
|
|
|
// set up and show statistics sheet
|
2017-08-21 09:48:17 +00:00
|
|
|
mStatisticsSheetBehavior = BottomSheetBehavior.from(mStatisticsSheet);
|
2016-12-05 14:10:24 +00:00
|
|
|
mStatisticsSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
2017-02-21 12:29:04 +00:00
|
|
|
mStatisticsSheetBehavior.setBottomSheetCallback(getStatisticsSheetCallback());
|
2016-12-05 14:10:24 +00:00
|
|
|
|
2018-04-25 20:58:59 +00:00
|
|
|
// attach listener for taps on elevation views
|
|
|
|
attachTapListenerToElevationViews();
|
|
|
|
|
2018-04-30 15:02:53 +00:00
|
|
|
// attach listener for taps on statistics sheet header
|
|
|
|
attachTapListenerToStatisticHeaderViews();
|
|
|
|
|
|
|
|
// attach listener for taps on statistics - for US and other states plagued by Imperial units
|
|
|
|
if (LengthUnitHelper.getUnitSystem() == IMPERIAL) {
|
|
|
|
attachTapListenerToStatisticsSheet();
|
|
|
|
}
|
2018-04-25 20:58:59 +00:00
|
|
|
|
2016-09-16 15:45:10 +00:00
|
|
|
return mRootView;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-15 14:29:21 +00:00
|
|
|
@Override
|
2018-01-16 13:27:50 +00:00
|
|
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
2017-02-15 14:29:21 +00:00
|
|
|
super.onViewCreated(view, savedInstanceState);
|
|
|
|
mDropdown.setAdapter(mDropdownAdapter);
|
|
|
|
mDropdown.setOnItemSelectedListener(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-16 15:45:10 +00:00
|
|
|
@Override
|
|
|
|
public void onResume() {
|
|
|
|
super.onResume();
|
2017-02-17 08:58:37 +00:00
|
|
|
// show / hide the onboarding layout
|
|
|
|
switchOnboardingLayout();
|
2016-09-30 15:32:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onPause() {
|
|
|
|
super.onPause();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroyView(){
|
|
|
|
super.onDestroyView();
|
|
|
|
|
|
|
|
// deactivate map
|
|
|
|
mMapView.onDetach();
|
|
|
|
}
|
2016-09-29 10:54:57 +00:00
|
|
|
|
|
|
|
|
2017-01-10 14:57:03 +00:00
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
2017-01-25 13:19:50 +00:00
|
|
|
LogHelper.v(LOG_TAG, "onDestroy called.");
|
2017-01-10 14:57:03 +00:00
|
|
|
|
|
|
|
// remove listener
|
|
|
|
LocalBroadcastManager.getInstance(mActivity).unregisterReceiver(mTrackSavedReceiver);
|
2017-01-25 13:19:50 +00:00
|
|
|
|
|
|
|
super.onDestroy();
|
2017-01-10 14:57:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-15 14:29:21 +00:00
|
|
|
@Override
|
|
|
|
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
|
|
|
// update current track
|
|
|
|
mCurrentTrack = i;
|
|
|
|
|
|
|
|
// load track and display map and statistics
|
|
|
|
LoadTrackAsyncHelper loadTrackAsyncHelper = new LoadTrackAsyncHelper();
|
2017-02-17 08:58:37 +00:00
|
|
|
loadTrackAsyncHelper.execute(i);
|
2017-02-15 14:29:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onNothingSelected(AdapterView<?> adapterView) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-30 15:32:54 +00:00
|
|
|
@Override
|
2018-01-16 13:27:50 +00:00
|
|
|
public void onSaveInstanceState(@NonNull Bundle outState) {
|
2016-09-30 15:32:54 +00:00
|
|
|
outState.putDouble(INSTANCE_LATITUDE_TRACK_MAP, mMapView.getMapCenter().getLatitude());
|
|
|
|
outState.putDouble(INSTANCE_LONGITUDE_TRACK_MAP, mMapView.getMapCenter().getLongitude());
|
2018-03-10 21:32:14 +00:00
|
|
|
outState.putDouble(INSTANCE_ZOOM_LEVEL_TRACK_MAP, mMapView.getZoomLevelDouble());
|
2016-09-30 15:32:54 +00:00
|
|
|
outState.putParcelable(INSTANCE_TRACK_TRACK_MAP, mTrack);
|
2017-02-15 14:29:21 +00:00
|
|
|
outState.putInt(INSTANCE_CURRENT_TRACK, mCurrentTrack);
|
2016-09-30 15:32:54 +00:00
|
|
|
super.onSaveInstanceState(outState);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-17 13:43:53 +00:00
|
|
|
@Override
|
|
|
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
|
|
super.onActivityResult(requestCode, resultCode, data);
|
|
|
|
switch(requestCode) {
|
|
|
|
case RESULT_DELETE_DIALOG:
|
|
|
|
if (resultCode == Activity.RESULT_OK) {
|
2017-08-21 09:48:17 +00:00
|
|
|
deleteCurrentTrack();
|
2017-05-17 13:43:53 +00:00
|
|
|
} else if (resultCode == Activity.RESULT_CANCELED){
|
|
|
|
LogHelper.v(LOG_TAG, "Delete dialog result: CANCEL");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RESULT_EXPORT_DIALOG:
|
|
|
|
if (resultCode == Activity.RESULT_OK) {
|
|
|
|
// User chose EXPORT
|
2018-02-22 11:53:40 +00:00
|
|
|
ExportHelper.exportToGpx(mActivity, mTrack);
|
2017-05-17 13:43:53 +00:00
|
|
|
} else if (resultCode == Activity.RESULT_CANCELED){
|
|
|
|
// User chose CANCEL
|
|
|
|
LogHelper.v(LOG_TAG, "Export to GPX: User chose CANCEL.");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-30 15:32:54 +00:00
|
|
|
/* Displays map and statistics for track */
|
|
|
|
private void displayTrack() {
|
|
|
|
GeoPoint position;
|
|
|
|
|
2016-09-29 10:54:57 +00:00
|
|
|
if (mTrack != null) {
|
2016-09-30 15:32:54 +00:00
|
|
|
// set end of track as position
|
|
|
|
Location lastLocation = mTrack.getWayPointLocation(mTrack.getSize() -1);
|
|
|
|
position = new GeoPoint(lastLocation.getLatitude(), lastLocation.getLongitude());
|
|
|
|
|
2017-01-23 11:32:27 +00:00
|
|
|
String recordingStart = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()).format(mTrack.getRecordingStart()) + " " +
|
|
|
|
DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()).format(mTrack.getRecordingStart());
|
|
|
|
String recordingStop = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()).format(mTrack.getRecordingStop()) + " " +
|
|
|
|
DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()).format(mTrack.getRecordingStop());
|
2017-08-29 08:30:45 +00:00
|
|
|
String stepsTaken;
|
|
|
|
if (mTrack.getStepCount() == -1) {
|
|
|
|
stepsTaken = getString(R.string.statistics_sheet_p_steps_no_pedometer);
|
|
|
|
} else {
|
|
|
|
stepsTaken = String.valueOf(Math.round(mTrack.getStepCount()));
|
|
|
|
}
|
2016-10-05 11:53:31 +00:00
|
|
|
|
2018-04-25 20:58:59 +00:00
|
|
|
// populate length views
|
|
|
|
displayCurrentLengthUnits();
|
|
|
|
// populate other views
|
2017-08-29 08:30:45 +00:00
|
|
|
mStepsView.setText(stepsTaken);
|
2016-09-29 10:54:57 +00:00
|
|
|
mWaypointsView.setText(String.valueOf(mTrack.getWayPoints().size()));
|
2018-04-25 20:58:59 +00:00
|
|
|
mDurationView.setText(LocationHelper.convertToReadableTime(mTrack.getTrackDuration(), true));
|
2016-10-05 11:53:31 +00:00
|
|
|
mRecordingStartView.setText(recordingStart);
|
|
|
|
mRecordingStopView.setText(recordingStop);
|
2018-02-06 16:10:36 +00:00
|
|
|
|
|
|
|
// show/hide elevation views depending on file format version
|
2018-02-07 14:00:34 +00:00
|
|
|
if (mTrack.getTrackFormatVersion() > 1 && mTrack.getMinAltitude() > 0) {
|
2018-02-06 16:10:36 +00:00
|
|
|
// show elevation views
|
|
|
|
mElevationDataViews.setVisibility(View.VISIBLE);
|
|
|
|
} else {
|
|
|
|
// hide elevation views
|
|
|
|
mElevationDataViews.setVisibility(View.GONE);
|
|
|
|
}
|
2016-09-30 15:32:54 +00:00
|
|
|
|
|
|
|
// draw track on map
|
|
|
|
drawTrackOverlay(mTrack);
|
2018-02-06 16:10:36 +00:00
|
|
|
|
2016-09-30 15:32:54 +00:00
|
|
|
} else {
|
|
|
|
position = new GeoPoint(DEFAULT_LATITUDE, DEFAULT_LONGITUDE);
|
2016-09-29 10:54:57 +00:00
|
|
|
}
|
|
|
|
|
2016-09-30 15:32:54 +00:00
|
|
|
// center map over position
|
|
|
|
mController.setCenter(position);
|
|
|
|
|
2016-09-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-30 15:32:54 +00:00
|
|
|
/* Draws track onto overlay */
|
|
|
|
private void drawTrackOverlay(Track track) {
|
|
|
|
mMapView.getOverlays().remove(mTrackOverlay);
|
|
|
|
mTrackOverlay = MapHelper.createTrackOverlay(mActivity, track, false);
|
|
|
|
mMapView.getOverlays().add(mTrackOverlay);
|
2016-09-16 15:45:10 +00:00
|
|
|
}
|
|
|
|
|
2017-01-10 14:57:03 +00:00
|
|
|
|
2017-02-17 08:58:37 +00:00
|
|
|
/* show the onboarding layout, if no track has been recorded yet */
|
|
|
|
private void switchOnboardingLayout() {
|
|
|
|
if (mDropdownAdapter.isEmpty()){
|
|
|
|
// show onboarding layout
|
|
|
|
mMapView.setVisibility(View.GONE);
|
|
|
|
mOnboardingView.setVisibility(View.VISIBLE);
|
2017-08-21 09:48:17 +00:00
|
|
|
mTrackManagementLayout.setVisibility(View.GONE);
|
|
|
|
mStatisticsSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
|
|
|
mStatisticsSheet.setVisibility(View.GONE);
|
2017-02-17 08:58:37 +00:00
|
|
|
} else {
|
|
|
|
// show normal layout
|
|
|
|
mOnboardingView.setVisibility(View.GONE);
|
|
|
|
mMapView.setVisibility(View.VISIBLE);
|
|
|
|
mTrackManagementLayout.setVisibility(View.VISIBLE);
|
|
|
|
mStatisticsSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
2017-08-21 09:48:17 +00:00
|
|
|
mStatisticsSheet.setVisibility(View.VISIBLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-25 20:58:59 +00:00
|
|
|
/* Displays views in statistic sheet according to current locale */
|
|
|
|
private void displayCurrentLengthUnits() {
|
|
|
|
mDistanceView.setText(LengthUnitHelper.convertDistanceToString(mTrack.getTrackDistance()));
|
|
|
|
mPositiveElevationView.setText(LengthUnitHelper.convertDistanceToString(mTrack.getPositiveElevation()));
|
|
|
|
mNegativeElevationView.setText(LengthUnitHelper.convertDistanceToString(mTrack.getNegativeElevation()));
|
|
|
|
mMaxAltitudeView.setText(LengthUnitHelper.convertDistanceToString(mTrack.getMaxAltitude()));
|
|
|
|
mMinAltitudeView.setText(LengthUnitHelper.convertDistanceToString(mTrack.getMinAltitude()));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Switches views in statistic sheet between Metric and Imperial */
|
|
|
|
private void displayOppositeLengthUnits() {
|
2018-04-27 16:28:03 +00:00
|
|
|
int oppositeLengthUnit = LengthUnitHelper.getUnitSystem() * -1;
|
2018-04-25 20:58:59 +00:00
|
|
|
mDistanceView.setText(LengthUnitHelper.convertDistanceToString(mTrack.getTrackDistance(), oppositeLengthUnit));
|
|
|
|
mPositiveElevationView.setText(LengthUnitHelper.convertDistanceToString(mTrack.getPositiveElevation(), oppositeLengthUnit));
|
|
|
|
mNegativeElevationView.setText(LengthUnitHelper.convertDistanceToString(mTrack.getNegativeElevation(), oppositeLengthUnit));
|
|
|
|
mMaxAltitudeView.setText(LengthUnitHelper.convertDistanceToString(mTrack.getMaxAltitude(), oppositeLengthUnit));
|
|
|
|
mMinAltitudeView.setText(LengthUnitHelper.convertDistanceToString(mTrack.getMinAltitude(), oppositeLengthUnit));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-08-21 09:48:17 +00:00
|
|
|
/* Deletes currently visible track */
|
|
|
|
private void deleteCurrentTrack() {
|
|
|
|
|
|
|
|
// delete track file and refresh dropdown adapter
|
|
|
|
if (mDropdownAdapter.getItem(mCurrentTrack).getTrackFile().delete()) {
|
|
|
|
mDropdownAdapter.refresh();
|
|
|
|
mDropdownAdapter.notifyDataSetChanged();
|
|
|
|
mDropdown.setAdapter(mDropdownAdapter);
|
|
|
|
} else {
|
|
|
|
LogHelper.e(LOG_TAG, "Unable to delete recording.");
|
2017-08-21 11:37:02 +00:00
|
|
|
return;
|
2017-08-21 09:48:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mDropdownAdapter.isEmpty()) {
|
|
|
|
// show onboarding
|
|
|
|
switchOnboardingLayout();
|
|
|
|
} else {
|
|
|
|
// show next track
|
|
|
|
mDropdown.setSelection(0, true);
|
|
|
|
mCurrentTrack = 0;
|
2017-02-17 08:58:37 +00:00
|
|
|
}
|
2017-08-21 09:48:17 +00:00
|
|
|
|
2017-02-17 08:58:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-21 12:29:04 +00:00
|
|
|
/* Creates BottomSheetCallback for the statistics sheet - needed in onCreateView */
|
|
|
|
private BottomSheetBehavior.BottomSheetCallback getStatisticsSheetCallback() {
|
|
|
|
return new BottomSheetBehavior.BottomSheetCallback() {
|
|
|
|
@Override
|
|
|
|
public void onStateChanged(@NonNull View bottomSheet, int newState) {
|
|
|
|
// react to state change
|
|
|
|
switch (newState) {
|
|
|
|
case BottomSheetBehavior.STATE_EXPANDED:
|
|
|
|
// statistics sheet expanded
|
2017-05-17 13:43:53 +00:00
|
|
|
mTrackManagementLayout.setVisibility(View.INVISIBLE);
|
2018-02-21 10:47:09 +00:00
|
|
|
mStatisticsSheet.setBackgroundColor(ContextCompat.getColor(mActivity, R.color.statistic_sheet_background_expanded));
|
2017-02-21 12:29:04 +00:00
|
|
|
break;
|
|
|
|
case BottomSheetBehavior.STATE_COLLAPSED:
|
|
|
|
// statistics sheet collapsed
|
2017-05-17 13:43:53 +00:00
|
|
|
mTrackManagementLayout.setVisibility(View.VISIBLE);
|
2018-02-21 10:47:09 +00:00
|
|
|
mStatisticsSheet.setBackgroundColor(ContextCompat.getColor(mActivity, R.color.statistic_sheet_background_collapsed));
|
2017-02-21 12:29:04 +00:00
|
|
|
mStatisticsSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
|
|
|
break;
|
|
|
|
case BottomSheetBehavior.STATE_HIDDEN:
|
|
|
|
// statistics sheet hidden
|
|
|
|
mStatisticsSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
|
2018-04-27 16:28:03 +00:00
|
|
|
// reset length unit displays
|
|
|
|
displayCurrentLengthUnits();
|
2017-02-21 12:29:04 +00:00
|
|
|
// react to dragging events
|
2017-05-17 13:43:53 +00:00
|
|
|
if (slideOffset < 0.5f) {
|
|
|
|
mTrackManagementLayout.setVisibility(View.VISIBLE);
|
|
|
|
} else {
|
|
|
|
mTrackManagementLayout.setVisibility(View.INVISIBLE);
|
|
|
|
}
|
2017-12-18 16:10:55 +00:00
|
|
|
if (slideOffset < 0.125f) {
|
2018-02-21 10:47:09 +00:00
|
|
|
mStatisticsSheet.setBackgroundColor(ContextCompat.getColor(mActivity, R.color.statistic_sheet_background_collapsed));
|
2017-12-18 16:10:55 +00:00
|
|
|
} else {
|
2018-02-21 10:47:09 +00:00
|
|
|
mStatisticsSheet.setBackgroundColor(ContextCompat.getColor(mActivity, R.color.statistic_sheet_background_expanded));
|
2017-12-18 16:10:55 +00:00
|
|
|
}
|
2017-02-21 12:29:04 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Creates OnClickListener for the delete button - needed in onCreateView */
|
|
|
|
private View.OnClickListener getDeleteButtonListener() {
|
|
|
|
return new View.OnClickListener() {
|
|
|
|
@Override
|
|
|
|
public void onClick(View view) {
|
2017-05-17 13:43:53 +00:00
|
|
|
// get text elements for delete dialog
|
|
|
|
int dialogTitle = R.string.dialog_delete_title;
|
|
|
|
int dialogPositiveButton = R.string.dialog_delete_action_delete;
|
|
|
|
int dialogNegativeButton = R.string.dialog_default_action_cancel;
|
2017-05-22 12:39:28 +00:00
|
|
|
DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
|
|
|
|
String recordingStartDate = df.format(mTrack.getRecordingStart());
|
2018-04-25 20:58:59 +00:00
|
|
|
String dialogMessage = getString(R.string.dialog_delete_content) + " " + recordingStartDate + " | " + LengthUnitHelper.convertDistanceToString(mTrack.getTrackDistance());
|
2017-05-17 13:43:53 +00:00
|
|
|
|
|
|
|
// show delete dialog - results are handles by onActivityResult
|
|
|
|
DialogFragment dialogFragment = DialogHelper.newInstance(dialogTitle, dialogMessage, dialogPositiveButton, dialogNegativeButton);
|
|
|
|
dialogFragment.setTargetFragment(MainActivityTrackFragment.this, RESULT_DELETE_DIALOG);
|
|
|
|
dialogFragment.show(mActivity.getSupportFragmentManager(), "DeleteDialog");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Creates OnClickListener for the export button - needed in onCreateView */
|
|
|
|
private View.OnClickListener getExportButtonListener() {
|
|
|
|
return new View.OnClickListener() {
|
|
|
|
@Override
|
|
|
|
public void onClick(View view) {
|
|
|
|
// dialog text components
|
|
|
|
int dialogTitle;
|
|
|
|
int dialogPositiveButton;
|
|
|
|
int dialogNegativeButton;
|
2017-05-22 12:39:28 +00:00
|
|
|
DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
|
|
|
|
String recordingStartDate = df.format(mTrack.getRecordingStart());
|
|
|
|
String dialogMessage;
|
2017-05-17 13:43:53 +00:00
|
|
|
|
|
|
|
// get text elements for delete dialog
|
2018-02-22 11:53:40 +00:00
|
|
|
if (ExportHelper.gpxFileExists(mTrack)) {
|
2017-05-17 13:43:53 +00:00
|
|
|
// CASE: OVERWRITE - GPX file exists
|
|
|
|
dialogTitle = R.string.dialog_export_title_overwrite;
|
2018-04-25 20:58:59 +00:00
|
|
|
dialogMessage = getString(R.string.dialog_export_content_overwrite) + " (" + recordingStartDate + " | " + LengthUnitHelper.convertDistanceToString(mTrack.getTrackDistance()) + ")";
|
2017-05-17 13:43:53 +00:00
|
|
|
dialogPositiveButton = R.string.dialog_export_action_overwrite;
|
|
|
|
dialogNegativeButton = R.string.dialog_default_action_cancel;
|
|
|
|
} else {
|
|
|
|
// CASE: EXPORT - GPX file does NOT yet exits
|
|
|
|
dialogTitle = R.string.dialog_export_title_export;
|
2018-04-25 20:58:59 +00:00
|
|
|
dialogMessage = getString(R.string.dialog_export_content_export) + " (" + recordingStartDate + " | " + LengthUnitHelper.convertDistanceToString(mTrack.getTrackDistance()) + ")";
|
2017-05-17 13:43:53 +00:00
|
|
|
dialogPositiveButton = R.string.dialog_export_action_export;
|
|
|
|
dialogNegativeButton = R.string.dialog_default_action_cancel;
|
|
|
|
}
|
|
|
|
|
|
|
|
// show delete dialog - results are handles by onActivityResult
|
|
|
|
DialogFragment dialogFragment = DialogHelper.newInstance(dialogTitle, dialogMessage, dialogPositiveButton, dialogNegativeButton);
|
|
|
|
dialogFragment.setTargetFragment(MainActivityTrackFragment.this, RESULT_EXPORT_DIALOG);
|
|
|
|
dialogFragment.show(mActivity.getSupportFragmentManager(), "ExportDialog");
|
2017-02-21 12:29:04 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-25 20:58:59 +00:00
|
|
|
/* Add tap listener to elevation data views */
|
|
|
|
private void attachTapListenerToElevationViews() {
|
2018-02-06 16:10:36 +00:00
|
|
|
int referencedIds[] = mElevationDataViews.getReferencedIds();
|
|
|
|
for (int id : referencedIds) {
|
|
|
|
mRootView.findViewById(id).setOnClickListener(new View.OnClickListener() {
|
|
|
|
@Override
|
|
|
|
public void onClick(View view) {
|
|
|
|
// inform user about possible issues with altitude measurements
|
|
|
|
Toast.makeText(mActivity, R.string.toast_message_elevation_info, Toast.LENGTH_LONG).show();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-30 15:02:53 +00:00
|
|
|
/* Add tap listener to statistic header views */
|
|
|
|
private void attachTapListenerToStatisticHeaderViews() {
|
|
|
|
int referencedIds[] = mStatisticsHeaderViews.getReferencedIds();
|
|
|
|
for (int id : referencedIds) {
|
|
|
|
mRootView.findViewById(id).setOnClickListener(new View.OnClickListener() {
|
|
|
|
@Override
|
|
|
|
public void onClick(View view) {
|
|
|
|
if (mStatisticsSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {
|
|
|
|
mStatisticsSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
|
|
|
} else {
|
|
|
|
mStatisticsSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-25 20:58:59 +00:00
|
|
|
/* Add tap listener to statistics sheet */
|
|
|
|
private void attachTapListenerToStatisticsSheet() {
|
|
|
|
mStatisticsView.setOnTouchListener(new View.OnTouchListener() {
|
|
|
|
@Override
|
|
|
|
public boolean onTouch(View v, MotionEvent event) {
|
2018-04-27 16:28:03 +00:00
|
|
|
if(event.getAction() == MotionEvent.ACTION_DOWN) {
|
|
|
|
displayOppositeLengthUnits();
|
|
|
|
} else if (event.getAction() == MotionEvent.ACTION_UP) {
|
2018-04-26 12:48:53 +00:00
|
|
|
displayCurrentLengthUnits();
|
2018-04-25 20:58:59 +00:00
|
|
|
}
|
2018-04-27 16:28:03 +00:00
|
|
|
return true;
|
2018-04-25 20:58:59 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-30 15:32:54 +00:00
|
|
|
/**
|
|
|
|
* Inner class: Loads track from external storage using AsyncTask
|
|
|
|
*/
|
2017-02-17 08:58:37 +00:00
|
|
|
private class LoadTrackAsyncHelper extends AsyncTask<Integer, Void, Void> {
|
2016-09-30 15:32:54 +00:00
|
|
|
|
|
|
|
@Override
|
2017-02-17 08:58:37 +00:00
|
|
|
protected Void doInBackground(Integer... ints) {
|
2016-09-30 15:32:54 +00:00
|
|
|
LogHelper.v(LOG_TAG, "Loading track object in background.");
|
2017-02-15 14:29:21 +00:00
|
|
|
|
2017-01-19 12:36:49 +00:00
|
|
|
StorageHelper storageHelper = new StorageHelper(mActivity);
|
2017-02-17 08:58:37 +00:00
|
|
|
if (ints.length > 0) {
|
|
|
|
// get track file from dropdown adapter
|
|
|
|
int item = ints[0];
|
|
|
|
File trackFile = mDropdownAdapter.getItem(item).getTrackFile();
|
|
|
|
LogHelper.v(LOG_TAG, "Loading track number " + item);
|
|
|
|
mTrack = storageHelper.loadTrack(trackFile);
|
2017-02-15 14:29:21 +00:00
|
|
|
} else {
|
|
|
|
// load track object from most current file
|
2017-02-17 08:58:37 +00:00
|
|
|
LogHelper.v(LOG_TAG, "No specific track specified. Loading most current one.");
|
2017-02-15 14:29:21 +00:00
|
|
|
mTrack = storageHelper.loadTrack(FILE_MOST_CURRENT_TRACK);
|
|
|
|
}
|
2016-09-30 15:32:54 +00:00
|
|
|
return null;
|
|
|
|
}
|
2016-09-16 15:45:10 +00:00
|
|
|
|
2016-09-30 15:32:54 +00:00
|
|
|
@Override
|
|
|
|
protected void onPostExecute(Void aVoid) {
|
|
|
|
super.onPostExecute(aVoid);
|
2017-02-15 14:29:21 +00:00
|
|
|
|
|
|
|
// display track on map
|
2016-09-30 15:32:54 +00:00
|
|
|
displayTrack();
|
|
|
|
}
|
2016-09-16 15:45:10 +00:00
|
|
|
}
|
2017-02-03 20:12:13 +00:00
|
|
|
/**
|
|
|
|
* End of inner class
|
|
|
|
*/
|
2016-09-16 15:45:10 +00:00
|
|
|
|
|
|
|
}
|