Skip to content

Instantly share code, notes, and snippets.

@shakil807g
Last active February 1, 2017 18:31
Show Gist options
  • Save shakil807g/405261c6594d859b6d9c5b0a18727ddb to your computer and use it in GitHub Desktop.
Save shakil807g/405261c6594d859b6d9c5b0a18727ddb to your computer and use it in GitHub Desktop.
Car Tracking in Google Map
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();
}
}
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);
}
}
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