/* * Geopaparazzi - Digital field mapping on Android based devices * Copyright (C) 2010 HydroloGIS (www.hydrologis.com) * * This program 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. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package eu.geopaparazzi.library.gps; import static eu.geopaparazzi.library.util.LibraryConstants.GPS_LOGGING_DISTANCE; import static eu.geopaparazzi.library.util.LibraryConstants.GPS_LOGGING_INTERVAL; import static eu.geopaparazzi.library.util.LibraryConstants.PREFS_KEY_GPSLOGGINGDISTANCE; import static eu.geopaparazzi.library.util.LibraryConstants.PREFS_KEY_GPSLOGGINGINTERVAL; import java.io.IOException; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteFullException; import android.location.GpsStatus; import android.location.Location; import android.os.Bundle; import android.os.SystemClock; import android.preference.PreferenceManager; import android.widget.Toast; import eu.geopaparazzi.library.R; import eu.geopaparazzi.library.database.GPLog; import eu.geopaparazzi.library.util.Utilities; /** * The Gps engine, used to put logs into the database. * * <p>This class takes care to make the logging occur at preferences settings. * That is why it is not listening directly to the gps, but instead to the gps manager. * It is the manager that updates the position. * * @author Andrea Antonello (www.hydrologis.com) */ @SuppressWarnings("nls") public class GpsDatabaseLogger implements GpsManagerListener { private final Context context; /** * The last taken gps location. */ private GpsLocation gpsLoc = null; /** * The previous gpslog location. * * <p>This changes with every gps log waiting time.</p> */ private Location previousLogLoc = null; private boolean isDatabaseLogging = false; private boolean isShutdown = false; private List<double[]> currentXY = new ArrayList<double[]>(); // private MediaPlayer mMediaPlayer; // private boolean doPlayAlarm = false; private int currentPointsNum; private float currentDistance; public GpsDatabaseLogger( Context context ) { this.context = context; } private long currentRecordedLogId = -1; private volatile boolean gotFix; private long lastLocationupdateMillis; public long getCurrentRecordedLogId() { return currentRecordedLogId; } /** * Getter for the logging info. * * @return true if the logger is active and recording points into the database. */ public boolean isDatabaseLogging() { return isDatabaseLogging; } /** * @return <code>true</code> only if the gps thread has finished. */ public boolean isShutdown() { return isShutdown; } /** * Starts logging into the database. * * @param logName a name for the new log or <code>null</code>. */ public void startDatabaseLogging( final String logName, final IGpsLogDbHelper dbHelper ) { if (isDatabaseLogging) { // we do not start twice return; } isDatabaseLogging = true; currentXY.clear(); Thread t = new Thread(){ public void run() { try { isShutdown = false; SQLiteDatabase sqliteDatabase = dbHelper.getDatabase(context); java.sql.Date now = new java.sql.Date(System.currentTimeMillis()); long gpsLogId = dbHelper.addGpsLog(context, now, now, logName, 2f, "red", true); currentRecordedLogId = gpsLogId; logH("Starting gps logging. Logid: " + gpsLogId); // get preferences SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); String minDistanceStr = preferences.getString(PREFS_KEY_GPSLOGGINGDISTANCE, String.valueOf(GPS_LOGGING_DISTANCE)); float minDistance = 1f; try { minDistance = Float.parseFloat(minDistanceStr); } catch (Exception e) { // ignore and use default } String intervalStr = preferences .getString(PREFS_KEY_GPSLOGGINGINTERVAL, String.valueOf(GPS_LOGGING_INTERVAL)); long waitForSecs = 3; try { waitForSecs = Long.parseLong(intervalStr); } catch (Exception e) { // ignore and use default } logH("Waiting interval: " + waitForSecs); currentPointsNum = 0; currentDistance = 0; previousLogLoc = null; while( isDatabaseLogging ) { if (gotFix) { if (gpsLoc == null) { waitGpsInterval(waitForSecs); continue; } if (previousLogLoc == null) { previousLogLoc = gpsLoc; } double recLon = gpsLoc.getLongitude(); double recLat = gpsLoc.getLatitude(); double recAlt = gpsLoc.getAltitude(); float lastDistance = previousLogLoc.distanceTo(gpsLoc); logABS("gpsloc: " + gpsLoc.getLatitude() + "/" + gpsLoc.getLongitude()); logABS("previousLoc: " + previousLogLoc.getLatitude() + "/" + previousLogLoc.getLongitude()); logABS("distance: " + lastDistance + " - mindistance: " + minDistance); // ignore near points if (lastDistance < minDistance) { waitGpsInterval(waitForSecs); continue; } try { if (isDatabaseLogging) { dbHelper.addGpsLogDataPoint(sqliteDatabase, gpsLogId, recLon, recLat, recAlt, gpsLoc.getSqlDate()); currentXY.add(new double[]{recLon, recLat}); } } catch (Exception e) { GPLog.error(this, e.getLocalizedMessage(), e); throw new IOException(e.getLocalizedMessage()); } currentPointsNum++; currentDistance = currentDistance + lastDistance; previousLogLoc = gpsLoc; } if (!isDatabaseLogging) { break; } // and wait waitGpsInterval(waitForSecs); } if (currentPointsNum < 2) { logABS("Removing gpslog, since too few points were added. Logid: " + gpsLogId); dbHelper.deleteGpslog(context, gpsLogId); } else { // set the end timestamp java.sql.Date end = new java.sql.Date(System.currentTimeMillis()); dbHelper.setEndTs(context, gpsLogId, end); } currentPointsNum = 0; currentDistance = 0f; currentRecordedLogId = -1; } catch (SQLiteFullException e) { e.printStackTrace(); String msg = context.getResources().getString(R.string.error_disk_full); GPLog.error(this, msg, e); Utilities.toast(context, msg, Toast.LENGTH_LONG); } catch (Exception e) { e.printStackTrace(); String msg = context.getResources().getString(R.string.cantwrite_gpslog); GPLog.error(this, msg, e); Utilities.toast(context, msg, Toast.LENGTH_LONG); } finally { isDatabaseLogging = false; currentXY.clear(); isShutdown = true; } logABS("Exit logging..."); } private void waitGpsInterval( long waitForSecs ) { try { // get interval and wait Thread.sleep(waitForSecs * 1000L); } catch (InterruptedException e) { e.printStackTrace(); String msg = context.getResources().getString(R.string.cantwrite_gpslog); GPLog.error(this, msg, e); } } }; t.start(); Utilities.toast(context, R.string.gpsloggingon, Toast.LENGTH_SHORT); } public void stopDatabaseLogging() { isDatabaseLogging = false; Utilities.toast(context, R.string.gpsloggingoff, Toast.LENGTH_SHORT); } /** * Get the current recorded log. * * @return the list of lon,lat. */ public List<double[]> getCurrentRecordedLog() { if (isDatabaseLogging) { return currentXY; } else { return null; } } public int getCurrentPointsNum() { return currentPointsNum; } public int getCurrentDistance() { return (int) currentDistance; } public void onLocationChanged( Location location ) { if (location == null) { return; } lastLocationupdateMillis = SystemClock.elapsedRealtime(); gpsLoc = new GpsLocation(location); } public void onStatusChanged( String provider, int status, Bundle extras ) { } public void onProviderEnabled( String provider ) { } public void onProviderDisabled( String provider ) { } public void gpsStart() { gotFix = false; logH("gpsStart called"); } public void gpsStop() { lastLocationupdateMillis = 0; gotFix = false; logH("gpsStop called"); } public void onGpsStatusChanged( int event, GpsStatus status ) { // check fix boolean tmpGotFix = GpsStatusInfo.checkFix(gotFix, lastLocationupdateMillis, event); if (!tmpGotFix) { // check if it is just standing still GpsStatusInfo info = new GpsStatusInfo(status); int satForFixCount = info.getSatUsedInFixCount(); if (satForFixCount > 2) { tmpGotFix = true; // updating loc update, assuming the still filter is giving troubles lastLocationupdateMillis = SystemClock.elapsedRealtime(); } } gotFix = tmpGotFix; } private void logH( String msg ) { if (GPLog.LOG_HEAVY) GPLog.addLogEntry(this, null, null, msg); } private void logABS( String msg ) { if (GPLog.LOG_ABSURD) GPLog.addLogEntry(this, null, null, msg); } public boolean hasFix() { return gotFix; } // ///////////////////////////////////////////////// // SOUND HANDLING // ///////////////////////////////////////////////// // private Handler alertDialogHandler = new Handler(){ // // public void handleMessage( android.os.Message msg ) { // mMediaPlayer = new MediaPlayer(); // doPlayAlarm = true; // AlertDialog.Builder builder = new AlertDialog.Builder(context); // String ok = context.getResources().getString(R.string.ok); // builder.setMessage(R.string.gpsloggingalarm).setCancelable(false) // .setPositiveButton(ok, new DialogInterface.OnClickListener(){ // public void onClick( DialogInterface dialog, int id ) { // doPlayAlarm = false; // if (mMediaPlayer != null && mMediaPlayer.isPlaying()) { // mMediaPlayer.stop(); // mMediaPlayer = null; // } // } // }); // AlertDialog alertDialog = builder.create(); // alertDialog.show(); // }; // }; // private Handler alertSoundHandler = new Handler(){ // public void handleMessage( android.os.Message msg ) { // try { // if (doPlayAlarm == false) { // return; // } // Uri alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM); // mMediaPlayer.setDataSource(context, alert); // final AudioManager audioManager = (AudioManager) // context.getSystemService(Context.AUDIO_SERVICE); // if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) { // mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM); // mMediaPlayer.setLooping(true); // mMediaPlayer.prepare(); // mMediaPlayer.start(); // } // } catch (Exception e) { // Logger.e(this, e.getLocalizedMessage(), e); // e.printStackTrace(); // } // }; // }; // private void playAlert() { // try { // alertDialogHandler.sendEmptyMessage(0); // int index = 0; // while( index < 3 ) { // Thread.sleep(1000); // index++; // } // alertSoundHandler.sendEmptyMessage(0); // } catch (InterruptedException e) { // Logger.e(this, e.getLocalizedMessage(), e); // e.printStackTrace(); // } // } }