package com.robert.maps.applib.overlays; import java.io.File; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.andnav.osm.util.GeoPoint; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Point; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; import android.preference.PreferenceManager; import com.robert.maps.applib.MainActivity; import com.robert.maps.applib.kml.PoiManager; import com.robert.maps.applib.kml.Track; import com.robert.maps.applib.trackwriter.IRemoteService; import com.robert.maps.applib.trackwriter.ITrackWriterCallback; import com.robert.maps.applib.utils.SimpleThreadFactory; import com.robert.maps.applib.utils.Ut; import com.robert.maps.applib.view.TileView; import com.robert.maps.applib.view.TileViewOverlay; public class CurrentTrackOverlay extends TileViewOverlay { private Paint mPaint; private int mLastZoom; private Path mPath; private Track mTrack; private Point mBaseCoords; private GeoPoint mBaseLocation; private TrackThread mThread; private com.robert.maps.applib.view.TileView.OpenStreetMapViewProjection mBasePj; private boolean mThreadRunned = false; protected ExecutorService mThreadExecutor = Executors.newSingleThreadExecutor(new SimpleThreadFactory("CurrentTrack")); private TileView mOsmv; private Context mContext; IRemoteService mService = null; private boolean mIsBound; private ServiceConnection mConnection; public CurrentTrackOverlay(MainActivity mainMapActivity, PoiManager poiManager) { mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { mService = IRemoteService.Stub.asInterface(service); try { mService.registerCallback(mCallback); } catch (RemoteException e) { } } public void onServiceDisconnected(ComponentName className) { mService = null; } }; final String defStyle = PreferenceManager.getDefaultSharedPreferences(mainMapActivity).getString("pref_track_style_current", ""); mTrack = new Track(defStyle); mContext = mainMapActivity; mBaseCoords = new Point(); mBaseLocation = new GeoPoint(0, 0); mLastZoom = -1; mBasePj = null; mOsmv = null; mThread = new TrackThread(); mThread.setName("Current Track thread"); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setColor(mTrack.Color); mPaint.setStrokeWidth(mTrack.Width); mPaint.setAlpha(Color.alpha(mTrack.ColorShadow)); mPaint.setShadowLayer((float) mTrack.ShadowRadius, 0, 0, mTrack.ColorShadow); mIsBound = false; } @Override public void Free() { if(mBasePj != null) mBasePj.StopProcessing(); mThreadExecutor.shutdown(); super.Free(); } private class TrackThread extends Thread { @Override public void run() { mPath = null; if(mTrack == null) mTrack = new Track(); else mTrack.getPoints().clear(); final File folder = Ut.getRMapsMainDir(mContext, "data"); if(folder.canRead()){ SQLiteDatabase db = null; try { db = new com.robert.maps.applib.trackwriter.DatabaseHelper(mContext, folder.getAbsolutePath() + "/writedtrack.db").getReadableDatabase(); } catch (Exception e) { db = null; } if(db != null){ final Cursor c = db.rawQuery("SELECT lat, lon FROM trackpoints ORDER BY id", null); mPath = mBasePj.toPixelsTrackPoints(c, mBaseCoords, mBaseLocation); if(mPath != null && mPath.isEmpty()) mPath = null; db.close(); }; }; try { Message.obtain(mOsmv.getHandler(), Ut.MAPTILEFSLOADER_SUCCESS_ID).sendToTarget(); } catch (Exception e) { } mThreadRunned = false; } } @Override protected void onDraw(Canvas c, TileView osmv) { if (!mThreadRunned && (mTrack == null || mLastZoom != osmv.getZoomLevel())) { mOsmv = osmv; mLastZoom = osmv.getZoomLevel(); mBasePj = mOsmv.getProjection(); mThreadRunned = true; mThreadExecutor.execute(mThread); return; } if(mPath == null) return; final com.robert.maps.applib.view.TileView.OpenStreetMapViewProjection pj = osmv.getProjection(); final Point screenCoords = new Point(); pj.toPixels(mBaseLocation, screenCoords); c.save(); if(screenCoords.x != mBaseCoords.x && screenCoords.y != mBaseCoords.y){ c.translate(screenCoords.x - mBaseCoords.x, screenCoords.y - mBaseCoords.y); c.scale((float)osmv.mTouchScale, (float)osmv.mTouchScale, mBaseCoords.x, mBaseCoords.y); }; if(mPath != null) c.drawPath(mPath, mPaint); c.restore(); } @Override protected void onDrawFinished(Canvas c, TileView osmv) { } public void onResume(){ mTrack = null; mContext.bindService(new Intent(IRemoteService.class.getName()), mConnection, 0 /*Context.BIND_AUTO_CREATE*/); mIsBound = true; } public void onPause(){ if (mIsBound) { // If we have received the service, and hence registered with // it, then now is the time to unregister. if (mService != null) { try { mService.unregisterCallback(mCallback); } catch (RemoteException e) { // There is nothing special we need to do if the service // has crashed. } } // Detach our existing connection. mContext.unbindService(mConnection); mIsBound = false; } } private ITrackWriterCallback mCallback = new ITrackWriterCallback.Stub() { public void newPointWrited(double lat, double lon) { if(mThreadRunned) return; if(mPath == null){ mPath = new Path(); mBaseLocation = new GeoPoint((int)(lat*1E6), (int)(lon*1E6)); mBasePj = mOsmv.getProjection(); mBaseCoords = mBasePj.toPixels2(mBaseLocation); mPath.setLastPoint(mBaseCoords.x, mBaseCoords.y); } else { final GeoPoint geopoint = new GeoPoint((int)(lat*1E6), (int)(lon*1E6)); final Point point = mBasePj.toPixels2(geopoint); mPath.lineTo(point.x, point.y); } } @Override public void onTrackStatUpdate(int Cnt, double Distance, long Duration, double MaxSpeed, double AvgSpeed, long MoveTime, double AvgMoveSpeed) throws RemoteException { } }; }