/* Copyright 2012 Nik Cain nik@showmehills.com This file is part of ShowMeHills. ShowMeHills 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. ShowMeHills 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 ShowMeHills. If not, see <http://www.gnu.org/licenses/>. */ package com.showmehills; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import android.content.Context; import android.content.Intent; import android.database.SQLException; import android.graphics.Matrix; import android.graphics.drawable.Drawable; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.location.Location; import android.location.LocationManager; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapActivity; import com.google.android.maps.MapController; import com.google.android.maps.MapView; import com.google.android.maps.Overlay; import com.google.android.maps.OverlayItem; import com.showmehills.R; public class MapOverlay extends MapActivity implements IShowMeHillsActivity, SensorEventListener { private HillDatabase myDbHelper; private Location curLocation; MapOverlayCompassItem compassOverlay; private RapidGPSLock mGPS; private SensorManager mSensorManager; Sensor accelerometer; Sensor magnetometer; float[] mGravity; float[] mGeomagnetic; float mDeclination = 0; int minLat = 0; int maxLat = 0; int minLon = 0; int maxLon = 0; private boolean mHasAccurateGravity = false; private boolean mHasAccurateAccelerometer = false; Timer timer = new Timer(); private int GPSretryTime = 15; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE); accelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); magnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME); mSensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_GAME); mGPS = new RapidGPSLock(this); mGPS.switchOn(); mGPS.findLocation(); myDbHelper = new HillDatabase(this, getString(R.string.dbname), getString(R.string.dbpath)); myDbHelper.createDataBase(); setContentView(R.layout.mapoverlay); MapView mapView = (MapView) findViewById(R.id.mapview); mapView.setBuiltInZoomControls(true); UpdateMarkers(); MapController mc = mapView.getController(); double fitFactor = 1.5; mc.zoomToSpan((int) (Math.abs(maxLat - minLat) * fitFactor), (int)(Math.abs(maxLon - minLon) * fitFactor)); mc.animateTo(new GeoPoint( (maxLat + minLat)/2, (maxLon + minLon)/2 )); timer.scheduleAtFixedRate(new LocationTimerTask(),GPSretryTime* 1000,GPSretryTime* 1000); } @Override protected void onResume() { Log.d("showmehills", "onResume"); super.onResume(); mGPS.switchOn(); mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME); mSensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_GAME); timer = new Timer(); timer.scheduleAtFixedRate(new LocationTimerTask(),GPSretryTime* 1000,GPSretryTime* 1000); UpdateMarkers(); myDbHelper.checkDataBase(); } @Override protected void onPause() { Log.d("showmehills", "onPause"); super.onPause(); timer.cancel(); mGPS.switchOff(); mSensorManager.unregisterListener(this); try { myDbHelper.close(); }catch(SQLException sqle){ throw sqle; } } @Override protected void onStop() { try { myDbHelper.close(); }catch(SQLException sqle){ throw sqle; } super.onStop(); } public void UpdateMarkers() { curLocation = mGPS.getCurrentLocation(); if (curLocation == null) return; if (!myDbHelper.checkDataBase()) return; myDbHelper.SetDirections(curLocation); MapView mapView = (MapView) findViewById(R.id.mapview); List<Overlay> mapOverlays = mapView.getOverlays(); mapOverlays.clear(); Drawable barrw = this.getResources().getDrawable(R.drawable.bluearrow); compassOverlay = new MapOverlayCompassItem(barrw, this); OverlayItem compassitem = new OverlayItem(new GeoPoint((int)(curLocation.getLatitude()*1E6),(int)(curLocation.getLongitude()*1E6)), "me","me"); compassOverlay.addOverlay(compassitem); mapOverlays.add(compassOverlay); Drawable drawable = this.getResources().getDrawable(R.drawable.androidmarker); minLat = (int) ((curLocation.getLatitude() - 0.01)*1E6); maxLat = (int) ((curLocation.getLatitude() + 0.01)*1E6); minLon = (int) ((curLocation.getLongitude() - 0.01)*1E6); maxLon = (int) ((curLocation.getLongitude() + 0.01)*1E6); Log.d("showmehills", "map lon-lat = " + minLat + "," + minLon); ArrayList<Hills> localhills = myDbHelper.localhills; for (int h = 0; h < localhills.size(); h++) { Hills h1 = localhills.get(h); Log.d("showmehills", "adding " + h1.hillname); GeoPoint point = new GeoPoint((int)(h1.latitude*1E6),(int)(h1.longitude*1E6)); OverlayItem overlayitem = new OverlayItem(point, h1.hillname, h1.hillname); MapOverlayItem itemizedoverlay = new MapOverlayItem(drawable, this); itemizedoverlay.addOverlay(overlayitem); mapOverlays.add(itemizedoverlay); maxLat = Math.max(point.getLatitudeE6(), maxLat); minLat = Math.min(point.getLatitudeE6(), minLat); maxLon = Math.max(point.getLongitudeE6(), maxLon); minLon = Math.min(point.getLongitudeE6(), minLon); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate menu from XML resource MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.mappreferences_menu, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.preferences_menutitem) { Intent settingsActivity = new Intent(getBaseContext(),AppPreferences.class); startActivity(settingsActivity); } else if (item.getItemId() == R.id.cameraview) { finish(); } else if (item.getItemId() == R.id.help) { Intent myHelpIntent = new Intent(getBaseContext(), Help.class); startActivityForResult(myHelpIntent, 0); } else if (item.getItemId() == R.id.about) { Intent myAboutIntent = new Intent(getBaseContext(), About.class); startActivityForResult(myAboutIntent, 0); } return super.onOptionsItemSelected(item); } @Override protected boolean isRouteDisplayed() { return false; } public void onAccuracyChanged(Sensor sensor, int accuracy) { } public void onSensorChanged(SensorEvent event) { // some phones never set the sensormanager as reliable, even when readings are ok // That means if we try to block it, those phones will never get a compass reading. // So we let any readings through until we know we can get accurate readings. Once We know that // we'll block the inaccurate ones if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) { if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER && mHasAccurateAccelerometer) return; if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD && mHasAccurateGravity) return; } else { if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) mHasAccurateAccelerometer = true; if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) mHasAccurateGravity = true; } if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) mGravity = event.values; if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) mGeomagnetic = event.values; if (mGravity != null && mGeomagnetic != null) { float[] rotationMatrixA = new float[9]; if (SensorManager.getRotationMatrix(rotationMatrixA, null, mGravity, mGeomagnetic)) { Matrix tmpA = new Matrix(); tmpA.setValues(rotationMatrixA); tmpA.postRotate( -mDeclination ); tmpA.getValues(rotationMatrixA); float[] dv = new float[3]; SensorManager.getOrientation(rotationMatrixA, dv); if (compassOverlay != null && compassOverlay.size() > 0) { compassOverlay.mBearing = (float) Math.toDegrees((float)dv[0]); MapView mapView = (MapView) findViewById(R.id.mapview); mapView.invalidate(); } } } } public LocationManager GetLocationManager() { return (LocationManager)getSystemService(Context.LOCATION_SERVICE); } class LocationTimerTask extends TimerTask { @Override public void run() { Log.d("showmehills", "renew GPS search"); runOnUiThread(new Runnable() { public void run() { mGPS.RenewLocation(); } }); } } }