/*------------------------------------------------------------------------------ ** Ident: Innovation en Inspiration > Google Android ** Author: rene ** Copyright: (c) Jan 22, 2009 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 edu.stanford.cs.sujogger.viewer; import java.util.Vector; import android.content.ContentResolver; import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ComposeShader; import android.graphics.CornerPathEffect; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Point; import android.graphics.RadialGradient; import android.graphics.Shader; import android.graphics.PorterDuff.Mode; import android.graphics.Shader.TileMode; import android.location.Location; import android.net.Uri; import android.widget.Toast; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapView; import com.google.android.maps.Overlay; import com.google.android.maps.Projection; import edu.stanford.cs.sujogger.R; import edu.stanford.cs.sujogger.db.GPStracking; import edu.stanford.cs.sujogger.db.GPStracking.Media; import edu.stanford.cs.sujogger.db.GPStracking.Waypoints; import edu.stanford.cs.sujogger.util.Common; /** * Creates an overlay that can draw a single segment of connected waypoints * * @version $Id: SegmentOverlay.java 467 2010-03-28 10:59:56Z rcgroot $ * @author rene (c) Jan 11, 2009, Sogeti B.V. */ public class SegmentOverlay extends Overlay { public static final int MIDDLE_SEGMENT = 0; public static final int FIRST_SEGMENT = 1; public static final int LAST_SEGMENT = 2; public static final String TAG = "OGT.SegmentOverlay"; public static final int DRAW_GREEN = 0; public static final int DRAW_RED = 1; public static final int DRAW_MEASURED = 2; public static final int DRAW_CALCULATED = 3; public static final int DRAW_DOTS = 4; private static final float MINIMUM_RL_DISTANCE = 25; private static final float MINIMUM_RL_TIME = 5; private static final float MINIMUM_PX_DISTANCE = 15; private int mTrackColoringMethod = DRAW_CALCULATED; private ContentResolver mResolver; private Context mContext; private Projection mProjection; private int mPlacement = SegmentOverlay.MIDDLE_SEGMENT; private Uri mWaypointsUri; private Uri mMediaUri; private double mAvgSpeed; private GeoPoint mTopLeft; private GeoPoint mBottumRight; private Vector<DotVO> mDotPath; private Vector<MediaVO> mMediaPath; private Path mPath; private Shader mShader; private GeoPoint mStartPoint; private GeoPoint mEndPoint; private int mCalculatedPoints; private Point mPrevScreenPoint; private Point mScreenPoint; private boolean mLastOnscreen; private int mStepSize = 1; private int mStep = 0; private MapView mMapView; private Location location; private Location prevLocation; private Cursor mWaypointsCursor; private Uri mSegmentUri; private int mWaypointCount; /** * Constructor: create a new TrackingOverlay. * * @param cxt * @param segmentUri * @param color * @param avgSpeed * @param mapView */ public SegmentOverlay(Context cxt, Uri segmentUri, int color, double avgSpeed, MapView mapView) { super(); this.mContext = cxt; this.mMapView = mapView; this.mTrackColoringMethod = color; this.mAvgSpeed = avgSpeed; this.mResolver = mContext.getApplicationContext().getContentResolver(); this.mSegmentUri = segmentUri; this.mMediaUri = Uri.withAppendedPath( mSegmentUri, "media" ); this.mWaypointsUri = Uri.withAppendedPath( mSegmentUri, "waypoints" ); Cursor waypointsCursor = null; try { waypointsCursor = this.mResolver.query( this.mWaypointsUri, new String[] { Waypoints._ID }, null, null, null ); mWaypointCount = waypointsCursor.getCount(); } finally { waypointsCursor.close(); } } @Override public void draw( Canvas canvas, MapView mapView, boolean shadow ) { super.draw( canvas, mapView, shadow ); if( shadow ) { // Common.log( TAG, "No shadows to draw" ); } else { mProjection = mapView.getProjection(); GeoPoint oldTopLeft = mTopLeft; GeoPoint oldBottumRight = mBottumRight; mTopLeft = mProjection.fromPixels( 0, 0 ); mBottumRight = mProjection.fromPixels( canvas.getWidth(), canvas.getHeight() ); if( oldTopLeft == null || oldBottumRight == null || mTopLeft.getLatitudeE6() / 100 != oldTopLeft.getLatitudeE6() / 100 || mTopLeft.getLongitudeE6() / 100 != oldTopLeft.getLongitudeE6() / 100 || mBottumRight.getLatitudeE6() / 100 != oldBottumRight.getLatitudeE6() / 100 || mBottumRight.getLongitudeE6() / 100 != oldBottumRight.getLongitudeE6() / 100 ) { this.mScreenPoint = new Point(); this.mPrevScreenPoint = new Point(); calculateTrack(); } switch( mTrackColoringMethod ) { case ( DRAW_CALCULATED ): case ( DRAW_MEASURED ): case ( DRAW_RED ): case ( DRAW_GREEN ): if( mPath == null ) { calculatePath(); } drawPath( canvas ); break; case ( DRAW_DOTS ): if( mDotPath == null ) { calculateDots(); } drawDots( canvas ); break; } drawStartStopCircles( canvas ); if( mMediaPath == null ) { calculateMedia(); } drawMedia( canvas ); } } public void calculateTrack() { switch( mTrackColoringMethod ) { case ( DRAW_CALCULATED ): case ( DRAW_MEASURED ): case ( DRAW_RED ): case ( DRAW_GREEN ): calculatePath(); break; case ( DRAW_DOTS ): calculateDots(); break; } } /** * @param canvas * @param mapView * @param shadow * @see SegmentOverlay#draw(Canvas, MapView, boolean) */ private synchronized void calculateDots() { mPath = null; if( mDotPath == null ) { mDotPath = new Vector<DotVO>(); } else { mDotPath.clear(); } mCalculatedPoints = 0; mStep = 0; try { mWaypointsCursor = this.mResolver.query( this.mWaypointsUri, new String[] { Waypoints.LATITUDE, Waypoints.LONGITUDE, Waypoints.ACCURACY }, null, null, null ); if( mProjection != null && mWaypointsCursor.moveToFirst() ) { GeoPoint geoPoint; do { geoPoint = extractGeoPoint(); setScreenPoint( geoPoint ); float distance = (float) distanceInPoints( this.mPrevScreenPoint, this.mScreenPoint ); if( distance > MINIMUM_PX_DISTANCE ) { DotVO dotVO = new DotVO(); dotVO.x = this.mScreenPoint.x; dotVO.y = this.mScreenPoint.y; dotVO.radius = mProjection.metersToEquatorPixels( mWaypointsCursor.getFloat( 2 ) ); mDotPath.add( dotVO ); this.mPrevScreenPoint.x = this.mScreenPoint.x; this.mPrevScreenPoint.y = this.mScreenPoint.y; } } while( moveToNextWayPoint() ); this.mEndPoint = extractGeoPoint(); DotVO pointVO = new DotVO(); pointVO.x = this.mScreenPoint.x; pointVO.y = this.mScreenPoint.y; pointVO.radius = mProjection.metersToEquatorPixels( mWaypointsCursor.getFloat( 2 ) ); mDotPath.add( pointVO ); } } finally { if( mWaypointsCursor != null ) { mWaypointsCursor.close(); } } } private synchronized void drawDots( Canvas canvas ) { Paint dotpaint = new Paint(); Paint radiusPaint = new Paint(); radiusPaint.setColor( Color.YELLOW ); radiusPaint.setAlpha( 100 ); for( DotVO dotVO : mDotPath ) { Bitmap bitmap = BitmapFactory.decodeResource( this.mContext.getResources(), R.drawable.stip2 ); canvas.drawBitmap( bitmap, dotVO.x - 8, dotVO.y - 8, dotpaint ); if( dotVO.radius > 8f ) { canvas.drawCircle( dotVO.x, dotVO.y, dotVO.radius, radiusPaint ); } } } private synchronized void calculatePath() { // Common.log(TAG, "CALCULATING PATH"); mDotPath = null; if( this.mPath == null ) { this.mPath = new Path(); } else { this.mPath.rewind(); } this.mShader = null; GeoPoint geoPoint; mCalculatedPoints = 0; mStep = 0; this.prevLocation = null; int moves = 0; calculateStepSize(); try { mWaypointsCursor = this.mResolver.query( this.mWaypointsUri, new String[] { Waypoints.LATITUDE, Waypoints.LONGITUDE, Waypoints.SPEED, Waypoints.TIME }, null, null, null ); if( mProjection != null && mWaypointsCursor.moveToFirst() ) { // Start point of the segments, possible a dot this.mStartPoint = extractGeoPoint(); this.location = new Location( this.getClass().getName() ); this.location.setLatitude( mWaypointsCursor.getDouble( 0 ) ); this.location.setLongitude( mWaypointsCursor.getDouble( 1 ) ); this.location.setTime( mWaypointsCursor.getLong( 3 ) ); moveToGeoPoint( this.mStartPoint ); do { // Common.log(TAG, "Moving the loop of: moveToNextWayPoint() at cursor position: "+trackCursor.getPosition() ) ; geoPoint = extractGeoPoint(); double speed = -1d; switch( mTrackColoringMethod ) { case DRAW_GREEN: case DRAW_RED: lineToGeoPoint( geoPoint, speed ); break; case DRAW_MEASURED: lineToGeoPoint( geoPoint, mWaypointsCursor.getDouble( 2 ) ); break; case DRAW_CALCULATED: this.location = new Location( this.getClass().getName() ); this.location.setLatitude( mWaypointsCursor.getDouble( 0 ) ); this.location.setLongitude( mWaypointsCursor.getDouble( 1 ) ); this.location.setTime( mWaypointsCursor.getLong( 3 ) ); if( ( this.prevLocation.distanceTo( this.location ) > MINIMUM_RL_DISTANCE && this.location.getTime() - this.prevLocation.getTime() > MINIMUM_RL_TIME ) || mWaypointsCursor.isLast() ) { speed = calculateSpeedBetweenLocations( this.prevLocation, this.location ); lineToGeoPoint( geoPoint, speed ); } else { lineToGeoPoint( geoPoint, -1d ); } break; default: lineToGeoPoint( geoPoint, speed ); break; } moves++; } while( moveToNextWayPoint() ); // End point of the segments, possible a dot this.mEndPoint = extractGeoPoint(); } } finally { if( mWaypointsCursor != null ) { mWaypointsCursor.close(); } } // Common.log( TAG, "transformSegmentToPath stop: points "+mCalculatedPoints+" from "+moves+" moves" ); //Common.log(TAG, "CALCULATING PATH DONE"); } /** * @param canvas * @param mapView * @param shadow * @see SegmentOverlay#draw(Canvas, MapView, boolean) */ private synchronized void drawPath( Canvas canvas ) { Paint routePaint = new Paint(); routePaint.setPathEffect( new CornerPathEffect( 10 ) ); switch( mTrackColoringMethod ) { case ( DRAW_CALCULATED ): case ( DRAW_MEASURED ): routePaint.setShader( this.mShader ); break; case ( DRAW_RED ): routePaint.setColor( Color.RED ); break; case ( DRAW_GREEN ): routePaint.setColor( Color.GREEN ); break; default: routePaint.setColor( Color.YELLOW ); break; } routePaint.setStyle( Paint.Style.STROKE ); routePaint.setStrokeWidth( 6 ); routePaint.setAntiAlias( true ); canvas.drawPath( this.mPath, routePaint ); } public synchronized void calculateMedia() { if( mMediaPath == null ) { mMediaPath = new Vector<MediaVO>(); } else { mMediaPath.clear(); } Cursor mediaCursor = null; try { // Common.log( TAG, "Searching for media on " + this.mMediaUri ); mediaCursor = this.mResolver.query( this.mMediaUri, new String[] { Media.WAYPOINT, Media.URI }, null, null, null ); if( mProjection != null && mediaCursor.moveToFirst() ) { do { MediaVO mediaVO = new MediaVO(); mediaVO.waypointId = mediaCursor.getLong( 0 ); mediaVO.uri = Uri.parse( mediaCursor.getString( 1 ) ); // Common.log( TAG, mediaVO.uri.toString() ); Uri mediaWaypoint = ContentUris.withAppendedId( mWaypointsUri, mediaVO.waypointId ); Cursor waypointCursor = null; try { waypointCursor = this.mResolver.query( mediaWaypoint, new String[] { Waypoints.LATITUDE, Waypoints.LONGITUDE }, null, null, null ); if( waypointCursor != null && waypointCursor.moveToFirst() ) { int microLatitude = (int) ( waypointCursor.getDouble( 0 ) * 1E6d ); int microLongitude = (int) ( waypointCursor.getDouble( 1 ) * 1E6d ); mediaVO.geopoint = new GeoPoint( microLatitude, microLongitude ); } } finally { if( waypointCursor != null ) { waypointCursor.close(); } } mMediaPath.add( mediaVO ); } while( mediaCursor.moveToNext() ); } } finally { if( mediaCursor != null ) { mediaCursor.close(); } } } private synchronized void drawMedia( Canvas canvas ) { for( MediaVO mediaVO : mMediaPath ) { if( isOnScreen( mediaVO.geopoint ) ) { setScreenPoint( mediaVO.geopoint ); int drawable = 0; if( mediaVO.uri.getScheme().equals( "file" ) ) { if( mediaVO.uri.getLastPathSegment().endsWith( "3gp" ) ) { drawable = R.drawable.media_film; } else if( mediaVO.uri.getLastPathSegment().endsWith( "jpg" ) ) { drawable = R.drawable.media_camera; } else if( mediaVO.uri.getLastPathSegment().endsWith( "txt" ) ) { drawable = R.drawable.media_notepad; } } else if( mediaVO.uri.getScheme().equals( "content" ) ) { if( mediaVO.uri.getAuthority().equals( GPStracking.AUTHORITY + ".string" ) ) { drawable = R.drawable.media_mark; } else if( mediaVO.uri.getAuthority().equals( "media" ) ) { drawable = R.drawable.media_speech; } } Bitmap bitmap = BitmapFactory.decodeResource( this.mContext.getResources(), drawable ); int left = ( bitmap.getWidth() * 3 ) / 7; int up = ( bitmap.getHeight() * 6 ) / 7; canvas.drawBitmap( bitmap, mScreenPoint.x - left, mScreenPoint.y - up, new Paint() ); } } } private void drawStartStopCircles( Canvas canvas ) { Bitmap bitmap; if( ( this.mPlacement == FIRST_SEGMENT || this.mPlacement == FIRST_SEGMENT + LAST_SEGMENT ) && this.mStartPoint != null ) { setScreenPoint( this.mStartPoint ); bitmap = BitmapFactory.decodeResource( this.mContext.getResources(), R.drawable.stip2 ); canvas.drawBitmap( bitmap, mScreenPoint.x - 8, mScreenPoint.y - 8, new Paint() ); } if( ( this.mPlacement == LAST_SEGMENT || this.mPlacement == FIRST_SEGMENT + LAST_SEGMENT ) && this.mEndPoint != null ) { setScreenPoint( this.mEndPoint ); bitmap = BitmapFactory.decodeResource( this.mContext.getResources(), R.drawable.stip ); canvas.drawBitmap( bitmap, mScreenPoint.x - 5, mScreenPoint.y - 5, new Paint() ); } } /** * Set the mPlace to the specified value. * * @see SegmentOverlay.FIRST * @see SegmentOverlay.MIDDLE * @see SegmentOverlay.LAST * @param place The placement of this segment in the line. */ public void addPlacement( int place ) { this.mPlacement += place; } public boolean isLast() { return ( mPlacement >= LAST_SEGMENT ); } public long getSegmentId() { return Long.parseLong( mSegmentUri.getLastPathSegment() ); } private void moveToGeoPoint( GeoPoint geoPoint ) { setScreenPoint( geoPoint ); if( this.mPath != null ) { this.mPath.moveTo( this.mScreenPoint.x, this.mScreenPoint.y ); } this.prevLocation = this.location; this.mPrevScreenPoint.x = this.mScreenPoint.x; this.mPrevScreenPoint.y = this.mScreenPoint.y; } private void lineToGeoPoint( GeoPoint geoPoint, double speed ) { // Common.log( TAG, "Drawing line to " + geoPoint + " with speed " + speed ); setScreenPoint( geoPoint ); // Bitmap bitmap = BitmapFactory.decodeResource( this.mContext.getResources(), R.drawable.stip2 ); // this.mCanvas.drawBitmap( bitmap, this.mScreenPoint.x - 8, this.mScreenPoint.y - 8, new Paint() ); Common.log(TAG, "speed = " + speed); if( speed >= 0.0 ) { int greenfactor = (int) Math.min( ( 127 * speed ) / mAvgSpeed, 255 ); int redfactor = 255 - greenfactor; int currentColor = Color.rgb( redfactor, greenfactor, 0 ); float distance = (float) distanceInPoints( this.mPrevScreenPoint, this.mScreenPoint ); if( distance > MINIMUM_PX_DISTANCE ) { int x_circle = ( this.mPrevScreenPoint.x + this.mScreenPoint.x ) / 2; int y_circle = ( this.mPrevScreenPoint.y + this.mScreenPoint.y ) / 2; float radius_factor = 0.4f; Shader lastShader = new RadialGradient( x_circle, y_circle, distance, new int[] { currentColor, currentColor, Color.TRANSPARENT }, new float[] { 0, radius_factor, 1 }, TileMode.CLAMP ); // Paint foo = new Paint(); // foo.setStyle( Paint.Style.STROKE ); // this.mCanvas.drawCircle( // x_circle, // y_circle, // distance*radius_factor, // foo ); // Common.log( TAG, "mPrevScreenPoint"+ mPrevScreenPoint ); // Common.log( TAG, "mScreenPoint"+ mScreenPoint ); // Common.log( TAG, "Created shader for speed " + speed + " on "+x_circle+","+y_circle); if( this.mShader != null ) { this.mShader = new ComposeShader( this.mShader, lastShader, Mode.SRC_OVER ); } else { this.mShader = lastShader; } this.prevLocation = this.location; this.mPrevScreenPoint.x = this.mScreenPoint.x; this.mPrevScreenPoint.y = this.mScreenPoint.y; } } else { // Draw tracks w/o speed in a light-blue color int currentColor = Color.rgb(107, 190, 222); float distance = (float) distanceInPoints( this.mPrevScreenPoint, this.mScreenPoint ); if( distance > MINIMUM_PX_DISTANCE ) { int x_circle = ( this.mPrevScreenPoint.x + this.mScreenPoint.x ) / 2; int y_circle = ( this.mPrevScreenPoint.y + this.mScreenPoint.y ) / 2; float radius_factor = 0.4f; Shader lastShader = new RadialGradient( x_circle, y_circle, distance, new int[] { currentColor, currentColor, Color.TRANSPARENT }, new float[] { 0, radius_factor, 1 }, TileMode.CLAMP ); if( this.mShader != null ) this.mShader = new ComposeShader( this.mShader, lastShader, Mode.SRC_OVER ); else this.mShader = lastShader; } } this.mPath.lineTo( this.mScreenPoint.x, this.mScreenPoint.y ); } private void setScreenPoint( GeoPoint geoPoint ) { this.mProjection.toPixels( geoPoint, this.mScreenPoint ); mCalculatedPoints++; } private boolean moveToNextWayPoint() { if( mWaypointsCursor.isLast() ) { return false; } //boolean onScreen = isOnScreen( extractGeoPoint( trackCursor ) ); if( mLastOnscreen ) { return moveToNextOnScreenWaypoint(); } else { mLastOnscreen = false; return moveToNextOffScreenWaypoint(); } } /** * Move the cursor to the next waypoint based on the stepsize * * @param trackCursor * @return */ private boolean moveToNextOnScreenWaypoint() { GeoPoint evalPoint; while( mWaypointsCursor.moveToNext() ) { mStep++; // evalPoint = extractGeoPoint( trackCursor ); // if( !isOnScreen( evalPoint ) ) // { // // Common.log(TAG, "first out screen "+trackCursor.getPosition() ); // return true; // } if( isFullStepTaken() ) { return true; } } // No full step can be taken, the last waypoint of the segment might be on screen. mWaypointsCursor.moveToLast(); evalPoint = extractGeoPoint(); return isOnScreen( evalPoint ); } private boolean moveToNextOffScreenWaypoint() { GeoPoint lastPoint = extractGeoPoint(); while( mWaypointsCursor.move( mStepSize * 2 ) ) { if( mWaypointsCursor.isLast() ) { // Common.log(TAG, "last off screen "+trackCursor.getPosition() ); return true; } GeoPoint evalPoint = extractGeoPoint(); if( isOnScreen( evalPoint ) ) { mLastOnscreen = true; moveToGeoPoint( lastPoint ); // Common.log(TAG, "first in screen "+trackCursor.getPosition() ); return true; } lastPoint = evalPoint; } return mWaypointsCursor.moveToLast(); } private boolean isFullStepTaken() { return mStep % mStepSize == 0; } /** * If a segment contains more then 500 waypoints and is zoomed out more then twice then some waypoints will not be used to render the line, this speeding things along. */ private void calculateStepSize() { if( mWaypointCount < 100 ) { mStepSize = 1; } else { int zoomLevel = mMapView.getZoomLevel(); int maxZoomLevel = mMapView.getMaxZoomLevel(); if( zoomLevel >= maxZoomLevel - 2 ) { mStepSize = 1; } else { mStepSize = 2 * ( maxZoomLevel - zoomLevel ); } } } /** * Is a given GeoPoint in the current projection of the map. * * @param eval * @return */ private boolean isOnScreen( GeoPoint eval ) { boolean under = this.mTopLeft.getLatitudeE6() > eval.getLatitudeE6(); boolean above = this.mBottumRight.getLatitudeE6() < eval.getLatitudeE6(); boolean right = this.mTopLeft.getLongitudeE6() < eval.getLongitudeE6(); boolean left = this.mBottumRight.getLongitudeE6() > eval.getLongitudeE6(); return under && above && right && left; } public void setTrackColoringMethod( int coloring, double avgspeed ) { this.mTrackColoringMethod = coloring; this.mAvgSpeed = avgspeed; calculatePath(); } /** * For the current waypoint cursor returns the GeoPoint * * @return */ private GeoPoint extractGeoPoint() { int microLatitude = (int) ( mWaypointsCursor.getDouble( 0 ) * 1E6d ); int microLongitude = (int) ( mWaypointsCursor.getDouble( 1 ) * 1E6d ); return new GeoPoint( microLatitude, microLongitude ); } /** * @param startLocation * @param endLocation * @return speed in m/s between 2 locations */ private static double calculateSpeedBetweenLocations( Location startLocation, Location endLocation ) { double speed = -1d; if( startLocation != null && endLocation != null ) { float distance = startLocation.distanceTo( endLocation ); float seconds = ( endLocation.getTime() - startLocation.getTime() ) / 1000f; speed = distance / seconds; // Common.log( TAG, "Found a speed of "+speed+ " over a distance of "+ distance+" in a time of "+seconds); } if( speed > 0 ) { return speed; } else { return -1d; } } public static int extendPoint( int x1, int x2 ) { int diff = x2 - x1; int next = x2 + diff; return next; } private static double distanceInPoints( Point start, Point end ) { int x = Math.abs( end.x - start.x ); int y = Math.abs( end.y - start.y ); return (double) Math.sqrt( x * x + y * y ); } private boolean handleMediaTap( Uri mediaUri ) { if( mediaUri.getScheme().equals( "file" ) ) { Intent intent = new Intent( android.content.Intent.ACTION_VIEW ); if( mediaUri.getLastPathSegment().endsWith( "3gp" ) ) { intent.setDataAndType( mediaUri, "video/3gpp" ); mContext.startActivity( intent ); return true; } else if( mediaUri.getLastPathSegment().endsWith( "jpg" ) ) { intent.setDataAndType( mediaUri, "image/jpeg" ); mContext.startActivity( intent ); return true; } else if( mediaUri.getLastPathSegment().endsWith( "txt" ) ) { intent.setDataAndType( mediaUri, "text/plain" ); mContext.startActivity( intent ); return true; } } else if( mediaUri.getScheme().equals( "content" ) ) { if( mediaUri.getAuthority().equals( GPStracking.AUTHORITY + ".string" ) ) { String text = mediaUri.getLastPathSegment(); Toast toast = Toast.makeText( mContext.getApplicationContext(), text, Toast.LENGTH_LONG ); toast.show(); return true; } else if( mediaUri.getAuthority().equals( "media" ) ) { mContext.startActivity( new Intent( Intent.ACTION_VIEW, mediaUri ) ); return true; } } return false; } /* * (non-Javadoc) * @see com.google.android.maps.Overlay#onTap(com.google.android.maps.GeoPoint, com.google.android.maps.MapView) */ @Override public boolean onTap( GeoPoint geoPoint, MapView mapView ) { MediaVO tappedMedia = null; float minScreendistance = Float.MAX_VALUE; float[] distance = new float[1]; for(MediaVO media : mMediaPath ) { double startLat = geoPoint.getLatitudeE6()/1E6d; double startLon = geoPoint.getLongitudeE6()/1E6d; double endLat = media.geopoint.getLatitudeE6()/1E6d; double endLon = media.geopoint.getLongitudeE6()/1E6d; Location.distanceBetween( startLat, startLon, endLat, endLon, distance ); float screendistance = mapView.getProjection().metersToEquatorPixels( distance[0] ) * Resources.getSystem().getDisplayMetrics().density; if( minScreendistance > screendistance ) { minScreendistance = screendistance; tappedMedia = media; } } if( minScreendistance < 15 ) { Common.log( TAG, String.format( "Tapped at a distance of %f which is %f on screen", distance[0], minScreendistance ) ); return handleMediaTap( tappedMedia.uri ); } return super.onTap( geoPoint, mapView ); } private static class MediaVO { public Uri uri; public GeoPoint geopoint; public long waypointId; } private static class DotVO { public int x; public int y; public float radius; } }