Last active
February 1, 2017 18:31
-
-
Save shakil807g/405261c6594d859b6d9c5b0a18727ddb to your computer and use it in GitHub Desktop.
Car Tracking in Google Map
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class carTrackerActivity extends LocationTrackerActivity { | |
private GoogleMap mMap; | |
private static final LatLng MELBOURNE = new LatLng(-37.81319, 144.96298); | |
private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689); | |
private static final LatLng ADELAIDE = new LatLng(-34.92873, 138.59995); | |
private static final LatLng PERTH = new LatLng(-31.95285, 115.85734); | |
private static final LatLng LHR = new LatLng(51.471547, -0.460052); | |
private static final LatLng LAX = new LatLng(33.936524, -118.377686); | |
private static final LatLng JFK = new LatLng(40.641051, -73.777485); | |
private static final LatLng AKL = new LatLng(-37.006254, 174.783018); | |
private final static String LINE = "rvumEis{y[}DUaBGu@EqESyCMyAGGZGdEEhBAb@DZBXCPGP]Xg@LSBy@E{@SiBi@wAYa@AQGcAY]I]KeBm@_Bw@cBu@ICKB}KiGsEkCeEmBqJcFkFuCsFuCgB_AkAi@cA[qAWuAKeB?uALgB\\eDx@oBb@eAVeAd@cEdAaCp@s@PO@MBuEpA{@R{@NaAHwADuBAqAGE?qCS[@gAO{Fg@qIcAsCg@u@SeBk@aA_@uCsAkBcAsAy@AMGIw@e@_Bq@eA[eCi@QOAK@O@YF}CA_@Ga@c@cAg@eACW@YVgDD]Nq@j@}AR{@rBcHvBwHvAuFJk@B_@AgAGk@UkAkBcH{@qCuAiEa@gAa@w@c@o@mA{Ae@s@[m@_AaCy@uB_@kAq@_Be@}@c@m@{AwAkDuDyC_De@w@{@kB_A}BQo@UsBGy@AaA@cLBkCHsBNoD@c@E]q@eAiBcDwDoGYY_@QWEwE_@i@E}@@{BNaA@s@EyB_@c@?a@F}B\\iCv@uDjAa@Ds@Bs@EyAWo@Sm@a@YSu@c@g@Mi@GqBUi@MUMMMq@}@SWWM]C[DUJONg@hAW\\QHo@BYIOKcG{FqCsBgByAaAa@gA]c@I{@Gi@@cALcEv@_G|@gAJwAAUGUAk@C{Ga@gACu@A[Em@Sg@Y_AmA[u@Oo@qAmGeAeEs@sCgAqDg@{@[_@m@e@y@a@YIKCuAYuAQyAUuAWUaA_@wBiBgJaAoFyCwNy@cFIm@Bg@?a@t@yIVuDx@qKfA}N^aE@yE@qAIeDYaFBW\\eBFkANkANWd@gALc@PwAZiBb@qCFgCDcCGkCKoC`@gExBaVViDH}@kAOwAWe@Cg@BUDBU`@sERcCJ{BzFeB"; | |
private static final String TAG = "carTrackerActivity"; | |
LatLng latLng; | |
private Marker marker; | |
private List<LatLng> decodedPath; | |
public int endIndex = 0; | |
private CompositeDisposable _disposables; | |
boolean isFirstSet = false; | |
boolean isAniminating = false; | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_car_tracker); | |
ButterKnife.bind(this); | |
setUpMapIfNeeded(); | |
final Bitmap largeIcon = BitmapFactory.decodeResource(getResources(), R.drawable.red_car); | |
_disposables = new CompositeDisposable(); | |
decodedPath = new ArrayList<>(); | |
Disposable dispos = relay.filter(new Predicate<Location>() { | |
@Override | |
public boolean test(Location location) { | |
if(!isFirstSet){ | |
isFirstSet = true; | |
return true; | |
} | |
else if(mCurrentLocation.distanceTo(location) > 1){ | |
return true; | |
} | |
return false; | |
} | |
}).subscribe(new Consumer<Location>() { | |
@Override | |
public void accept(Location location) throws Exception { | |
Log.d(TAG, "accept: "+location.toString()); | |
decodedPath.add(new LatLng(location.getLatitude(), location.getLongitude())); | |
if(marker == null) { | |
marker = mMap.addMarker(new MarkerOptions() | |
.icon(BitmapDescriptorFactory.fromBitmap(largeIcon)) | |
.anchor(0.5f, 0.3f) | |
.position(new LatLng(location.getLatitude(), location.getLongitude()))); | |
} | |
if(!isAniminating){ | |
animateMarker(marker,new LatLng(location.getLatitude(), location.getLongitude())); | |
} | |
Toast.makeText(carTrackerActivity.this, ""+location, Toast.LENGTH_SHORT).show(); | |
mCurrentLocation = location; | |
} | |
}); | |
_disposables.add(dispos); | |
} | |
@Override | |
public void onResume() { | |
super.onResume(); | |
//setUpMapIfNeeded(); | |
} | |
private void setUpMapIfNeeded() { | |
if (mMap != null) { | |
return; | |
} | |
((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)) | |
.getMapAsync(new OnMapReadyCallback() { | |
@Override | |
public void onMapReady(GoogleMap googleMap) { | |
mMap = googleMap; | |
if (mMap != null) { | |
mMap.getUiSettings().setRotateGesturesEnabled(false); | |
mMap.getUiSettings().setTiltGesturesEnabled(false); | |
GoogleDirection.withServerKey(getResources().getString(R.string.direction_api_key)) | |
.from(new LatLng(24.87854,67.06409)) | |
.to(new LatLng(24.92612,67.06412)) | |
.execute(new DirectionCallback() { | |
@Override | |
public void onDirectionSuccess(Direction direction, String rawBody) { | |
if(direction.isOK()) { | |
decodedPath = direction.getRouteList().get(0).getOverviewPolyline().getPointList(); | |
// decodedPath = PolyUtil.decode(LINE); | |
Bitmap largeIcon = BitmapFactory.decodeResource(getResources(), R.drawable.red_car); | |
mMap.addPolyline(new PolylineOptions().addAll(decodedPath)); | |
//mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(decodedPath.get(0),15)); | |
// animateMarker(marker,decodedPath.get(startIndex)); | |
} else { | |
Log.d(TAG, "onDirectionSuccess: "+rawBody); | |
Toast.makeText(carTrackerActivity.this, ""+rawBody, Toast.LENGTH_SHORT).show(); | |
// Do something | |
} | |
} | |
@Override | |
public void onDirectionFailure(Throwable t) { | |
// Do something | |
} | |
}); | |
} | |
} | |
}); | |
} | |
void animateMarker(final Marker marker, LatLng finalPosition) { | |
isAniminating = true; | |
final Property<Marker, LatLng> property = Property.of(Marker.class, LatLng.class, "position"); | |
ObjectAnimator animator = ObjectAnimator.ofObject(marker,property,typeEvaluator,decodedPath.get(0)); | |
animator.setDuration(1000); | |
animator.setInterpolator(new LinearInterpolator()); | |
animator.start(); | |
animator.addListener(animatorListenerAdapter); | |
//animator.addListener(animatorListenerAdapter); | |
} | |
final TypeEvaluator<LatLng> typeEvaluator = new TypeEvaluator<LatLng>() { | |
@Override | |
public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) { | |
LatLng latLng = SphericalUtil.interpolate(startValue, endValue,fraction); | |
Location startLoca = new Location("startLocation"); | |
startLoca.setLatitude(marker.getPosition().latitude); | |
startLoca.setLongitude(marker.getPosition().longitude); | |
Location endLoca = new Location("endLocation"); | |
endLoca.setLatitude(latLng.latitude); | |
endLoca.setLongitude(latLng.longitude); | |
float testbearing = startLoca.bearingTo(endLoca); | |
// double bearing = SphericalUtil.computeHeading(startValue,latLng); | |
//Log.d(TAG, "testbearing: "+testbearing); | |
//Log.d(TAG, "bearing: "+bearing); | |
// float rot = (float) (fraction * bearing + (1 - fraction) * startRotation); | |
// float rota = -rot > 180 ? rot / 2 : rot; | |
// Log.d(TAG, "rotation: with brearing "+rota); | |
float rotataion = fraction * testbearing + (1 - fraction) * marker.getRotation(); | |
float Trota = -rotataion > 180 ? rotataion / 2 : rotataion; | |
marker.setRotation(Trota); | |
return latLng; | |
} | |
}; | |
Animator.AnimatorListener animatorListenerAdapter = new Animator.AnimatorListener() { | |
@Override | |
public void onAnimationStart(Animator animation) { | |
Log.d(TAG, "onAnimationStart: "); | |
isAniminating = true; | |
} | |
@Override | |
public void onAnimationEnd(Animator animation) { | |
Log.d(TAG, "onAnimationEnd: "); | |
decodedPath.remove(0); | |
if(decodedPath.size() < 1) { | |
isAniminating = false; | |
return; | |
} | |
else { | |
ObjectAnimator animator = (ObjectAnimator) animation.clone(); | |
animator.setObjectValues(decodedPath.get(0)); | |
animator.start(); | |
animation.addListener(this); | |
} | |
} | |
@Override | |
public void onAnimationCancel(Animator animation) { | |
Log.d(TAG, "onAnimationCancel: "); | |
} | |
@Override | |
public void onAnimationRepeat(Animator animation) { | |
Log.d(TAG, "onAnimationRepeat: "); | |
} | |
}; | |
@Override | |
protected void onDestroy() { | |
super.onDestroy(); | |
_disposables.clear(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class LocationTrackerActivity extends AppCompatActivity implements | |
GoogleApiClient.ConnectionCallbacks, | |
GoogleApiClient.OnConnectionFailedListener, | |
LocationListener, | |
ResultCallback<LocationSettingsResult> | |
{ | |
private static final String TAG = "LocationTrackerActivity"; | |
private static final int REQUEST_CHECK_SETTINGS = 0x1; | |
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 5000; | |
private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = | |
UPDATE_INTERVAL_IN_MILLISECONDS / 2; | |
// Keys for storing activity state in the Bundle. | |
private final static String KEY_LOCATION = "location"; | |
private final static String KEY_LAST_UPDATED_TIME_STRING = "last-updated-time-string"; | |
private GoogleApiClient mGoogleApiClient; | |
private LocationRequest mLocationRequest; | |
private LocationSettingsRequest mLocationSettingsRequest; | |
public Location mCurrentLocation; | |
private String mLastUpdateTime; | |
protected final PublishRelay<Location> relay = PublishRelay.create(); | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
Log.d(TAG, "onCreate: "); | |
mLastUpdateTime = ""; | |
// Update values using data stored in the Bundle. | |
updateValuesFromBundle(savedInstanceState); | |
// Kick off the process of building the GoogleApiClient, LocationRequest, and | |
// LocationSettingsRequest objects. | |
buildGoogleApiClient(); | |
createLocationRequest(); | |
buildLocationSettingsRequest(); | |
} | |
private void updateValuesFromBundle(Bundle savedInstanceState) { | |
if (savedInstanceState != null) { | |
Log.d(TAG, "updateValuesFromBundle: "); | |
if (savedInstanceState.keySet().contains(KEY_LOCATION)) { | |
mCurrentLocation = savedInstanceState.getParcelable(KEY_LOCATION); | |
relay.accept(mCurrentLocation); | |
} | |
if (savedInstanceState.keySet().contains(KEY_LAST_UPDATED_TIME_STRING)) { | |
mLastUpdateTime = savedInstanceState.getString(KEY_LAST_UPDATED_TIME_STRING); | |
} | |
} | |
} | |
protected synchronized void buildGoogleApiClient() { | |
Log.i(TAG, "Building GoogleApiClient"); | |
mGoogleApiClient = new GoogleApiClient.Builder(this) | |
.addConnectionCallbacks(this) | |
.addOnConnectionFailedListener(this) | |
.addApi(LocationServices.API) | |
.build(); | |
} | |
protected void createLocationRequest() { | |
mLocationRequest = new LocationRequest(); | |
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS); | |
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS); | |
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); | |
} | |
protected void buildLocationSettingsRequest() { | |
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder(); | |
builder.addLocationRequest(mLocationRequest); | |
mLocationSettingsRequest = builder.build(); | |
} | |
protected void checkLocationSettings() { | |
PendingResult<LocationSettingsResult> result = | |
LocationServices.SettingsApi.checkLocationSettings( | |
mGoogleApiClient, | |
mLocationSettingsRequest | |
); | |
result.setResultCallback(this); // call on onResult | |
} | |
@Override | |
public void onResult(LocationSettingsResult locationSettingsResult) { | |
final Status status = locationSettingsResult.getStatus(); | |
switch (status.getStatusCode()) { | |
case LocationSettingsStatusCodes.SUCCESS: | |
Log.i(TAG, "All location settings are satisfied."); | |
startLocationUpdates(); | |
break; | |
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: | |
Log.i(TAG, "Location settings are not satisfied. Show the user a dialog to" + | |
"upgrade location settings "); | |
try { | |
// Show the dialog by calling startResolutionForResult(), and check the result | |
// in onActivityResult(). | |
status.startResolutionForResult(this, REQUEST_CHECK_SETTINGS); | |
} catch (IntentSender.SendIntentException e) { | |
Log.i(TAG, "PendingIntent unable to execute request."); | |
} | |
break; | |
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE: | |
Log.i(TAG, "Location settings are inadequate, and cannot be fixed here. Dialog " + | |
"not created."); | |
break; | |
} | |
} | |
@Override | |
protected void onActivityResult(int requestCode, int resultCode, Intent data) { | |
switch (requestCode) { | |
// Check for the integer request code originally supplied to startResolutionForResult(). | |
case REQUEST_CHECK_SETTINGS: | |
switch (resultCode) { | |
case Activity.RESULT_OK: | |
Log.i(TAG, "User agreed to make required location settings changes."); | |
startLocationUpdates(); | |
break; | |
case Activity.RESULT_CANCELED: | |
Log.i(TAG, "User chose not to make required location settings changes."); | |
break; | |
} | |
break; | |
} | |
} | |
protected void startLocationUpdates() { | |
Log.d(TAG, "startLocationUpdates: "); | |
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { | |
return; | |
} | |
LocationServices.FusedLocationApi.requestLocationUpdates( | |
mGoogleApiClient, | |
mLocationRequest, | |
this //// call onLocationChanged | |
); | |
} | |
protected void stopLocationUpdates() { | |
LocationServices.FusedLocationApi.removeLocationUpdates( | |
mGoogleApiClient, | |
this | |
); | |
} | |
@Override | |
protected void onStart() { | |
super.onStart(); | |
if(mGoogleApiClient!=null) | |
mGoogleApiClient.connect(); | |
} | |
@Override | |
public void onResume() { | |
super.onResume(); | |
Log.d(TAG, "onResume: "); | |
if (mGoogleApiClient!=null && mGoogleApiClient.isConnected() ) { | |
Log.d(TAG, "onResume: mGoogleApiClient isConnected"); | |
startLocationUpdates(); | |
} | |
} | |
@Override | |
protected void onPause() { | |
super.onPause(); | |
// Stop location updates to save battery, but don't disconnect the GoogleApiClient object. | |
if (mGoogleApiClient!=null && mGoogleApiClient.isConnected()) { | |
Log.d(TAG, "onPause: "); | |
stopLocationUpdates(); | |
} | |
} | |
@Override | |
protected void onStop() { | |
super.onStop(); | |
Log.d(TAG, "onStop: "); | |
if(mGoogleApiClient!=null) | |
mGoogleApiClient.disconnect(); | |
} | |
/** | |
* Runs when a GoogleApiClient object successfully connects. | |
*/ | |
@Override | |
public void onConnected(Bundle connectionHint) { | |
Log.i(TAG, "Connected to GoogleApiClient"); | |
if (mCurrentLocation == null) { | |
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { | |
return; | |
} | |
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); | |
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date()); | |
if(mCurrentLocation!=null) | |
relay.accept(mCurrentLocation); | |
} | |
checkLocationSettings(); | |
} | |
@Override | |
public void onLocationChanged(Location location) { | |
Log.d(TAG, "onLocationChanged: "); | |
mCurrentLocation = location; | |
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date()); | |
if(mCurrentLocation!=null) | |
relay.accept(mCurrentLocation); | |
} | |
@Override | |
public void onConnectionSuspended(int cause) { | |
Log.i(TAG, "Connection suspended"); | |
} | |
@Override | |
public void onConnectionFailed(ConnectionResult result) { | |
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode()); | |
} | |
public void onSaveInstanceState(Bundle savedInstanceState) { | |
Log.d(TAG, "onSaveInstanceState: "); | |
savedInstanceState.putParcelable(KEY_LOCATION, mCurrentLocation); | |
savedInstanceState.putString(KEY_LAST_UPDATED_TIME_STRING, mLastUpdateTime); | |
super.onSaveInstanceState(savedInstanceState); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MarkerAnimation { | |
static void animateMarkerToGB(final Marker marker, final LatLng finalPosition, final LatLngInterpolator latLngInterpolator) { | |
final LatLng startPosition = marker.getPosition(); | |
final Handler handler = new Handler(); | |
final long start = SystemClock.uptimeMillis(); | |
final Interpolator interpolator = new AccelerateDecelerateInterpolator(); | |
final float durationInMs = 3000; | |
handler.post(new Runnable() { | |
long elapsed; | |
float t; | |
float v; | |
@Override | |
public void run() { | |
// Calculate progress using interpolator | |
elapsed = SystemClock.uptimeMillis() - start; | |
t = elapsed / durationInMs; | |
v = interpolator.getInterpolation(t); | |
marker.setPosition(latLngInterpolator.interpolate(v, startPosition, finalPosition)); | |
// Repeat till progress is complete. | |
if (t < 1) { | |
// Post again 16ms later. | |
handler.postDelayed(this, 16); | |
} | |
} | |
}); | |
} | |
@TargetApi(Build.VERSION_CODES.HONEYCOMB) | |
static void animateMarkerToHC(final Marker marker, final LatLng finalPosition, final LatLngInterpolator latLngInterpolator) { | |
final LatLng startPosition = marker.getPosition(); | |
ValueAnimator valueAnimator = new ValueAnimator(); | |
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { | |
@Override | |
public void onAnimationUpdate(ValueAnimator animation) { | |
float v = animation.getAnimatedFraction(); | |
LatLng newPosition = latLngInterpolator.interpolate(v, startPosition, finalPosition); | |
marker.setPosition(newPosition); | |
} | |
}); | |
valueAnimator.setFloatValues(0, 1); // Ignored. | |
valueAnimator.setDuration(3000); | |
valueAnimator.start(); | |
} | |
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) | |
static void animateMarkerToICS(Marker marker, LatLng finalPosition, final LatLngInterpolator latLngInterpolator) { | |
TypeEvaluator<LatLng> typeEvaluator = new TypeEvaluator<LatLng>() { | |
@Override | |
public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) { | |
return latLngInterpolator.interpolate(fraction, startValue, endValue); | |
} | |
}; | |
Property<Marker, LatLng> property = Property.of(Marker.class, LatLng.class, "position"); | |
ObjectAnimator animator = ObjectAnimator.ofObject(marker, property, typeEvaluator, finalPosition); | |
animator.setDuration(3000); | |
animator.start(); | |
} | |
public class Spherical implements LatLngInterpolator { | |
/* From github.com/googlemaps/android-maps-utils */ | |
@Override | |
public LatLng interpolate(float fraction, LatLng from, LatLng to) { | |
// http://en.wikipedia.org/wiki/Slerp | |
double fromLat = toRadians(from.latitude); | |
double fromLng = toRadians(from.longitude); | |
double toLat = toRadians(to.latitude); | |
double toLng = toRadians(to.longitude); | |
double cosFromLat = cos(fromLat); | |
double cosToLat = cos(toLat); | |
// Computes Spherical interpolation coefficients. | |
double angle = computeAngleBetween(fromLat, fromLng, toLat, toLng); | |
double sinAngle = sin(angle); | |
if (sinAngle < 1E-6) { | |
return from; | |
} | |
double a = sin((1 - fraction) * angle) / sinAngle; | |
double b = sin(fraction * angle) / sinAngle; | |
// Converts from polar to vector and interpolate. | |
double x = a * cosFromLat * cos(fromLng) + b * cosToLat * cos(toLng); | |
double y = a * cosFromLat * sin(fromLng) + b * cosToLat * sin(toLng); | |
double z = a * sin(fromLat) + b * sin(toLat); | |
// Converts interpolated vector back to polar. | |
double lat = atan2(z, sqrt(x * x + y * y)); | |
double lng = atan2(y, x); | |
return new LatLng(toDegrees(lat), toDegrees(lng)); | |
} | |
private double computeAngleBetween(double fromLat, double fromLng, double toLat, double toLng) { | |
// Haversine's formula | |
double dLat = fromLat - toLat; | |
double dLng = fromLng - toLng; | |
return 2 * asin(sqrt(pow(sin(dLat / 2), 2) + | |
cos(fromLat) * cos(toLat) * pow(sin(dLng / 2), 2))); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment