/*------------------------------------------------------------------------------ ** Ident: Sogeti Smart Mobile Solutions ** Author: rene ** Copyright: (c) Apr 24, 2011 Sogeti Nederland B.V. All Rights Reserved. **------------------------------------------------------------------------------ ** Sogeti Nederland B.V. | No part of this file may be reproduced ** Distributed Software Engineering | or transmitted in any form or by any ** Lange Dreef 17 | means, electronic or mechanical, for the ** 4131 NJ Vianen | purpose, without the express written ** The Netherlands | permission of the copyright holder. *------------------------------------------------------------------------------ * * This file is part of OpenGPSTracker. * * OpenGPSTracker 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. * * OpenGPSTracker 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 OpenGPSTracker. If not, see <http://www.gnu.org/licenses/>. * */ package nl.sogeti.android.gpstracker.actions.utils; import nl.sogeti.android.gpstracker.db.GPStracking.Segments; import nl.sogeti.android.gpstracker.db.GPStracking.Tracks; import nl.sogeti.android.gpstracker.db.GPStracking.Waypoints; import nl.sogeti.android.gpstracker.util.Constants; import nl.sogeti.android.gpstracker.util.UnitsI18n; import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; import android.location.Location; import android.net.Uri; import android.os.AsyncTask; public class StatisticsCalulator extends AsyncTask<Uri, Void, Void> { @SuppressWarnings("unused") private static final String TAG = "OGT.StatisticsCalulator"; private Context mContext; private String overallavgSpeedText = "Unknown"; private String avgSpeedText = "Unknown"; private String maxSpeedText = "Unknown"; private String ascensionText = "Unknown"; private String minSpeedText = "Unknown"; private String tracknameText = "Unknown"; private String waypointsText = "Unknown"; private String distanceText = "Unknown"; private long mStarttime = -1; private long mEndtime = -1; private UnitsI18n mUnits; private double mMaxSpeed; private double mMaxAltitude; private double mMinAltitude; private double mAscension; private double mDistanceTraveled; private long mDuration; private double mAverageActiveSpeed; private StatisticsDelegate mDelegate; public StatisticsCalulator( Context ctx, UnitsI18n units, StatisticsDelegate delegate ) { mContext = ctx; mUnits = units; mDelegate = delegate; } private void updateCalculations( Uri trackUri ) { mStarttime = -1; mEndtime = -1; mMaxSpeed = 0; mAverageActiveSpeed = 0; mMaxAltitude = 0; mMinAltitude = 0; mAscension = 0; mDistanceTraveled = 0f; mDuration = 0; long duration = 1; double ascension = 0; ContentResolver resolver = mContext.getContentResolver(); Cursor waypointsCursor = null; try { waypointsCursor = resolver.query( Uri.withAppendedPath( trackUri, "waypoints" ), new String[] { "max (" + Waypoints.TABLE + "." + Waypoints.SPEED + ")" , "max (" + Waypoints.TABLE + "." + Waypoints.ALTITUDE + ")" , "min (" + Waypoints.TABLE + "." + Waypoints.ALTITUDE + ")" , "count(" + Waypoints.TABLE + "." + Waypoints._ID + ")" }, null, null, null ); if( waypointsCursor.moveToLast() ) { mMaxSpeed = waypointsCursor.getDouble( 0 ); mMaxAltitude = waypointsCursor.getDouble( 1 ); mMinAltitude = waypointsCursor.getDouble( 2 ); long nrWaypoints = waypointsCursor.getLong( 3 ); waypointsText = nrWaypoints + ""; } waypointsCursor.close(); waypointsCursor = resolver.query( Uri.withAppendedPath( trackUri, "waypoints" ), new String[] { "avg (" + Waypoints.TABLE + "." + Waypoints.SPEED + ")" }, Waypoints.TABLE + "." + Waypoints.SPEED +" > ?", new String[] { ""+Constants.MIN_STATISTICS_SPEED }, null ); if( waypointsCursor.moveToLast() ) { mAverageActiveSpeed = waypointsCursor.getDouble( 0 ); } } finally { if( waypointsCursor != null ) { waypointsCursor.close(); } } Cursor trackCursor = null; try { trackCursor = resolver.query( trackUri, new String[] { Tracks.NAME }, null, null, null ); if( trackCursor.moveToLast() ) { tracknameText = trackCursor.getString( 0 ); } } finally { if( trackCursor != null ) { trackCursor.close(); } } Cursor segments = null; Location lastLocation = null; Location lastAltitudeLocation = null; Location currentLocation = null; try { Uri segmentsUri = Uri.withAppendedPath( trackUri, "segments" ); segments = resolver.query( segmentsUri, new String[] { Segments._ID }, null, null, null ); if( segments.moveToFirst() ) { do { long segmentsId = segments.getLong( 0 ); Cursor waypoints = null; try { Uri waypointsUri = Uri.withAppendedPath( segmentsUri, segmentsId + "/waypoints" ); waypoints = resolver.query( waypointsUri, new String[] { Waypoints._ID, Waypoints.TIME, Waypoints.LONGITUDE, Waypoints.LATITUDE, Waypoints.ALTITUDE }, null, null, null ); if( waypoints.moveToFirst() ) { do { if( mStarttime < 0 ) { mStarttime = waypoints.getLong( 1 ); } currentLocation = new Location( this.getClass().getName() ); currentLocation.setTime( waypoints.getLong( 1 ) ); currentLocation.setLongitude( waypoints.getDouble( 2 ) ); currentLocation.setLatitude( waypoints.getDouble( 3 ) ); currentLocation.setAltitude( waypoints.getDouble( 4 ) ); // Do no include obvious wrong 0.0 lat 0.0 long, skip to next value in while-loop if( currentLocation.getLatitude() == 0.0d || currentLocation.getLongitude() == 0.0d ) { continue; } if( lastLocation != null ) { float travelPart = lastLocation.distanceTo( currentLocation ); long timePart = currentLocation.getTime() - lastLocation.getTime(); mDistanceTraveled += travelPart; duration += timePart; } if( currentLocation.hasAltitude() ) { if( lastAltitudeLocation != null ) { if( currentLocation.getTime() - lastAltitudeLocation.getTime() > 5*60*1000 ) // more then a 5m of climbing { if( currentLocation.getAltitude() > lastAltitudeLocation.getAltitude()+1 ) // more then 1m climb { ascension += currentLocation.getAltitude() - lastAltitudeLocation.getAltitude(); lastAltitudeLocation = currentLocation; } else { lastAltitudeLocation = currentLocation; } } } else { lastAltitudeLocation = currentLocation; } } lastLocation = currentLocation; mEndtime = lastLocation.getTime(); } while( waypoints.moveToNext() ); mDuration = mEndtime - mStarttime; } } finally { if( waypoints != null ) { waypoints.close(); } } lastLocation = null; } while( segments.moveToNext() ); } } finally { if( segments != null ) { segments.close(); } } double maxSpeed = mUnits.conversionFromMetersPerSecond( mMaxSpeed ); double overallavgSpeedfl = mUnits.conversionFromMeterAndMiliseconds( mDistanceTraveled, mDuration ); double avgSpeedfl = mUnits.conversionFromMeterAndMiliseconds( mDistanceTraveled, duration ); double traveled = mUnits.conversionFromMeter( mDistanceTraveled ); avgSpeedText = mUnits.formatSpeed( avgSpeedfl, true ); overallavgSpeedText = mUnits.formatSpeed( overallavgSpeedfl, true ); maxSpeedText = mUnits.formatSpeed( maxSpeed, true ); distanceText = String.format( "%.2f %s", traveled, mUnits.getDistanceUnit() ); ascensionText = String.format( "%.0f %s", ascension, mUnits.getHeightUnit() ); } /** * Get the overallavgSpeedText. * * @return Returns the overallavgSpeedText as a String. */ public String getOverallavgSpeedText() { return overallavgSpeedText; } /** * Get the avgSpeedText. * * @return Returns the avgSpeedText as a String. */ public String getAvgSpeedText() { return avgSpeedText; } /** * Get the maxSpeedText. * * @return Returns the maxSpeedText as a String. */ public String getMaxSpeedText() { return maxSpeedText; } /** * Get the minSpeedText. * * @return Returns the minSpeedText as a String. */ public String getMinSpeedText() { return minSpeedText; } /** * Get the tracknameText. * * @return Returns the tracknameText as a String. */ public String getTracknameText() { return tracknameText; } /** * Get the waypointsText. * * @return Returns the waypointsText as a String. */ public String getWaypointsText() { return waypointsText; } /** * Get the distanceText. * * @return Returns the distanceText as a String. */ public String getDistanceText() { return distanceText; } /** * Get the starttime. * * @return Returns the starttime as a long. */ public long getStarttime() { return mStarttime; } /** * Get the endtime. * * @return Returns the endtime as a long. */ public long getEndtime() { return mEndtime; } /** * Get the maximum speed. * * @return Returns the maxSpeeddb as m/s in a double. */ public double getMaxSpeed() { return mMaxSpeed; } /** * Get the min speed. * * @return Returns the average speed as m/s in a double. */ public double getAverageStatisicsSpeed() { return mAverageActiveSpeed; } /** * Get the maxAltitude. * * @return Returns the maxAltitude as a double. */ public double getMaxAltitude() { return mMaxAltitude; } /** * Get the minAltitude. * * @return Returns the minAltitude as a double. */ public double getMinAltitude() { return mMinAltitude; } /** * Get the total ascension in m. * * @return Returns the ascension as a double. */ public double getAscension() { return mAscension; } public CharSequence getAscensionText() { return ascensionText; } /** * Get the distanceTraveled. * * @return Returns the distanceTraveled as a float. */ public double getDistanceTraveled() { return mDistanceTraveled; } /** * Get the mUnits. * * @return Returns the mUnits as a UnitsI18n. */ public UnitsI18n getUnits() { return mUnits; } public String getDurationText() { long s = mDuration / 1000; String duration = String.format("%dh:%02dm:%02ds", s/3600, (s%3600)/60, (s%60)); return duration; } @Override protected Void doInBackground(Uri... params) { this.updateCalculations(params[0]); return null; } @Override protected void onPostExecute(Void result) { super.onPostExecute(result); if( mDelegate != null ) { mDelegate.finishedCalculations(this); } } }