package org.osmdroid.samplefragments.location; import android.app.Activity; import android.content.Context; import android.content.pm.ActivityInfo; import android.hardware.GeomagneticField; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.Surface; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.TextView; import org.osmdroid.R; import org.osmdroid.samplefragments.BaseSampleFragment; 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.MyLocationNewOverlay; /** * An example on setting the device's "up" based on heading, bearing, or compass * Created by alex on 4/30/16. */ public class SampleHeadingCompassUp extends BaseSampleFragment implements LocationListener, IOrientationConsumer { int deviceOrientation = 0; MyLocationNewOverlay overlay = null; IOrientationProvider compass = null; float gpsspeed; float gpsbearing; TextView textViewCurrentLocation = null; float lat = 0; float lon = 0; float alt = 0; long timeOfFix = 0; String screen_orientation = ""; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.map_with_locationbox, container, false); mMapView = (MapView) root.findViewById(R.id.mapview); textViewCurrentLocation = (TextView) root.findViewById(R.id.textViewCurrentLocation); return root; } @Override public String getSampleTitle() { return "Heading/Compass Up"; } @Override public void addOverlays() { overlay = new MyLocationNewOverlay(mMapView); overlay.setEnableAutoStop(false); overlay.enableFollowLocation(); overlay.enableMyLocation(); this.mMapView.getOverlayManager().add(overlay); } @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) getActivity().getSystemService( Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation(); switch (rotation) { case Surface.ROTATION_0: orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; this.deviceOrientation = 0; screen_orientation = "ROTATION_0 SCREEN_ORIENTATION_PORTRAIT"; break; case Surface.ROTATION_90: this.deviceOrientation = 90; orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; screen_orientation = "ROTATION_90 SCREEN_ORIENTATION_LANDSCAPE"; break; case Surface.ROTATION_180: this.deviceOrientation = 180; orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; screen_orientation = "ROTATION_180 SCREEN_ORIENTATION_REVERSE_PORTRAIT"; break; default: this.deviceOrientation = 270; orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; screen_orientation = "ROTATION_270 SCREEN_ORIENTATION_REVERSE_LANDSCAPE"; break; } getActivity().setRequestedOrientation(orientation); } LocationManager lm = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE); try { //on API15 AVDs,network provider fails. no idea why lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, (LocationListener) this); lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, (LocationListener) this); } catch (Exception ex) { } compass = new InternalCompassOrientationProvider(getActivity()); compass.startOrientationProvider(this); mMapView.getController().zoomTo(16); } @Override public void onPause() { super.onPause(); compass.stopOrientationProvider(); LocationManager lm = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE); try { lm.removeUpdates(this); } catch (Exception ex) { } //unlock the orientation getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); } @Override public void onDestroyView() { super.onDestroyView(); compass.destroy(); overlay.disableMyLocation(); overlay.disableFollowLocation(); overlay.onDetach(mMapView); if (mMapView != null) mMapView.onDetach(); mMapView = null; overlay = null; compass = null; textViewCurrentLocation = null; } @Override public void onLocationChanged(Location location) { if (mMapView == null) return; gpsbearing = location.getBearing(); gpsspeed = location.getSpeed(); lat = (float) location.getLatitude(); lon = (float) location.getLongitude(); alt = (float) location.getAltitude(); //meters timeOfFix = location.getTime(); //use gps bearing instead of the compass float t = (360 - gpsbearing - this.deviceOrientation); if (t < 0) { t += 360; } if (t > 360) { t -= 360; } //help smooth everything out t = (int) t; t = t / 5; t = (int) t; t = t * 5; if (gpsspeed >= 0.01) { mMapView.setMapOrientation(t); //otherwise let the compass take over } updateDisplay(location.getBearing(), true); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } Float trueNorth = 0f; @Override public void onOrientationChanged(final float orientationToMagneticNorth, IOrientationProvider source) { //note, on devices without a compass this never fires... //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; mMapView.setMapOrientation(t); updateDisplay(actualHeading,false); } } } private void updateDisplay(final float bearing, boolean isGps) { try { Activity act = getActivity(); if (act != null) act.runOnUiThread(new Runnable() { @Override public void run() { if (getActivity() != null && textViewCurrentLocation != null) { textViewCurrentLocation.setText("GPS Speed: " + gpsspeed + "m/s GPS Bearing: " + gpsbearing + "\nDevice Orientation: " + (int) deviceOrientation + " Compass heading: " + (int) bearing + "\n" + "True north: " + trueNorth.intValue() + " Map Orientation: " + (int) mMapView.getMapOrientation() + "\n" + screen_orientation); } } }); } catch (Exception ex) { ex.printStackTrace(); } Log.i(TAG,isGps + ","+gpsspeed + "," + gpsbearing + "," + deviceOrientation + "," + bearing + "," + trueNorth.intValue() + "," + mMapView.getMapOrientation() + "," + screen_orientation); } }