From 645f21b4b3e5557ef23f825f3e76bf6d9e366709 Mon Sep 17 00:00:00 2001 From: Geoffrey POUZET Date: Thu, 2 Aug 2018 16:43:13 +0200 Subject: [PATCH] Orientate the map to fit the current orientation. --- .../mytrackingdog/MainActivity.java | 169 ++++++++++++++---- .../mytrackingdog/services/ServiceGps.java | 26 ++- 2 files changed, 163 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/fr/chteufleur/mytrackingdog/MainActivity.java b/app/src/main/java/fr/chteufleur/mytrackingdog/MainActivity.java index 70dcd2c..9e2403d 100644 --- a/app/src/main/java/fr/chteufleur/mytrackingdog/MainActivity.java +++ b/app/src/main/java/fr/chteufleur/mytrackingdog/MainActivity.java @@ -2,17 +2,19 @@ package fr.chteufleur.mytrackingdog; import android.Manifest; import android.content.Context; +import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; +import android.hardware.GeomagneticField; +import android.location.Location; import android.location.LocationManager; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.annotation.RequiresApi; import android.support.v7.app.AppCompatActivity; -import android.util.DisplayMetrics; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; +import android.view.Surface; import android.view.WindowManager; import android.widget.Toast; @@ -21,21 +23,32 @@ import org.osmdroid.config.Configuration; import org.osmdroid.tileprovider.tilesource.TileSourceFactory; import org.osmdroid.util.GeoPoint; import org.osmdroid.views.MapView; +import org.osmdroid.views.overlay.compass.IOrientationConsumer; +import org.osmdroid.views.overlay.compass.IOrientationProvider; +import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider; import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider; import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay; +import java.util.Observable; +import java.util.Observer; + import fr.chteufleur.mytrackingdog.services.IServiceGps; import fr.chteufleur.mytrackingdog.services.ServiceGps; -public class MainActivity extends AppCompatActivity { +public class MainActivity extends AppCompatActivity implements IOrientationConsumer, Observer { public static final String TAG = "MainActivity"; private MyLocationNewOverlay mLocationOverlay; + private IOrientationProvider compass = null; private IServiceGps serviceGps = null; - Context ctx = null; - MapView map = null; + private Context ctx = null; + private MapView map = null; + + private Float trueNorth = 0f; + private int deviceOrientation = 0; + private boolean zoomed = false; private final int REQUEST_CODE_ASK_PERMISSION = 123; @@ -70,20 +83,9 @@ public class MainActivity extends AppCompatActivity { checkPermissions(); } - if (serviceGps == null) { - serviceGps = new ServiceGps(); - } - //load/initialize the osmdroid configuration, this can be done ctx = getApplicationContext(); Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(ctx)); - //setting this before the layout is inflated is a good idea - //it 'should' ensure that the map has a writable location for the map cache, even without permissions - //if no tiles are displayed, you can try overriding the cache path using Configuration.getInstance().setCachePath - //see also StorageUtils - //note, the load method also sets the HTTP User Agent to your application's package name, abusing osm's tile servers will get you banned based on this string - - //inflate and create the map setContentView(R.layout.main); // Keep screen ON @@ -102,50 +104,92 @@ public class MainActivity extends AppCompatActivity { GeoPoint startPoint = new GeoPoint(45.0000, 5.0000); mapController.setCenter(startPoint); - - final DisplayMetrics dm = ctx.getResources().getDisplayMetrics(); + // Current position on the map this.mLocationOverlay = new MyLocationNewOverlay(new GpsMyLocationProvider(ctx), map); map.getOverlays().add(this.mLocationOverlay); mLocationOverlay.enableMyLocation(); mLocationOverlay.enableFollowLocation(); mLocationOverlay.setOptionsMenuEnabled(true); + + if (serviceGps == null) { + serviceGps = new ServiceGps(); + ((Observable) serviceGps).addObserver(this); + } } + @Override public void onResume(){ super.onResume(); + //hack for x86 + if (!"Android-x86".equalsIgnoreCase(Build.BRAND)) { + //lock the device in current screen orientation + int orientation; + int rotation = ((WindowManager) getSystemService( + Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation(); + switch (rotation) { + case Surface.ROTATION_0: + orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; + this.deviceOrientation = 0; + break; + case Surface.ROTATION_90: + this.deviceOrientation = 90; + orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; + break; + case Surface.ROTATION_180: + this.deviceOrientation = 180; + orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; + break; + default: + this.deviceOrientation = 270; + orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; + break; + } + + setRequestedOrientation(orientation); + } + ((ServiceGps) serviceGps).setLocationManager((LocationManager) getSystemService(ctx.LOCATION_SERVICE)); serviceGps.start(); mLocationOverlay.enableFollowLocation(); mLocationOverlay.enableMyLocation(); - //this will refresh the osmdroid configuration on resuming. - //if you make changes to the configuration, use - //SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - //Configuration.getInstance().load(this, PreferenceManager.getDefaultSharedPreferences(this)); + if (compass == null) { + compass = new InternalCompassOrientationProvider(this); + } + compass.startOrientationProvider(this); + if (map != null) { - map.onResume(); //needed for compass, my location overlays, v6.0.0 and up + map.onResume(); } } + @Override public void onPause(){ super.onPause(); + pause(); + } - mLocationOverlay.disableFollowLocation(); - mLocationOverlay.disableMyLocation(); - - //this will refresh the osmdroid configuration on resuming. - //if you make changes to the configuration, use - //SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - //Configuration.getInstance().save(this, prefs); + private void pause() { + if (compass != null) { + compass.stopOrientationProvider(); + compass.destroy(); + compass = null; + } + if (mLocationOverlay != null) { + mLocationOverlay.disableFollowLocation(); + mLocationOverlay.disableMyLocation(); + } if (map != null) { - map.onPause(); //needed for compass, my location overlays, v6.0.0 and up + map.onPause(); } } + @Override public void onBackPressed() { super.onBackPressed(); + pause(); if (serviceGps != null) { serviceGps.stop(); } @@ -187,4 +231,67 @@ public class MainActivity extends AppCompatActivity { break; } } + + + @Override + public void onOrientationChanged(float orientationToMagneticNorth, IOrientationProvider source) { + //note, on devices without a compass this never fires... + Location location = ((ServiceGps) serviceGps).getCurrentLocation(); + if (location == null) { + return ; + } + + float gpsspeed = location.getSpeed(); + float lat = (float) location.getLatitude(); + float lon = (float) location.getLongitude(); + float alt = (float) location.getAltitude(); + long timeOfFix = location.getTime(); + + //only use the compass bit if we aren't moving, since gps is more accurate when we are moving + if (gpsspeed < 0.01) { + GeomagneticField gf = new GeomagneticField(lat, lon, alt, timeOfFix); + trueNorth = orientationToMagneticNorth + gf.getDeclination(); + gf = null; + synchronized (trueNorth) { + if (trueNorth > 360.0f) { + trueNorth = trueNorth - 360.0f; + } + float actualHeading = 0f; + + //this part adjusts the desired map rotation based on device orientation and compass heading + float t = (360 - trueNorth - this.deviceOrientation); + if (t < 0) { + t += 360; + } + if (t > 360) { + t -= 360; + } + actualHeading = t; + //help smooth everything out + t = (int) t; + t = t / 5; + t = (int) t; + t = t * 5; + map.setMapOrientation(t); + if (!zoomed) { + IMapController mapController = map.getController(); + mapController.setZoom(20.0); + zoomed = true; + } + } + } + } + + + @Override + public void update(Observable observable, Object o) { + if (observable == serviceGps) { + if (o instanceof String && (String) o == ServiceGps.NOTIF_NEW_LOCATION) { + float orientation = ((ServiceGps) serviceGps).getOrientation(deviceOrientation); + if (orientation >= 0) { + map.setMapOrientation(orientation); + } + } + } + } } diff --git a/app/src/main/java/fr/chteufleur/mytrackingdog/services/ServiceGps.java b/app/src/main/java/fr/chteufleur/mytrackingdog/services/ServiceGps.java index 2c20562..a04780f 100644 --- a/app/src/main/java/fr/chteufleur/mytrackingdog/services/ServiceGps.java +++ b/app/src/main/java/fr/chteufleur/mytrackingdog/services/ServiceGps.java @@ -6,11 +6,15 @@ import android.location.LocationManager; import android.os.Bundle; import android.util.Log; +import java.util.Observable; + import fr.chteufleur.mytrackingdog.MainActivity; -public class ServiceGps implements IServiceGps, LocationListener { +public class ServiceGps extends Observable implements IServiceGps, LocationListener { private static final String TAG = "ServiceGps"; + public static final String NOTIF_NEW_LOCATION = "fr.chteufleur.mytrackingdog.services.servicegps.newlocation"; + private LocationManager locationManager; private Location currentLocation = null; @@ -22,6 +26,24 @@ public class ServiceGps implements IServiceGps, LocationListener { return currentLocation; } + public float getOrientation(int deviceOrientation) { + float ret = -1; + if (currentLocation != null && currentLocation.getSpeed() >= 0.01) { + ret = (360 - currentLocation.getBearing() - deviceOrientation); + if (ret < 0) { + ret += 360; + } + if (ret > 360) { + ret -= 360; + } + //help smooth everything out + ret = (int) ret; + ret = ret / 5; + ret = (int) ret; + ret = ret * 5; + } + return ret; + } @Override public void start() { @@ -41,6 +63,8 @@ public class ServiceGps implements IServiceGps, LocationListener { @Override public void onLocationChanged(Location location) { currentLocation = location; + setChanged(); + notifyObservers(NOTIF_NEW_LOCATION); } @Override