I have an app in which I am continuously tracking user's location using Google Plays new service API for Maps. I am updating the location every single second and I am also checking user activity like STILL, TILTING, IN VEHICLE, etc to get the better location tracking. I am able to draw a path using my code but it's not accurate and differs very much from the road where the user actually drives/walk. It always draws the line someway far from the actual user's path.
My Service:-
public class MyService extends Service implements LocationListener {
private final Context mContext;
private static MyService mInstance = null;
private final static String TAG = "RidingTimerService";
boolean isGPSEnabled = false;
private long mStartTime = 0L;
private long timeInMilliseconds = 0L;
private long timeSwapBuff = 0L;
private long updatedTime = 0L;
private Handler mHandler = null;
private int mHours = 0;
// Declaring a Location Manager
private LocationManager mLocationManager = null;
private Location mCurrentLocation = null; // location
private double[][] positions;
private long[] times;
private final Integer data_points = 2; // how many data points to calculate
private double mTravelledDistance = 0.0f;
private SharedPreferences mPreferences = null;
private ArrayList<LatLng> mDirectionsPoints = new ArrayList<LatLng>();
public boolean mIsPhoneMoving = false;
public int mActivityType = -1;
int counter = 0;
private IntentFilter mBroadcastFilter;
private DetectionRequester mDetectionRequester;
private DetectionRemover mDetectionRemover;
public MyService() {
mContext = this;
}
@Override
public void onCreate() {
super.onCreate();
mInstance = this;
// two arrays for position and time.
positions = new double[data_points][2];
times = new long[data_points];
mStartTime = SystemClock.uptimeMillis();
mHandler = new Handler();
mHandler.postDelayed(countDownTimerThread, 0);
mPreferences = getSharedPreferences(MyPreferences.PREFERENCES,
Context.MODE_PRIVATE);
// Create a new Intent filter for the broadcast receiver
mBroadcastFilter = new IntentFilter(
MyConstants.ACTION_REFRESH_STATUS_LIST);
mBroadcastFilter.addCategory(MyConstants.CATEGORY_LOCATION_SERVICES);
// Get detection requester and remover objects
mDetectionRequester = new DetectionRequester(this);
mDetectionRemover = new DetectionRemover(this);
mDirectionsPoints.clear();
}
/**
* Pause the timer
*/
public void pauseRide() {
timeSwapBuff += timeInMilliseconds;
mHandler.removeCallbacks(countDownTimerThread);
mLocationManager.removeUpdates(this);
}
/**
* Restart the timer
*/
public void reStartRide() {
mStartTime = SystemClock.uptimeMillis();
mHandler.postDelayed(countDownTimerThread, 0);
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
0, 0, this);
}
@Override
public void onDestroy() {
mHandler.removeCallbacks(countDownTimerThread);
mLocationManager.removeUpdates(this);
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
getLocation();
return super.onStartCommand(intent, flags, startId);
}
/**
* Timer thread
*/
private final Runnable countDownTimerThread = new Runnable() {
public void run() {
mHours = 0;
timeInMilliseconds = SystemClock.uptimeMillis() - mStartTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
int secs = (int) (updatedTime / 1000);
final int mins = secs / 60;
mHours = mins / 60;
secs = secs % 60;
final Message msg = new Message();
final Bundle bundle = new Bundle();
bundle.putInt(MyPreferences.BROADCAST_CODES, 300);
bundle.putString(
"time",
String.format("%02d", mHours) + ":"
+ String.format("%02d", mins) + ":"
+ String.format("%02d", secs));
msg.setData(bundle);
final Intent intent = new Intent(MyConstants.BROADCAST_INTENT);
intent.putExtras(bundle);
sendBroadcast(intent);
mHandler.postDelayed(this, 1000);
}
};
@Override
public IBinder onBind(final Intent intent) {
return null;
}
@Override
public void onLocationChanged(final Location location) {
if (location != null) {
LocationUtils.sLatitude = location.getLatitude();
LocationUtils.sLongitude = location.getLongitude();
mDirectionsPoints.add(new LatLng(LocationUtils.sLatitude,
LocationUtils.sLongitude));
riderLocation(location);
} else {
Log.i(TAG, "Location is not available.");
}
}
/**
* Calculate speed, distance and average speed. Send Broadcast which
* received by activities
*
* @param location
*/
private void riderLocation(final Location location) {
DecimalFormat formatter = new DecimalFormat("#0.00");
double distance = 0.0;
Double speed = 0.0;
long t1 = 0l;
final float[] results = new float[3];
positions[counter][0] = location.getLatitude();
positions[counter][1] = location.getLongitude();
times[counter] = location.getTime();
final Bundle bundle = new Bundle();
bundle.putInt(MyPreferences.BROADCAST_CODES, 200);
distance = calculateDistance(positions[counter][0],
positions[counter][1], positions[(counter + (data_points - 1))
% data_points][0],
positions[(counter + (data_points - 1)) % data_points][1]);
Location.distanceBetween(positions[counter][0], positions[counter][1],
positions[(counter + (data_points - 1)) % data_points][0],
positions[(counter + (data_points - 1)) % data_points][1],
results);
mTravelledDistance += results[0] / 1000;
LocationUtils.sDistance = formatter
.format((mTravelledDistance * 100.0) / 100.0);
final double averageSpeed = mTravelledDistance / mHours;
LocationUtils.sAverageSpeed = formatter
.format((averageSpeed * 100.0) / 100.0);
if (location.hasSpeed()) {
speed = location.getSpeed() * 3.6;
LocationUtils.sSpeed = speed.intValue();
} else {
try {
t1 = times[counter]
- times[(counter + (data_points - 1)) % data_points];
} catch (final NullPointerException e) {
// all good, just not enough data yet.
}
speed = (distance / t1) * 3.6;
LocationUtils.sSpeed = speed.intValue();
counter = (counter + 1) % data_points;
}
LocationUtils.sLatitude = location.getLatitude();
LocationUtils.sLongitude = location.getLongitude();
final Intent intent = new Intent(MyConstants.BROADCAST_INTENT);
intent.putExtras(bundle);
sendBroadcast(intent);
}
public void onProviderDisabled(final String arg0) {
Toast.makeText(getApplicationContext(), "Gps Disabled",
Toast.LENGTH_LONG).show();
}
public void onProviderEnabled(final String arg0) {
Toast.makeText(getApplicationContext(), "Gps Enabled",
Toast.LENGTH_SHORT).show();
}
/**
* @return location
*/
public Location getLocation() {
try {
mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
// getting GPS status
isGPSEnabled = mLocationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (!isGPSEnabled) {
// no network provider is enabled
showSettingsAlert();
} else {
// if GPS Enabled get lat/long using GPS Services
if (isGPSEnabled) {
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 0, 0, this);
Log.d(TAG, "GPS Enabled");
if (mCurrentLocation == null) {
if (mLocationManager != null) {
mCurrentLocation = mLocationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (mCurrentLocation != null) {
LocationUtils.sLatitude = mCurrentLocation
.getLatitude();
LocationUtils.sLongitude = mCurrentLocation
.getLongitude();
}
}
} else {
LocationUtils.sLatitude = mCurrentLocation
.getLatitude();
LocationUtils.sLongitude = mCurrentLocation
.getLongitude();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return mCurrentLocation;
}
/**
* @fn public static RidingTimerService getInstance()
* @brief returns instance of the service.
* @return RidingTimerService instance
*/
public static MyService getInstance() {
return mInstance;
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
/**
* Reset all the values stored in Preferences
*/
public void resetAllText() {
mPreferences.edit().putString(MyPreferences.LATITUDE, "0.0").commit();
mPreferences.edit().putString(MyPreferences.LONGITUDE, "0.0")
.commit();
mPreferences.edit().putString(MyPreferences.SPEED, "0.0").commit();
mPreferences.edit().putString(MyPreferences.AVERAGE_SPEED, "0.0")
.commit();
mPreferences.edit().putString(MyPreferences.DISTANCE, "0.0").commit();
}
/**
* Respond to "Start" button by requesting activity recognition updates.
*
* @param view
* The view that triggered this method.
*/
public void onStartUpdates() {
// Pass the update request to the requester object
mDetectionRequester.requestUpdates();
}
/**
* Respond to "Stop" button by canceling updates.
*
* @param view
* The view that triggered this method.
*/
public void onStopUpdates() {
// Pass the remove request to the remover object
mDetectionRemover.removeUpdates(mDetectionRequester
.getRequestPendingIntent());
/*
* Cancel the PendingIntent. Even if the removal request fails,
* canceling the PendingIntent will stop the updates.
*/
mDetectionRequester.getRequestPendingIntent().cancel();
}
/**
* Function to show settings alert dialog On pressing Settings button will
* lauch Settings Options
* */
public void showSettingsAlert() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
alertDialog.setTitle("GPS");
alertDialog.setMessage("GPS is not enabled. Do you want to enable it?");
// On pressing Settings button
alertDialog.setPositiveButton("Settings",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(
Settings.ACTION_LOCATION_SOURCE_SETTINGS);
mContext.startActivity(intent);
}
});
// on pressing cancel button
alertDialog.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
// Showing Alert Message
alertDialog.show();
}
/**
* @return List of Direction points
*/
public ArrayList<LatLng> getDirectionsPoints() {
if (mDirectionsPoints != null) {
return mDirectionsPoints;
} else {
mDirectionsPoints = new ArrayList<LatLng>();
return mDirectionsPoints;
}
}
/**
* Calculate distance
*
* @param lat1
* @param lon1
* @param lat2
* @param lon2
* @return
*/
private double calculateDistance(final double lat1, final double lon1,
final double lat2, final double lon2) {
// haversine great circle distance approximation, returns meters
final double theta = lon1 - lon2;
double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2))
+ Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2))
* Math.cos(deg2rad(theta));
dist = Math.acos(dist);
dist = rad2deg(dist);
dist = dist * 60; // 60 nautical miles per degree of seperation
dist = dist * 1852; // 1852 meters per nautical mile
return dist;
}
private double deg2rad(final double deg) {
return (deg * Math.PI / 180.0);
}
private double rad2deg(final double rad) {
return (rad * 180.0 / Math.PI);
}
}
I kept location updates every 1 seconds and activity recognition updates every 3 seconds. I am able to get the location but path is not drawn properly in Google maps.
Code to draw path :-
public class MapsActivity extends FragmentActivity {
private static GoogleMap mGoogleMap = null;
private static final String TAG = "MapsActivity";
private Button mBtnStartRide, mBtnPauseRide, mBtnStopRide = null;
private static TextView mTxtLatLong, mTxtTimer, mTxtTotalSize,
mTxtSpeed = null;
private static PolylineOptions mPolyLineOptions = null;
// Storing the directions returned by the direcction api
private SharedPreferences mPreferences = null;
private MapsBroadcastReceiver receiver = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
receiver = new MapsBroadcastReceiver();
mPreferences = getSharedPreferences(TestPreferences.PREFERENCES,
Context.MODE_PRIVATE);
mTxtLatLong = (TextView) findViewById(R.id.txtLatLong);
mTxtTimer = (TextView) findViewById(R.id.txtTimer);
mTxtTotalSize = (TextView) findViewById(R.id.txtDirectionsSize);
mTxtSpeed = (TextView) findViewById(R.id.txtSpeed);
mBtnStartRide = (Button) findViewById(R.id.btn_start_ride);
mBtnPauseRide = (Button) findViewById(R.id.btn_pause_ride);
mBtnStopRide = (Button) findViewById(R.id.btn_stop_ride);
final Button mBtnCenter = (Button) findViewById(R.id.btn_center);
mBtnCenter.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
animateCameraTo();
}
});
mBtnStartRide.setOnClickListener(btnStartRideClickListener);
mBtnPauseRide.setOnClickListener(btnPauseRideClickListener);
mBtnStopRide.setOnClickListener(btnStopRideClickListener);
initilizeMap();
}
/**
* Start Ride Button Click Listener
*/
private OnClickListener btnStartRideClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
if (mPreferences.getBoolean(TestPreferences.IS_RIDE_PAUSE, false)) {
if (MyService.getInstance() != null) {
MyService.getInstance().reStartRide();
}
} else {
startService(new Intent(MapsActivity.this,
MyService.class));
}
mPreferences.edit().putBoolean(TestPreferences.IS_RIDE_START, true)
.commit();
mPreferences.edit().remove(TestPreferences.IS_RIDE_PAUSE).commit();
mPreferences.edit().remove(TestPreferences.IS_RIDE_STOPPED)
.commit();
mBtnStartRide.setVisibility(View.GONE);
mBtnPauseRide.setVisibility(View.VISIBLE);
mBtnStopRide.setVisibility(View.VISIBLE);
}
};
/**
* Start Ride Button Click Listener
*/
private OnClickListener btnPauseRideClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
MyService.getInstance().pauseRide();
mPreferences.edit().putBoolean(TestPreferences.IS_RIDE_PAUSE, true)
.commit();
mPreferences.edit()
.putBoolean(TestPreferences.IS_RIDE_START, false).commit();
mBtnStartRide.setVisibility(View.VISIBLE);
mBtnPauseRide.setVisibility(View.GONE);
mBtnStopRide.setVisibility(View.VISIBLE);
}
};
/**
* Stop Ride Button Click Listener
*/
private OnClickListener btnStopRideClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
stopService(new Intent(MapsActivity.this, MyService.class));
mPreferences.edit().remove(TestPreferences.IS_RIDE_PAUSE).commit();
mPreferences.edit()
.putBoolean(TestPreferences.IS_RIDE_START, false).commit();
mPreferences.edit()
.putBoolean(TestPreferences.IS_RIDE_STOPPED, true).commit();
mBtnStartRide.setVisibility(View.VISIBLE);
mBtnPauseRide.setVisibility(View.GONE);
mBtnStopRide.setVisibility(View.GONE);
}
};
@Override
protected void onResume() {
super.onResume();
registerReceiver(receiver, new IntentFilter(
MyConstants.BROADCAST_INTENT));
initilizeMap();
if (mPreferences.getBoolean(TestPreferences.IS_RIDE_START, false)) {
mBtnStartRide.setVisibility(View.GONE);
mBtnPauseRide.setVisibility(View.VISIBLE);
mBtnStopRide.setVisibility(View.VISIBLE);
} else if (mPreferences
.getBoolean(TestPreferences.IS_RIDE_PAUSE, false)) {
mBtnStartRide.setVisibility(View.VISIBLE);
mBtnPauseRide.setVisibility(View.GONE);
mBtnStopRide.setVisibility(View.VISIBLE);
} else if (mPreferences.getBoolean(TestPreferences.IS_RIDE_STOPPED,
false)) {
// Show start button and gone Pause & Stop both
mBtnStartRide.setVisibility(View.VISIBLE);
mBtnPauseRide.setVisibility(View.GONE);
mBtnStopRide.setVisibility(View.GONE);
} else {
// Show start button and gone Pause & Stop both
mBtnStartRide.setVisibility(View.VISIBLE);
mBtnPauseRide.setVisibility(View.GONE);
mBtnStopRide.setVisibility(View.GONE);
}
setAllText();
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
@Override
protected void onDestroy() {
super.onDestroy();
mGoogleMap = null;
}
/**
* Function to load map. If map is not created it will create it for you
* */
private void initilizeMap() {
if (mGoogleMap == null) {
mGoogleMap = ((MapFragment) getFragmentManager().findFragmentById(
R.id.map)).getMap();
// check if map is created successfully or not
if (mGoogleMap == null) {
Toast.makeText(getApplicationContext(),
"Sorry! unable to create maps", Toast.LENGTH_SHORT)
.show();
} else {
mPolyLineOptions = new PolylineOptions().width(6).color(
Color.BLUE);
mGoogleMap.setTrafficEnabled(true);
mGoogleMap.getUiSettings().setMyLocationButtonEnabled(true);
mGoogleMap.getUiSettings().setRotateGesturesEnabled(true);
mGoogleMap.getUiSettings().setCompassEnabled(true);
mGoogleMap.getUiSettings().setZoomGesturesEnabled(true);
mGoogleMap.getUiSettings().setZoomControlsEnabled(true);
if (MyService.getInstance() != null
&& MyService.getInstance().getDirectionsPoints() != null
&& !MyService.getInstance().getDirectionsPoints()
.isEmpty()
&& MyService.getInstance().getDirectionsPoints()
.size() >= 1) {
mGoogleMap.addMarker(new MarkerOptions()
.position(
MyService.getInstance()
.getDirectionsPoints().get(0))
.anchor(0.8f, 1.0f).title("Your Location"));
animateCameraTo(MyService.getInstance()
.getDirectionsPoints().get(0).latitude,
MyService.getInstance().getDirectionsPoints()
.get(0).longitude);
}
}
} else {
mPolyLineOptions = new PolylineOptions().width(6).color(Color.BLUE);
mGoogleMap.getUiSettings().setMyLocationButtonEnabled(true);
mGoogleMap.getUiSettings().setRotateGesturesEnabled(true);
mGoogleMap.getUiSettings().setCompassEnabled(true);
mGoogleMap.getUiSettings().setZoomGesturesEnabled(true);
mGoogleMap.getUiSettings().setZoomControlsEnabled(true);
if (MyService.getInstance() != null
&& MyService.getInstance().getDirectionsPoints() != null
&& !MyService.getInstance().getDirectionsPoints()
.isEmpty()
&& MyService.getInstance().getDirectionsPoints().size() >= 1) {
Log.i(TAG, "Lat long in resume2222222222 = "
+ MyService.getInstance().getDirectionsPoints()
.get(0).latitude
+ ", "
+ MyService.getInstance().getDirectionsPoints()
.get(0).longitude);
mGoogleMap.addMarker(new MarkerOptions()
.position(
MyService.getInstance().getDirectionsPoints()
.get(0)).anchor(0.8f, 1.0f)
.title("Your Location"));
animateCameraTo(MyService.getInstance().getDirectionsPoints()
.get(0).latitude, MyService.getInstance()
.getDirectionsPoints().get(0).longitude);
}
}
}
/**
* @author Scorpion
*
*/
private class MapsBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getExtras().getInt(TestPreferences.BROADCAST_CODES)) {
case 100:
showErrorDialog(intent.getExtras().getInt(
TestPreferences.BROADCAST_CODES));
break;
case 200:
setAllText();
break;
case 300:
if (intent.getExtras().getString("time") != null) {
mTxtTimer.setText("Timer - "
+ intent.getExtras().getString("time"));
} else {
mTxtTimer.setText("Timer - 00:00:00");
}
break;
default:
break;
}
if (MyService.getInstance() != null
&& !MyService.getInstance().getDirectionsPoints()
.isEmpty()
&& MyService.getInstance().getDirectionsPoints().size() == 1) {
mGoogleMap.addMarker(new MarkerOptions()
.position(
MyService.getInstance().getDirectionsPoints()
.get(0)).anchor(0.8f, 1.0f)
.title("Your Location"));
}
}
}
/**
*
*/
public void setAllText() {
mTxtLatLong.setText("Lat - " + LocationUtils.sLatitude + ", Lng - "
+ LocationUtils.sLongitude);
mTxtSpeed.setText("Speed - " + LocationUtils.sSpeed);
mTxtTotalSize.setText("Distance - " + LocationUtils.sDistance);
}
/**
* Animate to position on Google Maps
*
* @param lat
* @param lng
*/
private void animateCameraTo() {
// Saving the points in a polyline
if (MyService.getInstance() != null
&& MyService.getInstance().getDirectionsPoints() != null
&& !MyService.getInstance().getDirectionsPoints().isEmpty()) {
mPolyLineOptions.geodesic(true);
mPolyLineOptions.addAll(MyService.getInstance()
.getDirectionsPoints());
// Drawing the path on the map Polyline route =
mGoogleMap.addPolyline(mPolyLineOptions);
int index = MyService.getInstance().getDirectionsPoints().size() - 1;
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(MyService.getInstance().getDirectionsPoints()
.get(index)).zoom(20).build();
mGoogleMap.animateCamera(CameraUpdateFactory
.newCameraPosition(cameraPosition));
}
}
/**
* Animate to position on Google Maps
*
* @param lat
* @param lng
*/
private void animateCameraTo(final double lat, final double lng) {
// Saving the points in a polyline
if (MyService.getInstance() != null
&& MyService.getInstance().getDirectionsPoints() != null
&& !MyService.getInstance().getDirectionsPoints().isEmpty()) {
mPolyLineOptions.geodesic(true);
mPolyLineOptions.addAll(MyService.getInstance()
.getDirectionsPoints());
// Drawing the path on the map
mGoogleMap.addPolyline(mPolyLineOptions);
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(new LatLng(lat, lng)).zoom(20).build();
mGoogleMap.animateCamera(CameraUpdateFactory
.newCameraPosition(cameraPosition));
}
}
/**
* Show a dialog returned by Google Play services for the connection error
* code
*
* @param errorCode
* An error code returned from onConnectionFailed
*/
private void showErrorDialog(int errorCode) {
// Get the error dialog from Google Play services
Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(errorCode,
MapsActivity.this,
LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST);
// If Google Play services can provide an error dialog
if (errorDialog != null) {
// Create a new DialogFragment in which to show the error dialog
ErrorDialogFragment errorFragment = new ErrorDialogFragment();
// Set the dialog in the DialogFragment
errorFragment.setDialog(errorDialog);
// Show the error dialog in the DialogFragment
errorFragment.show(getSupportFragmentManager(),
LocationUtils.APPTAG);
}
}
}
Coordinate results got from Location provider :- 23.030392522689674, 72.5570888165469, 23.030408166940184, 72.55708600340783, 23.030451207802273, 72.55708215400317, 23.030448342522195, 72.5570607428365, 23.03045605637773, 72.55702903413072, 23.03046687434995, 72.55702007867455, 23.030481227996425, 72.55702017125606, 23.03049188235562, 72.55701618151457, 23.030501580461667, 72.55701051075931, 23.030506644074638, 72.55700568837983, 23.030510243171772, 72.55699463185964, 23.03051656621021, 72.55698811382064, 23.030523584332027, 72.55698589863236, 23.030527893257556, 72.5569835596, 23.03052731568596, 72.55698681171178, 23.030533706759005, 72.55699683791043, 23.03053795413862, 72.5570022232021, 23.03054422659466, 72.55700788646914, 23.030550353227323, 72.5570133047868, 23.03056167617575, 72.5570171806126, 23.030572274532982, 72.55702744953462, 23.03057623596164, 72.55703687229187, 23.03058756510295, 72.55703589208271, 23.030591797598742, 72.5570396833694, 23.030597556470788, 72.55703954449652, 23.030602030769657, 72.55704359454182, 23.030606735158617, 72.55704993131606, 23.030611670633565, 72.55705060538087,23.030618875802222, 72.55705181604097, 23.030629137631596, 72.55705043471286, 23.030651405170016, 72.55705440295588, 23.03066642161307, 72.55705285209174, 23.030690454277963, 72.55703884780276, 23.030708214416187, 72.55703489882957, 23.03072341369183, 72.5570340196122, 23.030737371000015, 72.55703289416898, 23.03075088423441, 72.55703750535102, 23.030767572625837, 72.55704489874579, 23.030794398930176, 72.55703870239826, 23.03081655932613, 72.55702474270966, 23.030827505666753, 72.5570121351611, 23.03083720431765, 72.55700390084714, 23.03084624667527, 72.55700122660554, 23.030859495795887, 72.55699948514881, 23.030870357210333, 72.55699625144317, 23.030881843633054
Create a new Google Map API Key from the API console using the steps demonstrated in this tutorial. Create a New Android Studio Project and select the template as Google Maps Activity. Add the API key inside the google_maps_api.
Add line or shape.Select a layer and click where to start drawing. A layer can have 2,000 lines, shapes or places. Click each corner or bend of your line or shape. To move the map, click and hold the mouse.
Choose or create a project, enable billing, and enable the Directions API. See Set up in the Cloud Console. Create and restrict an API key, and add it to your code. See Use an API Key.
This code will work
GoogleMap map;
// ... get a map.
// Add a thin red line from London to New York.
Polyline line = map.addPolyline(new PolylineOptions()
.add(new LatLng(51.5, -0.1), new LatLng(40.7, -74.0))
.width(5)
.color(Color.RED));
You should split your problem into the aspects of data collection and data display.
Therefore take two coordinates you precisely know and draw a straight polyline on google maps. If it's really displayed at the wrong location, GoogleMap has indeed a bug, which BTW I don't believe.
Then print out your coordinates e.g. to LogCat before drawing them and check the coordinates. If they are wrong, it is not a problem of GoogleMaps but of the LocationProvider or of how you use it.
If the coordinates are collected correctly, you may pick them somehow up from LogCat and use them directly in your code to draw a polyline. If then the polyline is displaced, you may again have found a bug in GoogleMap. Then you should paste the coordinates here, so someone can reproduce it. It may be device dependent. I never had a polyline which did not match the map.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With