diff --git a/app/app.iml b/app/app.iml index ea171ad..2db12ae 100644 --- a/app/app.iml +++ b/app/app.iml @@ -88,6 +88,10 @@ + + + + @@ -111,7 +115,10 @@ + + + @@ -126,6 +133,7 @@ + diff --git a/app/build.gradle b/app/build.gradle index 392afb7..0dcef11 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,6 +24,7 @@ testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.2.1' compile 'com.android.support:design:23.2.1' + compile 'com.google.android.gms:play-services-location:8.4.0' compile 'com.survivingwithandroid:weatherlib:1.6.0' compile 'com.survivingwithandroid:weatherlib_okhttpclient:1.6.0' compile 'com.squareup.okhttp:okhttp:2.0.+' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b8fd3d9..b42201a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,9 +17,12 @@ android:allowBackup="true" android:icon="@mipmap/ic_icon" android:label="@string/app_title" - android:hardwareAccelerated="false" + android:hardwareAccelerated="true" android:supportsRtl="true" android:theme="@style/AppTheme" > + + diff --git a/app/src/main/java/de/apps4ics/mountainnavigation/LocationService.java b/app/src/main/java/de/apps4ics/mountainnavigation/LocationService.java new file mode 100644 index 0000000..0fc5c1d --- /dev/null +++ b/app/src/main/java/de/apps4ics/mountainnavigation/LocationService.java @@ -0,0 +1,143 @@ +/** + * This file is part of MountainNavigation. + * + * MountainNavigation is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MountainNavigation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MountainNavigation. If not, see . + * + * @copyright Copyright (c) 2016 Vinzenz Rosenkanz + * + * @author Vinzenz Rosenkranz + */ + +package de.apps4ics.mountainnavigation; + +import android.Manifest; +import android.app.Service; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.location.Location; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.ActivityCompat; +import android.util.Log; + +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.location.LocationRequest; +import com.google.android.gms.location.LocationServices; + +import java.util.Timer; +import java.util.TimerTask; + + +public class LocationService extends Service implements com.google.android.gms.location.LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { + private static final int GPS_MIN_TIME = 5000; + private static final int GPS_MIN_DIST = 10; + private GoogleApiClient mGoogleApiClient; + private LocationRequest mLocationRequest; + private LocationUpdateCallback locationCallback; + private int instances; + + private Timer timer; + + private final IBinder binder = new MyBinder(); + + public void setLocationCallback(LocationUpdateCallback locationCallback) { + this.locationCallback = locationCallback; + } + + @Override + public void onCreate() { + super.onCreate(); + Log.d(MainActivity.TAG, "Creating..."); + instances = 0; + mGoogleApiClient = new GoogleApiClient.Builder(this) + .addApi(LocationServices.API) + .addConnectionCallbacks(this) + .addOnConnectionFailedListener(this) + .build(); + mGoogleApiClient.connect(); + timer = new Timer(); + } + + @Override + public int onStartCommand(final Intent intent, int flags, int startId) { + Log.d(MainActivity.TAG, "StartCommand..."); + instances++; + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + Log.d(MainActivity.TAG, "Starting timer..." + instances); + } + }, 0, GPS_MIN_TIME); + return Service.START_STICKY; + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + Log.d(MainActivity.TAG, "onBind..."); + return binder; + } + + @Override + public void onConnected(@Nullable Bundle bundle) { + mLocationRequest = LocationRequest.create(); + mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); + mLocationRequest.setInterval(GPS_MIN_TIME); + mLocationRequest.setSmallestDisplacement(GPS_MIN_DIST); + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + // TODO: Consider calling + // ActivityCompat#requestPermissions + // here to request the missing permissions, and then overriding + // public void onRequestPermissionsResult(int requestCode, String[] permissions, + // int[] grantResults) + // to handle the case where the user grants the permission. See the documentation + // for ActivityCompat#requestPermissions for more details. + return; + } + LocationServices.FusedLocationApi.requestLocationUpdates( + mGoogleApiClient, mLocationRequest, this); + } + + @Override + public void onConnectionSuspended(int i) { + Log.d(MainActivity.TAG, "LOCATION suspended"); + } + + @Override + public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { + Log.d(MainActivity.TAG, "LOCATION connection failed"); + } + + @Override + public void onLocationChanged(Location location) { + Log.d(MainActivity.TAG, "LOCATION found: " + location.toString()); + locationCallback.onLocationUpdate(location); + } + + @Override + public void onDestroy() { + super.onDestroy(); + mGoogleApiClient.disconnect(); + } + + public class MyBinder extends Binder { + LocationService getService() { + return LocationService.this; + } + } +} diff --git a/app/src/main/java/de/apps4ics/mountainnavigation/LocationUpdateCallback.java b/app/src/main/java/de/apps4ics/mountainnavigation/LocationUpdateCallback.java new file mode 100644 index 0000000..731d971 --- /dev/null +++ b/app/src/main/java/de/apps4ics/mountainnavigation/LocationUpdateCallback.java @@ -0,0 +1,28 @@ +/** + * This file is part of MountainNavigation. + * + * MountainNavigation is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MountainNavigation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MountainNavigation. If not, see . + * + * @copyright Copyright (c) 2016 Vinzenz Rosenkanz + * + * @author Vinzenz Rosenkranz + */ + +package de.apps4ics.mountainnavigation; + +import android.location.Location; + +public interface LocationUpdateCallback { + void onLocationUpdate(Location location); +} diff --git a/app/src/main/java/de/apps4ics/mountainnavigation/MainActivity.java b/app/src/main/java/de/apps4ics/mountainnavigation/MainActivity.java index 72c6c28..23e685e 100644 --- a/app/src/main/java/de/apps4ics/mountainnavigation/MainActivity.java +++ b/app/src/main/java/de/apps4ics/mountainnavigation/MainActivity.java @@ -22,22 +22,24 @@ package de.apps4ics.mountainnavigation; import android.app.AlertDialog; +import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.res.Resources; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.location.Criteria; import android.location.Location; -import android.location.LocationListener; import android.location.LocationManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.WifiManager; +import android.os.IBinder; +import android.os.PowerManager; import android.preference.PreferenceManager; import android.provider.Settings; import android.support.design.widget.FloatingActionButton; @@ -101,7 +103,7 @@ import de.apps4ics.mountainnavigation.pois.Poi; import de.apps4ics.mountainnavigation.pois.Types; -public class MainActivity extends AppCompatActivity implements LocationListener, OnSingleWeatherRetrieved { +public class MainActivity extends AppCompatActivity implements OnSingleWeatherRetrieved, LocationUpdateCallback { public static final String TAG = "MountainNavigation"; /** @@ -116,11 +118,14 @@ private static final int MIN_WEATHER_RELOAD_DIST = 5000; //5km, in m private static final int MIN_POI_RELOAD_TIME = 300000; //5min, in ms private static final int MIN_POI_RELOAD_DIST = 500; //0.5km, in m + private long lastWeatherInformation; + private long lastPoiInformation; private static int MAX_POIS_AROUND = 50; public static final int MAX_WIFI_LEVELS = 5; private static ConnectivityManager cm; private static TelephonyManager tm; private static WifiManager wm; + private static PowerManager pm; private static NetworkInfo activeNetwork; private static int networkStrength; @@ -137,9 +142,6 @@ private static WeatherHandler weatherHandler; private static HikeHandler hikeHandler; - private long lastWeatherInformation; - private long lastPoiInformation; - private static MapView mapView; private IMapController mapController; public static int ZOOM_LEVEL; @@ -165,6 +167,23 @@ private static List foundLocations; + private LocationService locationService; + private ServiceConnection serviceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + Log.d(TAG, "onServiceConnected"); + LocationService.MyBinder binder = (LocationService.MyBinder) service; + locationService = binder.getService(); + locationService.setLocationCallback(MainActivity.this); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + Log.d(TAG, "onServiceDisconnected"); + locationService = null; + } + }; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -179,6 +198,7 @@ tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); tm.listen(new MyPhoneStateListener(), PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); wm = (WifiManager) getSystemService(WIFI_SERVICE); + pm = (PowerManager) getSystemService(POWER_SERVICE); sharedPrefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this); @@ -754,9 +774,6 @@ Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivity(intent); } - Criteria criteria = new Criteria(); - provider = locationManager.getBestProvider(criteria, false); - mLocation = locationManager.getLastKnownLocation(provider); } private void Toaster(String text){ @@ -825,59 +842,6 @@ } @Override - public void onLocationChanged(Location location) { - if(mLocation != null) { - Location oldLocation = new Location(mLocation); - long currentTime = System.currentTimeMillis(); - float distance = mLocation.distanceTo(oldLocation); - - if(currentTime - lastWeatherInformation >= MIN_WEATHER_RELOAD_TIME || distance >= MIN_WEATHER_RELOAD_DIST) { - lastWeatherInformation = currentTime; - weatherHandler.getCurrentWeather(location, this); - } - if(currentTime - lastPoiInformation >= MIN_POI_RELOAD_TIME || distance >= MIN_POI_RELOAD_DIST) { //5 minutes - lastPoiInformation = currentTime; - ArrayList pois = new ArrayList<>(poiHandler.getPoisAround(location.getLatitude(), location.getLongitude(), MAX_POIS_AROUND)); - Log.d(TAG, "found " + pois.size() + " pois."); - for(Poi p : pois) { - p.display(); - } - } - } - mLocation = location; - if(mLocation == null) return; - foundLocations.add(location); - - if(hikeHandler.isRecording()) hikeHandler.addLocation(mLocation); - - double lat = location.getLatitude(); - double lon = location.getLongitude(); - GeoPoint gp = new GeoPoint(lat, lon); - - mapView.getOverlays().remove(currentPosition); - currentPosition.setPosition(gp); - currentPosition.setSnippet(String.format(getString(R.string.osm_marker_snippet), gp.getLatitude(), gp.getLongitude(), gp.getAltitude(), 0)); - mapView.getOverlays().add(currentPosition); - mapView.invalidate(); - mapController.setCenter(gp); - } - - @Override - public void onStatusChanged(String provider, int status, Bundle extras) { - Log.d(TAG, "onStatusChanged: " + provider + ", " + status); - } - - @Override - public void onProviderEnabled(String provider) { - Log.d(TAG, "onProviderEnabled: " + provider); - } - - @Override - public void onProviderDisabled(String provider) { - Log.d(TAG, "onProviderDisabled: " + provider); - } - - @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); drawerToggle.syncState(); @@ -923,6 +887,45 @@ } @Override + public void onLocationUpdate(Location location) { + Log.d(TAG, "isInteractive? " + pm.isInteractive()); + if(mLocation != null && pm.isInteractive()) { + Location oldLocation = new Location(mLocation); + long currentTime = System.currentTimeMillis(); + float distance = mLocation.distanceTo(oldLocation); + + if(currentTime - lastWeatherInformation >= MIN_WEATHER_RELOAD_TIME || distance >= MIN_WEATHER_RELOAD_DIST) { + lastWeatherInformation = currentTime; + weatherHandler.getCurrentWeather(location, this); + } + if(currentTime - lastPoiInformation >= MIN_POI_RELOAD_TIME || distance >= MIN_POI_RELOAD_DIST) { //5 minutes + lastPoiInformation = currentTime; + ArrayList pois = new ArrayList<>(poiHandler.getPoisAround(location.getLatitude(), location.getLongitude(), MAX_POIS_AROUND)); + Log.d(MainActivity.TAG, "found " + pois.size() + " pois."); + for(Poi p : pois) { + p.display(); + } + } + } + mLocation = location; + if(mLocation == null) return; + foundLocations.add(location); + + if(hikeHandler.isRecording()) hikeHandler.addLocation(mLocation); + + double lat = location.getLatitude(); + double lon = location.getLongitude(); + GeoPoint gp = new GeoPoint(lat, lon); + + mapView.getOverlays().remove(currentPosition); + currentPosition.setPosition(gp); + currentPosition.setSnippet(String.format(getString(R.string.osm_marker_snippet), gp.getLatitude(), gp.getLongitude(), gp.getAltitude(), 0)); + mapView.getOverlays().add(currentPosition); + mapView.invalidate(); + mapController.setCenter(gp); + } + + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch(requestCode){ @@ -950,18 +953,25 @@ protected void onResume() { super.onResume(); weatherHandler = new WeatherHandler(this); - locationManager.requestLocationUpdates(provider, GPS_MIN_TIME, GPS_MIN_DIST, this); + Intent service = new Intent(this, LocationService.class); + bindService(service, serviceConnection, Context.BIND_AUTO_CREATE); + startService(service); } @Override protected void onPause() { super.onPause(); - locationManager.removeUpdates(this); + } + + @Override + protected void onStop() { + super.onStop(); } @Override protected void onDestroy() { super.onDestroy(); + unbindService(serviceConnection); } @Override