diff --git a/myTracks/build.gradle b/myTracks/build.gradle index fc8311b66..5d7cf3bdc 100644 --- a/myTracks/build.gradle +++ b/myTracks/build.gradle @@ -5,7 +5,7 @@ android { defaultConfig { applicationId "com.google.android.maps.mytracks" - minSdkVersion 14 + minSdkVersion 21 targetSdkVersion 26 testApplicationId "com.google.android.maps.mytracks.test" @@ -22,33 +22,38 @@ android { dependencies { compile project(':myTracksLib') - compile files('libs/android-support-v4.jar') + //compile files('libs/android-support-v4.jar') compile files('libs/antlib.jar') - compile files('libs/gdata-client-1.0.jar') - compile files('libs/gdata-client-meta-1.0.jar') - compile files('libs/gdata-core-1.0.jar') - compile files('libs/gdata-spreadsheet-3.0.jar') - compile files('libs/gdata-spreadsheet-meta-3.0.jar') + //compile files('libs/gdata-client-1.0.jar') + //compile files('libs/gdata-client-meta-1.0.jar') + //compile files('libs/gdata-core-1.0.jar') + //compile files('libs/gdata-spreadsheet-3.0.jar') + //compile files('libs/gdata-spreadsheet-meta-3.0.jar') compile files('libs/google-api-client-1.12.0-beta.jar') compile files('libs/google-api-client-android-1.12.0-beta.jar') compile files('libs/google-api-services-drive-v2-rev30-1.12.0-beta.jar') - compile files('libs/google-api-services-fusiontables-v1-rev16-1.12.0-beta.jar') - compile files('libs/google-common.jar') + //compile files('libs/google-api-services-fusiontables-v1-rev16-1.12.0-beta.jar') + //compile files('libs/google-common.jar') compile files('libs/google-http-client-1.12.0-beta.jar') compile files('libs/google-http-client-android-1.12.0-beta.jar') compile files('libs/google-http-client-gson-1.12.0-beta.jar') - compile files('libs/google-http-client-jackson-1.12.0-beta.jar') - compile files('libs/google-http-client-jackson2-1.12.0-beta.jar') - compile files('libs/google-oauth-client-1.12.0-beta.jar') - compile files('libs/google-play-services.jar') - compile files('libs/gson-2.1.jar') - compile files('libs/guava-jdk5-13.0.jar') - compile files('libs/jackson-core-2.0.5.jar') - compile files('libs/jackson-core-asl-1.9.9.jar') - compile files('libs/jsr305.jar') - compile files('libs/libGoogleAnalytics.jar') + //compile files('libs/google-http-client-jackson-1.12.0-beta.jar') + //compile files('libs/google-http-client-jackson2-1.12.0-beta.jar') + //compile files('libs/google-oauth-client-1.12.0-beta.jar') + //compile files('libs/google-play-services.jar') + //compile files('libs/gson-2.1.jar') + compile files('libs/guava-jdk5-13.0.jar') //@visiblefortesting + //compile files('libs/jackson-core-2.0.5.jar') + //compile files('libs/jackson-core-asl-1.9.9.jar') + //compile files('libs/jsr305.jar') + //compile files('libs/libGoogleAnalytics.jar') androidTestCompile files('libs/AndroidMockGenerator.jar') androidTestCompile files('libs/robotium-solo-5.0.1.jar') implementation 'com.google.android.gms:play-services-location:11.8.0' + implementation 'com.google.android.gms:play-services:11.8.0' + implementation 'com.google.android.gms:play-services-auth:11.8.0' +// compile 'com.google.firebase:firebase-core:9.2.0' +// compile 'com.google.firebase:firebase-auth:9.2.0' +// compile 'com.google.firebase:firebase-messaging:11.8.0' } diff --git a/myTracks/src/androidTest/java/com/google/android/apps/mytracks/endtoendtest/common/ViewsTest.java b/myTracks/src/androidTest/java/com/google/android/apps/mytracks/endtoendtest/common/ViewsTest.java index 5b1bb3d83..e5856815f 100644 --- a/myTracks/src/androidTest/java/com/google/android/apps/mytracks/endtoendtest/common/ViewsTest.java +++ b/myTracks/src/androidTest/java/com/google/android/apps/mytracks/endtoendtest/common/ViewsTest.java @@ -20,7 +20,6 @@ import com.google.android.apps.mytracks.TrackDetailActivity; import com.google.android.apps.mytracks.TrackListActivity; import com.google.android.apps.mytracks.endtoendtest.EndToEndTestUtils; import com.google.android.apps.mytracks.fragments.ChartFragment; -import com.google.android.apps.mytracks.fragments.MyTracksMapFragment; import com.google.android.apps.mytracks.fragments.StatsFragment; import com.google.android.maps.mytracks.R; diff --git a/myTracks/src/main/java/com/google/android/apps/mytracks/TrackDetailActivity.java b/myTracks/src/main/java/com/google/android/apps/mytracks/TrackDetailActivity.java index 083e72aff..c030384d8 100644 --- a/myTracks/src/main/java/com/google/android/apps/mytracks/TrackDetailActivity.java +++ b/myTracks/src/main/java/com/google/android/apps/mytracks/TrackDetailActivity.java @@ -30,7 +30,6 @@ import com.google.android.apps.mytracks.fragments.ExportDialogFragment.ExportCal import com.google.android.apps.mytracks.fragments.ExportDialogFragment.ExportType; import com.google.android.apps.mytracks.fragments.FrequencyDialogFragment; import com.google.android.apps.mytracks.fragments.MapLayerDialogFragment; -import com.google.android.apps.mytracks.fragments.MyTracksMapFragment; import com.google.android.apps.mytracks.fragments.PlayMultipleDialogFragment; import com.google.android.apps.mytracks.fragments.PlayMultipleDialogFragment.PlayMultipleCaller; import com.google.android.apps.mytracks.fragments.StatsFragment; @@ -236,11 +235,6 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity tabsAdapter = new TabsAdapter(this, tabHost, viewPager); - TabSpec mapTabSpec = tabHost.newTabSpec(MyTracksMapFragment.MAP_FRAGMENT_TAG).setIndicator( - getString(R.string.track_detail_map_tab), - getResources().getDrawable(R.drawable.ic_tab_map)); - tabsAdapter.addTab(mapTabSpec, MyTracksMapFragment.class, null); - TabSpec chartTabSpec = tabHost.newTabSpec(ChartFragment.CHART_FRAGMENT_TAG).setIndicator( getString(R.string.track_detail_chart_tab), getResources().getDrawable(R.drawable.ic_tab_chart)); diff --git a/myTracks/src/main/java/com/google/android/apps/mytracks/fragments/MyTracksMapFragment.java b/myTracks/src/main/java/com/google/android/apps/mytracks/fragments/MyTracksMapFragment.java deleted file mode 100644 index e6970a81a..000000000 --- a/myTracks/src/main/java/com/google/android/apps/mytracks/fragments/MyTracksMapFragment.java +++ /dev/null @@ -1,764 +0,0 @@ -/* - * 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.MarkerDetailActivity; -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.services.MyTracksLocationManager; -import com.google.android.apps.mytracks.stats.TripStatistics; -import com.google.android.apps.mytracks.util.ApiAdapterFactory; -import com.google.android.apps.mytracks.util.GoogleLocationUtils; -import com.google.android.apps.mytracks.util.IntentUtils; -import com.google.android.apps.mytracks.util.LocationUtils; -import com.google.android.apps.mytracks.util.PreferencesUtils; -import com.google.android.apps.mytracks.util.TrackIconUtils; -import com.google.android.gms.location.LocationListener; -import com.google.android.gms.maps.CameraUpdate; -import com.google.android.gms.maps.CameraUpdateFactory; -import com.google.android.gms.maps.GoogleMap; -import com.google.android.gms.maps.GoogleMap.OnCameraChangeListener; -import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener; -import com.google.android.gms.maps.LocationSource; -import com.google.android.gms.maps.LocationSource.OnLocationChangedListener; -import com.google.android.gms.maps.SupportMapFragment; -import com.google.android.gms.maps.model.CameraPosition; -import com.google.android.gms.maps.model.LatLng; -import com.google.android.gms.maps.model.LatLngBounds; -import com.google.android.gms.maps.model.Marker; -import com.google.android.gms.maps.model.Polyline; -import com.google.android.maps.mytracks.R; - -import android.content.Context; -import android.content.Intent; -import android.location.Location; -import android.os.Bundle; -import android.os.Looper; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; -import android.view.ViewTreeObserver.OnGlobalLayoutListener; -import android.widget.FrameLayout; -import android.widget.ImageButton; -import android.widget.RelativeLayout; -import android.widget.TextView; -import android.widget.Toast; - -import java.util.ArrayList; -import java.util.EnumSet; - -/** - * A fragment to display map to the user. - * - * @author Leif Hendrik Wilden - * @author Rodrigo Damazio - */ -public class MyTracksMapFragment extends SupportMapFragment implements TrackDataListener { - - public static final String MAP_FRAGMENT_TAG = "mapFragment"; - - private static final String CURRENT_LOCATION_KEY = "current_location_key"; - private static final String - KEEP_CURRENT_LOCATION_VISIBLE_KEY = "keep_current_location_visible_key"; - - private static final float DEFAULT_ZOOM_LEVEL = 18f; - - // Google's latitude and longitude - private static final double DEFAULT_LATITUDE = 37.423; - private static final double DEFAULT_LONGITUDE = -122.084; - - private static final int MAP_VIEW_PADDING = 32; - - // States from TrackDetailActivity, set in onResume - private TrackDataHub trackDataHub; - - // Current location - private Location currentLocation; - private Location lastTrackPoint; - private int recordingGpsAccuracy = PreferencesUtils.RECORDING_GPS_ACCURACY_DEFAULT; - - /** - * True to continue keeping the current location visible on the screen. - *

- * Set to true when
- * 1. user clicks on the my location button
- * 2. first location during a recording
- * Set to false when
- * 1. showing a marker
- * 2. user manually zooms/pans - */ - private boolean keepCurrentLocationVisible; - private MyTracksLocationManager myTracksLocationManager; - - // LocationListener for periodic location request - private LocationListener locationListener; - - private OnLocationChangedListener onLocationChangedListener; - - // Current track - private Track currentTrack; - - // Current paths - private ArrayList paths = new ArrayList(); - boolean reloadPaths = true; - - // UI elements - private GoogleMap googleMap; - private MapOverlay mapOverlay; - private View mapView; - private ImageButton myLocationImageButton; - private TextView messageTextView; - - @Override - public void onCreate(Bundle bundle) { - super.onCreate(bundle); - setHasOptionsMenu(true); - mapOverlay = new MapOverlay(getActivity()); - } - - @Override - public View onCreateView( - LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - mapView = super.onCreateView(inflater, container, savedInstanceState); - View layout = inflater.inflate(R.layout.map, container, false); - RelativeLayout mapContainer = (RelativeLayout) layout.findViewById(R.id.map_container); - mapContainer.addView(mapView, 0); - - /* - * For Froyo (2.2) and Gingerbread (2.3), need a transparent FrameLayout on - * top for view pager to work correctly. - */ - FrameLayout frameLayout = new FrameLayout(getActivity()); - frameLayout.setBackgroundColor(getResources().getColor(android.R.color.transparent)); - mapContainer.addView(frameLayout, - new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); - - myLocationImageButton = (ImageButton) layout.findViewById(R.id.map_my_location); - myLocationImageButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (!myTracksLocationManager.isGpsProviderEnabled()) { - String message = GoogleLocationUtils.getGpsDisabledMyLocationMessage(getActivity()); - Toast.makeText(getActivity(), message, Toast.LENGTH_LONG).show(); - } else { - keepCurrentLocationVisible = true; - if (locationListener != null) { - myTracksLocationManager.removeLocationUpdates(locationListener); - locationListener = null; - } - if (isSelectedTrackRecording()) { - myTracksLocationManager.requestLastLocation(new LocationListener() { - @Override - public void onLocationChanged(Location location) { - if (isResumed()) { - setCurrentLocation(location); - updateCurrentLocation(true); - } - } - }); - } else { - locationListener = new LocationListener() { - @Override - public void onLocationChanged(Location location) { - if (isResumed()) { - boolean isFirst = setCurrentLocation(location); - updateCurrentLocation(isFirst); - } - } - }; - - /* - * Set currentLocation to null to cause the first requested location - * to force zoom to the default level. - */ - currentLocation = null; - myTracksLocationManager.requestLocationUpdates(0, 0f, locationListener); - } - } - } - }); - messageTextView = (TextView) layout.findViewById(R.id.map_message); - return layout; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - if (savedInstanceState != null) { - keepCurrentLocationVisible = savedInstanceState.getBoolean( - KEEP_CURRENT_LOCATION_VISIBLE_KEY, false); - if (keepCurrentLocationVisible) { - Location location = (Location) savedInstanceState.getParcelable(CURRENT_LOCATION_KEY); - if (location != null) { - setCurrentLocation(location); - } - } - } - - /* - * At this point, after onCreateView, getMap will not return null and we can - * initialize googleMap. However, onActivityCreated can be called multiple - * times, e.g., when the user switches tabs. With - * GoogleMapOptions.useViewLifecycleInFragment == false, googleMap lifecycle - * is tied to the fragment lifecycle and the same googleMap object is - * returned in getMap. Thus we only need to initialize googleMap once, when - * it is null. - */ - if (googleMap == null) { - googleMap = getMap(); - googleMap.setMyLocationEnabled(true); - - /* - * My Tracks needs to handle the onClick event when the my location button - * is clicked. Currently, the API doesn't allow handling onClick event, - * thus hiding the default my location button and providing our own. - */ - googleMap.getUiSettings().setMyLocationButtonEnabled(false); - googleMap.setIndoorEnabled(true); - googleMap.setOnMarkerClickListener(new OnMarkerClickListener() { - - @Override - public boolean onMarkerClick(Marker marker) { - if (isResumed()) { - String title = marker.getTitle(); - if (title != null && title.length() > 0) { - long id = Long.valueOf(title); - Context context = getActivity(); - Intent intent = IntentUtils.newIntent(context, MarkerDetailActivity.class) - .putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, id); - context.startActivity(intent); - } - } - return true; - } - }); - googleMap.setLocationSource(new LocationSource() { - - @Override - public void activate(OnLocationChangedListener listener) { - onLocationChangedListener = listener; - } - - @Override - public void deactivate() { - onLocationChangedListener = null; - } - }); - googleMap.setOnCameraChangeListener(new OnCameraChangeListener() { - - @Override - public void onCameraChange(CameraPosition cameraPosition) { - if (isResumed() && keepCurrentLocationVisible && currentLocation != null - && !isLocationVisible(currentLocation)) { - keepCurrentLocationVisible = false; - } - } - }); - } - } - - @Override - public void onResume() { - super.onResume(); - - // First obtain the states from TrackDetailActivity - long trackId = ((TrackDetailActivity) getActivity()).getTrackId(); - long markerId = ((TrackDetailActivity) getActivity()).getMarkerId(); - resumeTrackDataHub(); - - myTracksLocationManager = new MyTracksLocationManager(getActivity(), Looper.myLooper(), true); - boolean isGpsProviderEnabled = myTracksLocationManager.isGpsProviderEnabled(); - - if (googleMap != null) { - - // Disable my location if gps is disabled - googleMap.setMyLocationEnabled(isGpsProviderEnabled); - } - - // setWarningMessage depends on resumeTrackDataHub being invoked beforehand - setWarningMessage(isGpsProviderEnabled); - - currentTrack = MyTracksProviderUtils.Factory.get(getActivity()).getTrack(trackId); - mapOverlay.setShowEndMarker(!isSelectedTrackRecording()); - if (markerId != -1L) { - showMarker(markerId); - } else { - if (keepCurrentLocationVisible && currentLocation != null && isSelectedTrackRecording()) { - updateCurrentLocation(true); - } else { - /* - * Clear the current location in case the current location is no longer - * being updated continuously. - */ - if (onLocationChangedListener != null) { - onLocationChangedListener.onLocationChanged(new Location("")); - } - showTrack(); - } - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - outState.putBoolean(KEEP_CURRENT_LOCATION_VISIBLE_KEY, keepCurrentLocationVisible); - if (currentLocation != null) { - /* - * currentLocation is a MyTracksLocation object, which cannot be - * unmarshalled. Thus creating a Location object before placing it in the - * bundle. - */ - outState.putParcelable(CURRENT_LOCATION_KEY, new Location(currentLocation)); - } - } - - @Override - public void onPause() { - super.onPause(); - pauseTrackDataHub(); - if (locationListener != null) { - myTracksLocationManager.removeLocationUpdates(locationListener); - locationListener = null; - } - myTracksLocationManager.close(); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflator) { - menuInflator.inflate(R.menu.map, menu); - TrackIconUtils.setMenuIconColor(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem menuItem) { - if (menuItem.getItemId() == R.id.menu_map_layer) { - ((TrackDetailActivity) getActivity()).showMapLayerDialog(); - return true; - } - return super.onOptionsItemSelected(menuItem); - } - - @Override - public void onTrackUpdated(Track track) { - currentTrack = track; - } - - @Override - public void clearTrackPoints() { - lastTrackPoint = null; - if (isResumed()) { - mapOverlay.clearPoints(); - reloadPaths = true; - } - } - - @Override - public void onSampledInTrackPoint(final Location location) { - lastTrackPoint = location; - if (isResumed()) { - mapOverlay.addLocation(location); - } - } - - @Override - public void onSampledOutTrackPoint(Location location) { - lastTrackPoint = location; - } - - @Override - public void onSegmentSplit(Location location) { - if (isResumed()) { - mapOverlay.addSegmentSplit(); - } - } - - @Override - public void onNewTrackPointsDone() { - if (isResumed()) { - getActivity().runOnUiThread(new Runnable() { - public void run() { - if (isResumed() && googleMap != null && currentTrack != null) { - boolean hasStartMarker = mapOverlay.update( - googleMap, paths, currentTrack.getTripStatistics(), reloadPaths); - - /* - * If has the start marker, then don't need to reload the paths each - * time - */ - if (hasStartMarker) { - reloadPaths = false; - } - - if (lastTrackPoint != null && isSelectedTrackRecording()) { - boolean firstLocation = setCurrentLocation(lastTrackPoint); - if (firstLocation) { - keepCurrentLocationVisible = true; - } - updateCurrentLocation(firstLocation); - setWarningMessage(true); - } - } - } - }); - } - } - - @Override - public void clearWaypoints() { - if (isResumed()) { - mapOverlay.clearWaypoints(); - } - } - - @Override - public void onNewWaypoint(Waypoint waypoint) { - if (isResumed() && waypoint != null && LocationUtils.isValidLocation(waypoint.getLocation())) { - mapOverlay.addWaypoint(waypoint); - } - } - - @Override - public void onNewWaypointsDone() { - if (isResumed()) { - getActivity().runOnUiThread(new Runnable() { - public void run() { - if (isResumed() && googleMap != null && currentTrack != null) { - mapOverlay.update(googleMap, paths, currentTrack.getTripStatistics(), true); - } - } - }); - } - } - - @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 onRecordingGpsAccuracy(int newValue) { - recordingGpsAccuracy = newValue; - return false; - } - - @Override - public boolean onRecordingDistanceIntervalChanged(int minRecordingDistance) { - // We don't care. - return false; - } - - @Override - public boolean onMapTypeChanged(final int mapType) { - if (isResumed()) { - getActivity().runOnUiThread(new Runnable() { - public void run() { - if (isResumed() && googleMap != null) { - googleMap.setMapType(mapType); - } - } - }); - } - return false; - } - - /** - * Resumes the trackDataHub. Needs to be synchronized because the trackDataHub - * can be accessed by multiple threads. - */ - private synchronized void resumeTrackDataHub() { - trackDataHub = ((TrackDetailActivity) getActivity()).getTrackDataHub(); - trackDataHub.registerTrackDataListener(this, EnumSet.of(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 the trackDataHub - * can be accessed by multiple threads. - */ - private synchronized void pauseTrackDataHub() { - if (trackDataHub != null) { - trackDataHub.unregisterTrackDataListener(this); - } - trackDataHub = null; - } - - /** - * Returns true if the selected track is recording. Needs to be synchronized - * because the trackDataHub can be accessed by multiple threads. - */ - private synchronized boolean isSelectedTrackRecording() { - return trackDataHub != null && trackDataHub.isSelectedTrackRecording(); - } - - /** - * Sets the current location. - * - * @param location the location - * @return true if this is the first location - */ - private boolean setCurrentLocation(Location location) { - boolean isFirst = false; - if (currentLocation == null && location != null) { - isFirst = true; - } - currentLocation = location; - return isFirst; - } - - /** - * Updates the current location. - * - * @param forceZoom true to force zoom to the current location regardless of - * the keepCurrentLocationVisible policy - */ - private void updateCurrentLocation(final boolean forceZoom) { - getActivity().runOnUiThread(new Runnable() { - public void run() { - if (!isResumed() || googleMap == null || onLocationChangedListener == null - || currentLocation == null) { - return; - } - onLocationChangedListener.onLocationChanged(currentLocation); - if (forceZoom || (keepCurrentLocationVisible && !isLocationVisible(currentLocation))) { - LatLng latLng = new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude()); - CameraUpdate cameraUpdate = forceZoom ? CameraUpdateFactory.newLatLngZoom( - latLng, DEFAULT_ZOOM_LEVEL) - : CameraUpdateFactory.newLatLng(latLng); - googleMap.animateCamera(cameraUpdate); - } - }; - }); - } - - /** - * Shows the current track by moving the camera over the track. - */ - private void showTrack() { - if (googleMap == null || currentTrack == null) { - return; - } - if (currentTrack.getNumberOfPoints() < 2) { - googleMap.moveCamera( - CameraUpdateFactory.newLatLngZoom(getDefaultLatLng(), googleMap.getMinZoomLevel())); - return; - } - - if (mapView == null) { - return; - } - - if (mapView.getWidth() == 0 || mapView.getHeight() == 0) { - if (mapView.getViewTreeObserver().isAlive()) { - mapView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - if (!isResumed()) { - return; - } - ApiAdapterFactory.getApiAdapter() - .removeGlobalLayoutListener(mapView.getViewTreeObserver(), this); - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - if (isResumed()) { - moveCameraOverTrack(); - } - } - }); - } - }); - } - return; - } - moveCameraOverTrack(); - } - - /** - * Moves the camera over the current track. - */ - private void moveCameraOverTrack() { - /** - * Check all the required variables. - */ - if (googleMap == null || currentTrack == null || currentTrack.getNumberOfPoints() < 2 - || mapView == null || mapView.getWidth() == 0 || mapView.getHeight() == 0) { - return; - } - - TripStatistics tripStatistics = currentTrack.getTripStatistics(); - int latitudeSpanE6 = tripStatistics.getTop() - tripStatistics.getBottom(); - int longitudeSpanE6 = tripStatistics.getRight() - tripStatistics.getLeft(); - if (latitudeSpanE6 > 0 && latitudeSpanE6 < 180E6 && longitudeSpanE6 > 0 - && longitudeSpanE6 < 360E6) { - LatLng southWest = new LatLng( - tripStatistics.getBottomDegrees(), tripStatistics.getLeftDegrees()); - LatLng northEast = new LatLng( - tripStatistics.getTopDegrees(), tripStatistics.getRightDegrees()); - LatLngBounds bounds = LatLngBounds.builder().include(southWest).include(northEast).build(); - - /** - * Note cannot call CameraUpdateFactory.newLatLngBounds(LatLngBounds - * bounds, int padding) if the map view has not undergone layout. Thus - * calling CameraUpdateFactory.newLatLngBounds(LatLngBounds bounds, int - * width, int height, int padding) after making sure that mapView is valid - * in the above code. - */ - CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds( - bounds, mapView.getWidth(), mapView.getHeight(), MAP_VIEW_PADDING); - googleMap.moveCamera(cameraUpdate); - } - } - - /** - * Shows a marker by moving the camera over the marker. - * - * @param id the marker id - */ - private void showMarker(final long id) { - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - if (!isResumed() || googleMap == null) { - return; - } - MyTracksProviderUtils MyTracksProviderUtils = Factory.get(getActivity()); - Waypoint waypoint = MyTracksProviderUtils.getWaypoint(id); - if (waypoint == null) { - return; - } - Location location = waypoint.getLocation(); - if (location == null) { - return; - } - LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude()); - keepCurrentLocationVisible = false; - CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, DEFAULT_ZOOM_LEVEL); - googleMap.moveCamera(cameraUpdate); - } - }); - } - - /** - * Gets the default LatLng. - */ - private LatLng getDefaultLatLng() { - MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(getActivity()); - Location location = myTracksProviderUtils.getLastValidTrackPoint(); - if (location != null) { - return new LatLng(location.getLatitude(), location.getLongitude()); - } - return new LatLng(DEFAULT_LATITUDE, DEFAULT_LONGITUDE); - } - - /** - * Returns true if the location is visible. Needs to run on the UI thread. - * - * @param location the location - */ - private boolean isLocationVisible(Location location) { - if (location == null || googleMap == null) { - return false; - } - LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude()); - return googleMap.getProjection().getVisibleRegion().latLngBounds.contains(latLng); - } - - /** - * Sets the warning message. - * - * @param isGpsProviderEnabled true if gps provider is enabled - */ - private void setWarningMessage(boolean isGpsProviderEnabled) { - String message = getWarningMessage(isGpsProviderEnabled); - - if (message == null) { - messageTextView.setVisibility(View.GONE); - return; - } - messageTextView.setText(message); - messageTextView.setVisibility(View.VISIBLE); - if (isGpsProviderEnabled) { - messageTextView.setOnClickListener(null); - } else { - Toast.makeText(getActivity(), R.string.gps_not_found, Toast.LENGTH_LONG).show(); - - // Click to show the location source settings - messageTextView.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - if (isResumed()) { - startActivity(GoogleLocationUtils.newLocationSettingsIntent(getActivity())); - } - } - }); - } - } - - /** - * Gets the warning message. - * - * @param isGpsProviderEnabled true if gps provider is enabled - */ - private String getWarningMessage(boolean isGpsProviderEnabled) { - if (!isSelectedTrackRecording()) { - return null; - } - if (!isGpsProviderEnabled) { - return GoogleLocationUtils.getGpsDisabledMessage(getActivity()); - } - - boolean hasFix; - boolean hasGoodFix; - if (currentLocation == null) { - hasFix = false; - hasGoodFix = false; - } else { - hasFix = !LocationUtils.isLocationOld(currentLocation); - hasGoodFix = currentLocation.hasAccuracy() - && currentLocation.getAccuracy() < recordingGpsAccuracy; - } - if (!hasFix) { - return getString(R.string.gps_wait_for_signal); - } else if (!hasGoodFix) { - return getString(R.string.gps_wait_for_better_signal); - } else { - return null; - } - } -} \ No newline at end of file diff --git a/myTracks/src/main/java/com/google/android/apps/mytracks/services/MyTracksLocationManager.java b/myTracks/src/main/java/com/google/android/apps/mytracks/services/MyTracksLocationManager.java index e3e160dea..5ff8921d6 100644 --- a/myTracks/src/main/java/com/google/android/apps/mytracks/services/MyTracksLocationManager.java +++ b/myTracks/src/main/java/com/google/android/apps/mytracks/services/MyTracksLocationManager.java @@ -16,201 +16,208 @@ package com.google.android.apps.mytracks.services; -import com.google.android.apps.mytracks.util.GoogleLocationUtils; -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks; -import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener; -import com.google.android.gms.location.LocationClient; -import com.google.android.gms.location.LocationListener; -import com.google.android.gms.location.LocationRequest; - +import android.annotation.SuppressLint; import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; +import android.location.Location; import android.location.LocationManager; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.support.annotation.Nullable; + +import com.google.android.apps.mytracks.util.GoogleLocationUtils; +import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks; +import com.google.android.gms.location.FusedLocationProviderClient; +import com.google.android.gms.location.LocationCallback; +import com.google.android.gms.location.LocationListener; +import com.google.android.gms.location.LocationRequest; +import com.google.android.gms.location.LocationServices; +import com.google.android.gms.tasks.OnSuccessListener; + + /** * My Tracks Location Manager. Applies Google location settings before allowing * access to {@link LocationManager}. - * + * * @author Jimmy Shih */ public class MyTracksLocationManager { - /** - * Observer for Google location settings. - * - * @author Jimmy Shih - */ - private class GoogleSettingsObserver extends ContentObserver { + /** + * Observer for Google location settings. + * + * @author Jimmy Shih + */ + private class GoogleSettingsObserver extends ContentObserver { - public GoogleSettingsObserver(Handler handler) { - super(handler); - } - - @Override - public void onChange(boolean selfChange) { - isAllowed = GoogleLocationUtils.isAllowed(context); - } - } - - private final ConnectionCallbacks connectionCallbacks = new ConnectionCallbacks() { - @Override - public void onDisconnected() {} - - @Override - public void onConnected(Bundle bunlde) { - handler.post(new Runnable() { - @Override - public void run() { - if (requestLastLocation != null && locationClient.isConnected()) { - requestLastLocation.onLocationChanged(locationClient.getLastLocation()); - requestLastLocation = null; - } - if (requestLocationUpdates != null && locationClient.isConnected()) { - LocationRequest locationRequest = new LocationRequest().setPriority( - LocationRequest.PRIORITY_HIGH_ACCURACY).setInterval(requestLocationUpdatesTime) - .setFastestInterval(requestLocationUpdatesTime) - .setSmallestDisplacement(requestLocationUpdatesDistance); - locationClient.requestLocationUpdates( - locationRequest, requestLocationUpdates, handler.getLooper()); - } + public GoogleSettingsObserver(Handler handler) { + super(handler); } - }); - } - }; - private final OnConnectionFailedListener - onConnectionFailedListener = new OnConnectionFailedListener() { - @Override - public void onConnectionFailed(ConnectionResult connectionResult) {} - }; - - private final Context context; - private final Handler handler; - private final LocationClient locationClient; - private final LocationManager locationManager; - private final ContentResolver contentResolver; - private final GoogleSettingsObserver observer; - - private boolean isAllowed; - private LocationListener requestLastLocation; - private LocationListener requestLocationUpdates; - private float requestLocationUpdatesDistance; - private long requestLocationUpdatesTime; - - public MyTracksLocationManager(Context context, Looper looper, boolean enableLocaitonClient) { - this.context = context; - this.handler = new Handler(looper); - - if (enableLocaitonClient) { - locationClient = new LocationClient(context, connectionCallbacks, onConnectionFailedListener); - locationClient.connect(); - } else { - locationClient = null; - } - - locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); - contentResolver = context.getContentResolver(); - observer = new GoogleSettingsObserver(handler); - - isAllowed = GoogleLocationUtils.isAllowed(context); - - contentResolver.registerContentObserver( - GoogleLocationUtils.USE_LOCATION_FOR_SERVICES_URI, false, observer); - } - - /** - * Closes the {@link MyTracksLocationManager}. - */ - public void close() { - if (locationClient != null) { - locationClient.disconnect(); - } - contentResolver.unregisterContentObserver(observer); - } - - /** - * Returns true if allowed to access the location manager. Returns true if - * there is no enforcement or the Google location settings allows access to - * location data. - */ - public boolean isAllowed() { - return isAllowed; - } - - /** - * Returns true if gps provider is enabled. - */ - public boolean isGpsProviderEnabled() { - if (!isAllowed()) { - return false; - } - String provider = LocationManager.GPS_PROVIDER; - if (locationManager.getProvider(provider) == null) { - return false; - } - return locationManager.isProviderEnabled(provider); - } - - /** - * Request last location. - * - * @param locationListener location listener - */ - public void requestLastLocation(final LocationListener locationListener) { - handler.post(new Runnable() { @Override - public void run() { - if (!isAllowed()) { - requestLastLocation = null; - locationListener.onLocationChanged(null); + public void onChange(boolean selfChange) { + isAllowed = GoogleLocationUtils.isAllowed(context); + } + } + + private final ConnectionCallbacks connectionCallbacks = new ConnectionCallbacks() { + @Override + public void onConnected(@Nullable Bundle bundle) { + + } + + @Override + public void onConnectionSuspended(int i) { + handler.post(new Runnable() { + @SuppressLint("MissingPermission") + @Override + public void run() { + if (requestLastLocation != null) { + locationClient.getLastLocation().addOnSuccessListener( + new OnSuccessListener() { + @Override + public void onSuccess(Location location) { + // GPS location can be null if GPS is switched off + if (location != null) { + requestLastLocation.onLocationChanged(location); + } + requestLastLocation = null; + } + }); + } + if (requestLocationUpdates != null) { + LocationRequest locationRequest = new LocationRequest().setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) + .setInterval(requestLocationUpdatesTime) + .setFastestInterval(requestLocationUpdatesTime) + .setSmallestDisplacement(requestLocationUpdatesDistance); + + locationClient.requestLocationUpdates(locationRequest, requestLocationUpdates, handler.getLooper()); + } + } + }); + } + }; + private final Context context; + private final Handler handler; + private final FusedLocationProviderClient locationClient; + private final LocationManager locationManager; + private final ContentResolver contentResolver; + private final GoogleSettingsObserver observer; + + private boolean isAllowed; + private LocationListener requestLastLocation; + private LocationCallback requestLocationUpdates; + private float requestLocationUpdatesDistance; + private long requestLocationUpdatesTime; + + public MyTracksLocationManager(Context context, Looper looper, boolean enableLocationClient) { + this.context = context; + this.handler = new Handler(looper); + + if (enableLocationClient) { + locationClient = LocationServices.getFusedLocationProviderClient(context); } else { - requestLastLocation = locationListener; - connectionCallbacks.onConnected(null); + locationClient = null; } - } - }); - } - /** - * Requests location updates. This is an ongoing request, thus the caller - * needs to check the status of {@link #isAllowed}. - * - * @param minTime the minimal time - * @param minDistance the minimal distance - * @param locationListener the location listener - */ - public void requestLocationUpdates( - final long minTime, final float minDistance, final LocationListener locationListener) { - handler.post(new Runnable() { - @Override - public void run() { - requestLocationUpdatesTime = minTime; - requestLocationUpdatesDistance = minDistance; - requestLocationUpdates = locationListener; - connectionCallbacks.onConnected(null); - } - }); - } + locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + contentResolver = context.getContentResolver(); + observer = new GoogleSettingsObserver(handler); - /** - * Removes location updates. - * - * @param locationListener the location listener - */ - public void removeLocationUpdates(final LocationListener locationListener) { - handler.post(new Runnable() { - @Override - public void run() { - requestLocationUpdates = null; - if (locationClient != null && locationClient.isConnected()) { - locationClient.removeLocationUpdates(locationListener); + isAllowed = GoogleLocationUtils.isAllowed(context); + + contentResolver.registerContentObserver( + GoogleLocationUtils.USE_LOCATION_FOR_SERVICES_URI, false, observer); + } + + /** + * Closes the {@link MyTracksLocationManager}. + */ + public void close() { + contentResolver.unregisterContentObserver(observer); + } + + /** + * Returns true if allowed to access the location manager. Returns true if + * there is no enforcement or the Google location settings allows access to + * location data. + */ + public boolean isAllowed() { + return isAllowed; + } + + /** + * Returns true if gps provider is enabled. + */ + public boolean isGpsProviderEnabled() { + if (!isAllowed()) { + return false; } - } - }); - } + String provider = LocationManager.GPS_PROVIDER; + if (locationManager.getProvider(provider) == null) { + return false; + } + return locationManager.isProviderEnabled(provider); + } + + /** + * Request last location. + * + * @param locationListener location listener + */ + public void requestLastLocation(final LocationListener locationListener) { + handler.post(new Runnable() { + @Override + public void run() { + if (!isAllowed()) { + requestLastLocation = null; + locationListener.onLocationChanged(null); + } else { + requestLastLocation = locationListener; + connectionCallbacks.onConnected(null); + } + } + }); + } + + /** + * Requests location updates. This is an ongoing request, thus the caller + * needs to check the status of {@link #isAllowed}. + * + * @param minTime the minimal time + * @param minDistance the minimal distance + * @param locationListener the location listener + */ + public void requestLocationUpdates( + final long minTime, final float minDistance, final LocationCallback locationListener) { + handler.post(new Runnable() { + @Override + public void run() { + requestLocationUpdatesTime = minTime; + requestLocationUpdatesDistance = minDistance; + requestLocationUpdates = locationListener; + connectionCallbacks.onConnected(null); + } + }); + } + + /** + * Removes location updates. + * + * @param locationListener the location listener + */ + public void removeLocationUpdates(final LocationCallback locationListener) { + handler.post(new Runnable() { + @Override + public void run() { + requestLocationUpdates = null; + if (locationClient != null) { + locationClient.removeLocationUpdates(locationListener); + } + } + }); + } } diff --git a/myTracks/src/main/java/com/google/android/apps/mytracks/services/TrackRecordingService.java b/myTracks/src/main/java/com/google/android/apps/mytracks/services/TrackRecordingService.java index aefbe4955..23554f851 100644 --- a/myTracks/src/main/java/com/google/android/apps/mytracks/services/TrackRecordingService.java +++ b/myTracks/src/main/java/com/google/android/apps/mytracks/services/TrackRecordingService.java @@ -16,6 +16,27 @@ package com.google.android.apps.mytracks.services; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.database.sqlite.SQLiteException; +import android.location.Location; +import android.location.LocationManager; +import android.net.Uri; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.PowerManager.WakeLock; +import android.os.Process; +import android.support.annotation.Nullable; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.TaskStackBuilder; +import android.util.Log; + import com.google.android.apps.mytracks.Constants; import com.google.android.apps.mytracks.TrackDetailActivity; import com.google.android.apps.mytracks.TrackListActivity; @@ -47,34 +68,15 @@ import com.google.android.apps.mytracks.util.TrackIconUtils; import com.google.android.apps.mytracks.util.TrackNameUtils; import com.google.android.apps.mytracks.util.UnitConversions; import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks; -import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener; +import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks; +import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener; import com.google.android.gms.location.ActivityRecognitionClient; import com.google.android.gms.location.DetectedActivity; -import com.google.android.gms.location.LocationListener; +import com.google.android.gms.location.LocationCallback; +import com.google.android.gms.location.LocationResult; import com.google.android.maps.mytracks.R; import com.google.common.annotations.VisibleForTesting; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.database.sqlite.SQLiteException; -import android.location.Location; -import android.location.LocationManager; -import android.net.Uri; -import android.os.Binder; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.PowerManager.WakeLock; -import android.os.Process; -import android.support.v4.app.NotificationCompat; -import android.support.v4.app.TaskStackBuilder; -import android.util.Log; - import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -119,8 +121,6 @@ public class TrackRecordingService extends Service { private MyTracksProviderUtils myTracksProviderUtils; private Handler handler; private MyTracksLocationManager myTracksLocationManager; - private PendingIntent activityRecognitionPendingIntent; - private ActivityRecognitionClient activityRecognitionClient; private PeriodicTaskExecutor voiceExecutor; private PeriodicTaskExecutor splitExecutor; private SharedPreferences sharedPreferences; @@ -238,43 +238,25 @@ public class TrackRecordingService extends Service { } }; - private LocationListener locationListener = new LocationListener() { - @Override - public void onLocationChanged(final Location location) { - if (myTracksLocationManager == null || executorService == null - || !myTracksLocationManager.isAllowed() || executorService.isShutdown() - || executorService.isTerminated()) { - return; + private LocationCallback locationListener = new LocationCallback() { + + public void onLocationResult(final LocationResult locationResult) { + if (myTracksLocationManager == null || executorService == null + || !myTracksLocationManager.isAllowed() || executorService.isShutdown() + || executorService.isTerminated()) { + return; + } + executorService.submit(new Runnable() { + @Override + public void run() { + onLocationChangedAsync(locationResult.getLastLocation()); + } + }); } - executorService.submit(new Runnable() { - @Override - public void run() { - onLocationChangedAsync(location); - } - }); - } }; - private final ConnectionCallbacks activityRecognitionCallbacks = new ConnectionCallbacks() { - @Override - public void onDisconnected() {} - - @Override - public void onConnected(Bundle bundle) { - activityRecognitionClient.requestActivityUpdates( - ONE_MINUTE, activityRecognitionPendingIntent); - } - }; - - private final OnConnectionFailedListener - activityRecognitionFailedListener = new OnConnectionFailedListener() { - - @Override - public void onConnectionFailed(ConnectionResult connectionResult) {} - }; - private final Runnable registerLocationRunnable = new Runnable() { - @Override + @Override public void run() { if (isRecording() && !isPaused()) { registerLocationListener(); @@ -298,12 +280,6 @@ public class TrackRecordingService extends Service { myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this); handler = new Handler(); myTracksLocationManager = new MyTracksLocationManager(this, handler.getLooper(), true); - activityRecognitionPendingIntent = PendingIntent.getService(context, 0, - new Intent(context, ActivityRecognitionIntentService.class), - PendingIntent.FLAG_UPDATE_CURRENT); - activityRecognitionClient = new ActivityRecognitionClient( - context, activityRecognitionCallbacks, activityRecognitionFailedListener); - activityRecognitionClient.connect(); voiceExecutor = new PeriodicTaskExecutor(this, new AnnouncementPeriodicTaskFactory()); splitExecutor = new PeriodicTaskExecutor(this, new SplitPeriodicTaskFactory()); sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE); @@ -390,12 +366,6 @@ public class TrackRecordingService extends Service { } finally { voiceExecutor = null; } - - if (activityRecognitionClient.isConnected()) { - activityRecognitionClient.removeActivityUpdates(activityRecognitionPendingIntent); - } - activityRecognitionClient.disconnect(); - activityRecognitionPendingIntent.cancel(); myTracksLocationManager.close(); myTracksLocationManager = null; @@ -621,8 +591,6 @@ public class TrackRecordingService extends Service { // Update shared preferences updateRecordingState(trackId, false); PreferencesUtils.setInt(this, R.string.auto_resume_track_current_retry_key, 0); - PreferencesUtils.setInt(this, R.string.activity_recognition_type_key, - PreferencesUtils.ACTIVITY_RECOGNITION_TYPE_DEFAULT); // Update database track.setId(trackId); @@ -1311,7 +1279,7 @@ public class TrackRecordingService extends Service { if (!canAccess()) { return; } - trackRecordingService.locationListener.onLocationChanged(location); + //TODO trackRecordingService.locationListener.onLocationChanged(location); } @Override diff --git a/myTracksLib/build.gradle b/myTracksLib/build.gradle index 75d4921e9..dcfc2d8dc 100644 --- a/myTracksLib/build.gradle +++ b/myTracksLib/build.gradle @@ -4,7 +4,7 @@ android { compileSdkVersion 26 defaultConfig { - minSdkVersion 14 + minSdkVersion 21 targetSdkVersion 26 }