Drawing route on Google Maps using Google Maps Android API v2 - android
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
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.
Your code for drawing the path looks strange.
Inside the for-loop you should only add the points to an instance of PolylineOptions (which you create before entering the for loop).
Then, after the for-loop you can add the width, color etc. to the polylineOptions object and finally use that in mGoogleMap.addPolyline().
In your coding, you are somehow adding a new polyline for each point (I am wondering that this draws lines at all, as each "line" consists of one point only.).
Related
Android application for calculating distance travelled by a bike
I want to build an Android application for calculating distance traveled by a bike and sending notification for the maintenance or services to be done according to the total distance covered. Anyone please help me! public class Main2Activity extends AppCompatActivity implements View.OnClickListener { Button start, stop; TextView distanceValue, dist, last; DistanceService gps; #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); start = (Button) findViewById(R.id.btn_start); //stop = (Button) findViewById(R.id.btn_stop); distanceValue = (TextView) findViewById(R.id.distance); start.setOnClickListener(this); // stop.setOnClickListener(this); // dist = (TextView) findViewById(R.id.txt_dist); //last = (TextView) findViewById(R.id.txt_last); } #Override public void onRequestPermissionsResult(int requestCode,#NonNull String[] permissions, #NonNull int[] grantResults) { switch (requestCode) { case Utility.REQUEST_CODE_ASK_PERMISSIONS: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Toast.makeText(getApplicationContext(), "Granted", Toast.LENGTH_LONG).show(); } else { Toast.makeText(getApplicationContext(), "Permission Denied", Toast.LENGTH_LONG).show(); } break; } } #Override public void onClick(View v) { int id = v.getId(); switch (id) { case R.id.btn_start: gps = new DistanceService(Main2Activity.this,distanceValue); startService(new Intent(this, DistanceService.class)); break; } } } Distance Service.java ............. public class DistanceService { private static final int REQUEST_CODE_ASK_PERMISSIONS = 123; double distanceKm,distanceMeters; protected LocationManager locManager; private LocationListener locListener = new myLocationListener(); static final Double EARTH_RADIUS = 6371.00; private boolean gps_enabled = false; private boolean network_enabled = false; private final Context context; TextView tv; public DistanceService(Context ctx,TextView textView){ context=ctx; tv=textView; location(); } public void location() { locManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE); try { gps_enabled = locManager.isProviderEnabled(LocationManager.GPS_PROVIDER); } catch (Exception ex) { ex.printStackTrace(); Toast.makeText(context,ex.toString(),Toast.LENGTH_LONG).show(); } try { network_enabled = locManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); } catch (Exception ex) { } Log.v("Debug", "in on create.. 2"); if (gps_enabled) { checkPermission(context); locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locListener); Log.v("Debug", "Enabled.."); } if (network_enabled) { locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,0,0,locListener); Log.v("Debug", "Disabled.."); } Log.v("Debug", "in on create..3"); } private class myLocationListener implements LocationListener { double lat_old=0.0; double lon_old=0.0; double lat_new; double lon_new; double time=10; double speed=0.0; #Override public void onLocationChanged(Location location) { Log.v("Debug", "in onLocation changed.."); if(location!=null){ checkPermission(context); locManager.removeUpdates(locListener); //String Speed = "Device Speed: " +location.getSpeed(); lat_new=location.getLongitude(); lon_new =location.getLatitude(); String longitude = "Longitude: " +location.getLongitude(); String latitude = "Latitude: " +location.getLatitude(); double distance =getDistance(lat_new, lon_new, lat_old, lon_old); speed = distance/time; tv.setText( longitude+"\n"+latitude+"\nDistance is: " +distance+"\nSpeed is: "+speed); Toast.makeText(context, longitude+"\n"+latitude+"\nDistance is: " +distance+"\nSpeed is: "+speed , Toast.LENGTH_SHORT).show(); // tv.setText(longitude+"\n"+latitude+"\nDistance is: " // +distance+"\nSpeed is: "+speed ); lat_old=lat_new; lon_old=lon_new; } } #Override public void onProviderDisabled(String provider) {} #Override public void onProviderEnabled(String provider) {} #Override public void onStatusChanged(String provider, int status, Bundle extras) {} } public double getDistance(double lat1, double lon1, double lat2, double lon2){ Location locationA = new Location("point A"); locationA.setLatitude(lat1); locationA.setLongitude(lon1); Location locationB = new Location("point B"); locationB.setLatitude(lat2); locationB.setLongitude(lon2); distanceMeters = locationA.distanceTo(locationA); distanceKm = distanceMeters / 1000f; return distanceKm; // last.setText("mtr:"+distanceMeters+"km:"+String.format("%.2f Km",distanceKm )); } // public double CalculationByDistance(double lat1, double lon1, double lat2, double lon2) { // double Radius = EARTH_RADIUS; // double dLat = Math.toRadians(lat2-lat1); // double dLon = Math.toRadians(lon2-lon1); // double a = Math.sin(dLat/2) * Math.sin(dLat/2) + // Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * // Math.sin(dLon/2) * Math.sin(dLon/2); // double c = 2 * Math.asin(Math.sqrt(a)); // return Radius * c; // } public static boolean checkPermission(final Context context) { int currentAPIVersion = Build.VERSION.SDK_INT; if(currentAPIVersion>= 23) { if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission (context, Manifest.permission.ACCESS_COARSE_LOCATION )!= PackageManager.PERMISSION_GRANTED) { if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, Manifest.permission.ACCESS_FINE_LOCATION)|| ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, Manifest.permission.ACCESS_COARSE_LOCATION) ) { AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context); alertBuilder.setCancelable(true); alertBuilder.setTitle("Permission necessary"); alertBuilder.setMessage("External storage permission is necessary"); alertBuilder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { #TargetApi(Build.VERSION_CODES.JELLY_BEAN) public void onClick(DialogInterface dialog, int which) { ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_CODE_ASK_PERMISSIONS ); } }); AlertDialog alert = alertBuilder.create(); alert.show(); } else { ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_CODE_ASK_PERMISSIONS ); } return false; } else { return true; } } else { return true; } }
For calculation get old Lat-Lang and get new Lat-Lang and find distance between them private static double distanceRadians(double lat1, double lng1, double lat2, double lng2) { return arcHav(havDistance(lat1, lat2, lng1 - lng2)); } /** * Returns the angle between two LatLngs, in radians. This is the same as * the distance on the unit sphere. */ static double computeAngleBetween(LatLng from, LatLng to) { return distanceRadians(toRadians(from.latitude), toRadians(from.longitude), toRadians(to.latitude), toRadians(to.longitude)); } /** * Returns the distance between two LatLngs, in meters. */ public static double computeDistanceBetween(LatLng from, LatLng to) { return computeAngleBetween(from, to) * EARTH_RADIUS; } /** * Computes inverse haversine. Has good numerical stability around 0. * arcHav(x) == acos(1 - 2 * x) == 2 * asin(sqrt(x)). * The argument must be in [0, 1], and the result is positive. */ static double arcHav(double x) { return 2 * asin(sqrt(x)); } /** * Returns haversine(angle-in-radians). * hav(x) == (1 - cos(x)) / 2 == sin(x / 2)^2. */ static double hav(double x) { double sinHalf = sin(x * 0.5); return sinHalf * sinHalf; } /** * Returns hav() of distance from (lat1, lng1) to (lat2, lng2) on the unit sphere. */ static double havDistance(double lat1, double lat2, double dLng) { return hav(lat1 - lat2) + hav(dLng) * cos(lat1) * cos(lat2); }
Track user location in Realtime using Polylines in Google Maps (Android)
I have some experience with Android, but am new to using the Google Maps API and Location Services. I am trying to show the user's movement on a MapFragment by moving the tracker and drawing a Polyline over where the user has been, sort of like MapMyRun. From what I've seen on my debugger, I get a location after the Fragment resumes, and it is appended to the list of LatLngs. What I need is for the map to update every few seconds, or everytime the location changes by a tenth of a mile or so. Here is what I have for the activity containing the MapFragment. My instinct tells me I need to do something inside of the the method handleNewLocation that would update the map...either that or perhaps do something in the LocationProvider that would update the location more often. Any help, tips, or links would be greatly appreciated! My goal is to learn so that I understand how I can do this better in the future :)! package com.seniorproject.trafton.trackrecordrace; //Import statements not shown for readability import... public class MapsActivity extends AppCompatActivity implements LocationProvider.LocationCallback { public static final String TAG = "cloudsTraf"; //MapsActivity.class.getSimpleName(); private GoogleMap mMap; // Might be null if Google Play services APK is not available. private LocationProvider mLocationProvider; //variable for toggle buttons private boolean isRunning = false; //ArrayList to store geopoints for current run private ArrayList<LatLng> geoPoints; //Array of distances private ArrayList<Float> distances; //total distance private float totalDistance; //polyline that represented the route Polyline tracker; /*Load up widgets for tracking */ private ImageButton mPlayButton; private ImageButton mPauseButton; private TextView mRunTimeText; private TextView mRunSpeedText; private TextView mRunDistText; private TextView mRunCalsText; private Boolean mIsPlayButtonClicked; //Handler to control timer tracking //Thank you to Nikos Maravitsas for the tutorial on timers private Handler timeHandler = new Handler(); private long startTime = 0L; long timeInMillis = 0L; long timeSwapBuffer = 0L; long updatedTime = 0L; #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_maps); setUpMapIfNeeded(); mLocationProvider = new LocationProvider(this, this); geoPoints = new ArrayList<LatLng>(); //added //Add in code to inflate the tracking modules mRunTimeText = (TextView) findViewById(R.id.run_time_text); mRunDistText = (TextView) findViewById(R.id.run_dist_text); mRunSpeedText = (TextView) findViewById(R.id.run_speed_text); Toolbar runToolbar= (Toolbar) findViewById(R.id.toolbar_run); runToolbar.setTitle("Run on " + getDate()); runToolbar.setTitleTextColor(Color.WHITE); setSupportActionBar(runToolbar); } //Inflate the menu for the toolbar public boolean onCreateOptionsMenu(Menu menu) { Log.e("XXX", "Menu created"); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_maps_run, menu); return super.onCreateOptionsMenu(menu); } //Handles possibilities of menu items being selected. #Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection switch (item.getItemId()) { case R.id.action_begin_run: if (!isRunning) { startTime = SystemClock.uptimeMillis(); timeHandler.postDelayed(updateTimerThread,0); item.setIcon(R.drawable.ic_pause_white_24dp); isRunning = true; } else { timeSwapBuffer += timeInMillis; timeHandler.removeCallbacks(updateTimerThread); item.setIcon(R.drawable.ic_play_arrow_white_24dp); isRunning = false; } return true; case R.id.action_stop_run: //stop run, save run, and transport user to the stats for that run return true; default: return super.onOptionsItemSelected(item); } } /*Code to update the timer, begins a new timer thread.*/ private Runnable updateTimerThread = new Runnable() { public void run(){ timeInMillis = SystemClock.uptimeMillis() - startTime; updatedTime = timeSwapBuffer + timeInMillis; //Get integer value from time update and put into textView int seconds = (int) (updatedTime/1000); //need two seconds variables for formatting purposes. int secs = seconds % 60; int mins = (seconds / 60); int hours = (mins / 60); mRunTimeText.setText("" + hours + ":" + String.format("%02d", mins) + ":" + String.format("%02d", secs)); timeHandler.postDelayed(this, 0); } }; /* */ #Override protected void onResume() { super.onResume(); setUpMapIfNeeded(); mLocationProvider.connect(); } #Override protected void onPause() { super.onPause(); mLocationProvider.disconnect(); } /** * Sets up the map if it is possible to do so (i.e., the Google Play services APK is correctly * installed) and the map has not already been instantiated.. This will ensure that we only ever * call {#link #setUpMap()} once when {#link #mMap} is not null. * <p/> * If it isn't installed {#link SupportMapFragment} (and * {#link com.google.android.gms.maps.MapView MapView}) will show a prompt for the user to * install/update the Google Play services APK on their device. * <p/> * A user can return to this FragmentActivity after following the prompt and correctly * installing/updating/enabling the Google Play services. Since the FragmentActivity may not * have been completely destroyed during this process (it is likely that it would only be * stopped or paused), {#link #onCreate(Bundle)} may not be called again so we should call this * method in {#link #onResume()} to guarantee that it will be called. */ private void setUpMapIfNeeded() { // Do a null check to confirm that we have not already instantiated the map. if (mMap == null) { // Try to obtain the map from the SupportMapFragment. mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)) .getMap(); // Check if we were successful in obtaining the map. if (mMap != null) { setUpMap(); } } } /** * This should only be called once and when we are sure that {#link #mMap} is not null. */ private void setUpMap() { //mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker")); } //handle new location public void handleNewLocation(Location location) { Log.d(TAG, location.toString()); double currentLatitude = location.getLatitude(); double currentLongitude = location.getLongitude(); LatLng latLng = new LatLng(currentLatitude, currentLongitude); //Get the new geopoints to redraw the line on each iteration geoPoints.add(latLng); //get the latest distance update if (geoPoints.size() > 2) { calculateDistance(); } //set the distance test mRunDistText.setText(Float.toString(totalDistance) + " Meters"); mRunSpeedText.setText((location.getSpeed() + " m/s")); //draw the polyline drawRoute(); MarkerOptions options = new MarkerOptions() .position(latLng) .title("I am here!"); mMap.addMarker(options); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng,15)); } /* *Methods to calculate metrics. All measurements returned are approximations. */ //returns the latest distance between geoPoints. Append to total number public void calculateDistance(){ Location newLoc = new Location("Latest Location"); Location oldLoc = new Location("Last known Location"); LatLng newPt = geoPoints.get(geoPoints.size()- 1); LatLng oldPt = geoPoints.get(geoPoints.size()-2); distances.add(oldLoc.distanceTo(newLoc)); //add to the distance variable totalDistance = totalDistance + oldLoc.distanceTo(newLoc); Log.d(TAG, "distance between points is: " + oldLoc.distanceTo(newLoc)); } //calculates the current KCals being burned public void calculateKcals(){ } //get today's date in a simple format public String getDate(){ Date today = Calendar.getInstance().getTime(); SimpleDateFormat formatter = new SimpleDateFormat("EEE MMM dd"); String todaysDate = formatter.format(today); return todaysDate; } //method to draw polyline. Uses the recorded geopoints. public void drawRoute(){ mMap.clear(); PolylineOptions options = new PolylineOptions().width(5).color(android.R.color.holo_blue_dark).geodesic(true).visible(true); for(int i = 0; i < geoPoints.size(); i++){ LatLng pt = geoPoints.get(i); options.add(pt); } Log.d(TAG,"GeoPoints recorded: " + geoPoints); mMap.addPolyline(options); } } I'm grabbing the location in a different file (Because, y'know, modularity is good.). If there is any additional data I can provide, I would be more than happy to include it! package com.seniorproject.trafton.trackrecordrace; import android.app.Activity; import android.content.Context; import android.content.IntentSender; import android.location.Location; import android.os.Bundle; import android.util.Log; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.location.LocationListener; import com.google.android.gms.location.LocationRequest; import com.google.android.gms.location.LocationServices; public class LocationProvider implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener { public abstract interface LocationCallback { public void handleNewLocation(Location location); } public static final String TAG = LocationProvider.class.getSimpleName(); /* * Define a request code to send to Google Play services * This code is returned in Activity.onActivityResult */ private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000; private LocationCallback mLocationCallback; private Context mContext; private GoogleApiClient mGoogleApiClient; private LocationRequest mLocationRequest; public LocationProvider(Context context, LocationCallback callback) { mGoogleApiClient = new GoogleApiClient.Builder(context) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); mLocationCallback = callback; // Create the LocationRequest object mLocationRequest = LocationRequest.create() .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) .setInterval(3 * 1000) // 10 seconds, in milliseconds .setFastestInterval(1 * 1000); // 1 second, in milliseconds mContext = context; } public void connect() { mGoogleApiClient.connect(); } public void disconnect() { if (mGoogleApiClient.isConnected()) { LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); mGoogleApiClient.disconnect(); } } #Override public void onConnected(Bundle bundle) { Log.i(TAG, "Location services connected."); Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); if (location == null) { LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); } else { mLocationCallback.handleNewLocation(location); } } #Override public void onConnectionSuspended(int i) { } #Override public void onConnectionFailed(ConnectionResult connectionResult) { /* * Google Play services can resolve some errors it detects. * If the error has a resolution, try sending an Intent to * start a Google Play services activity that can resolve * error. */ if (connectionResult.hasResolution() && mContext instanceof Activity) { try { Activity activity = (Activity)mContext; // Start an Activity that tries to resolve the error connectionResult.startResolutionForResult(activity, CONNECTION_FAILURE_RESOLUTION_REQUEST); /* * Thrown if Google Play services canceled the original * PendingIntent */ } catch (IntentSender.SendIntentException e) { // Log the error e.printStackTrace(); } } else { /* * If no resolution is available, display a dialog to the * user with the error. */ Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode()); } } #Override public void onLocationChanged(Location location) { mLocationCallback.handleNewLocation(location); Log.i(TAG, "New location received "); } }
To draw a Polyline on the map do this in onLocationChanged Polyline route = mMap.addPolyline(new PolylineOptions()); route.setPoints(mGeoPoints);`
How to use this codes? I want to add moving marker like a car in my map
Just want to know how to use this codes? 'cause everytime I paste this codes in my java, there is nothing happen... Please help me. I want to add moving marker inside map for my app. thanks for advance :) private GoogleMap map; #Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.map); try { if(map == null) { map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap(); } if(map != null) { map.setMapType(GoogleMap.MAP_TYPE_NORMAL); } } catch(Exception e) { e.printStackTrace(); } } public void animateMarker(final Marker marker, final LatLng toPosition, final boolean hideMarker) { final Handler handler = new Handler(); final long start = SystemClock.uptimeMillis(); Projection proj = map.getProjection(); Point startPoint = proj.toScreenLocation(marker.getPosition()); final LatLng startLatLng = proj.fromScreenLocation(startPoint); final long duration = 500; final Interpolator interpolator = new LinearInterpolator(); handler.post(new Runnable() { #Override public void run() { long elapsed = SystemClock.uptimeMillis() - start; float t = interpolator.getInterpolation((float) elapsed / duration); double lng = t * toPosition.longitude + (1 - t) * startLatLng.longitude; double lat = t * toPosition.latitude + (1 - t) * startLatLng.latitude; marker.setPosition(new LatLng(lat, lng)); if (t < 1.0) { // Post again 16ms later. handler.postDelayed(this, 16); } else { if (hideMarker) { marker.setVisible(false); } else { marker.setVisible(true); } } } }); } } .......
Start with a simple application to understand how to use the code. But in this case, I do not see the use of the method animateMarker. You need someone who would cause it (eg, button).
LocationClient by Google Services not using GPS data
I am currently trying the LocationClient provided by Google Services. When I am next to a building I receive frequent location updates but in the middle of a road they are less frequent and less accurate. In the country side, no updates at all. I wondered if the Google Location Services uses the GPS so I disabled all location providers but the GPS in the phone's settings and I instantly stopped receiving any update. Obviously my LocationClient does not receive any update using GPS data. Am I missing something? Is there anything I have to set for the LocationClient or do I have to use the standard LocationManager.GPS_PROVIDER? I am trying to build an app for running and I need accurate location data. Any advice would be much appreciated ;-)! Here is the implementation that I use: public class CustomLocationProvider implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener, android.location.LocationListener { private static final float DATA_UPDATE_DISTANCE = 100.0f; private static final long ONE_MIN = 1000 * 60; private static final long FIVE_MIN = ONE_MIN * 5; private static final int UPDATE_TIME = 5000; private static final int FASTEST_INTERVAL = 16; private static final int ACCURACY_THRESHOLD = 30; private Context mContext; private LocationClient mLocationClient; private Location mPreviousLocation; private float mTotalDistance; private float mDistanceSinceLastUpdate = 0.0f; private WeakReference<Activity> mDelegate; public interface LocationProviderDelegate { void locationUpdated(Location location); } // These settings are the same as the settings for the map. They will in fact give you updates // at the maximal rates currently possible. private static final LocationRequest REQUEST = LocationRequest.create() .setInterval(UPDATE_TIME) // 5 seconds .setFastestInterval(FASTEST_INTERVAL) // 16ms = 60fps .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); public CustomLocationProvider (Context context, Activity delegate) { if(context != null) { mContext = context; mDelegate = new WeakReference<Activity>(delegate); } } public void enableTracking(boolean enable) { if(enable) { setUpLocationClientIfNeeded(); mLocationClient.connect(); } else { if(mLocationClient != null) { mLocationClient.disconnect(); } } } private void setUpLocationClientIfNeeded() { if (mLocationClient == null) { mLocationClient = new LocationClient( mContext, this, // ConnectionCallbacks this); // OnConnectionFailedListener } } #Override public void onLocationChanged(Location location) { if(mPreviousLocation != null && location.getTime() > mPreviousLocation.getTime() && location.getAccuracy() < ACCURACY_THRESHOLD) { float distanceIncrement = mPreviousLocation.distanceTo(location); mDistanceSinceLastUpdate += distanceIncrement; mTotalDistance += distanceIncrement; if(mDistanceSinceLastUpdate >= DATA_UPDATE_DISTANCE) { mDistanceSinceLastUpdate = 0.0f; requestDataUpdate(location); } updateLocation(location); } else if( mPreviousLocation == null){ requestDataUpdate(location); updateLocation(location); } } private void updateLocation(Location location) { try { ((LocationProviderDelegate) mDelegate.get()).locationUpdated(location); } catch (Exception e) { Logger.logError("Cannot cast as a LocationProviderDelegate"); } mPreviousLocation = location; } /** * Callback called when connected to GCore. Implementation of {#link ConnectionCallbacks}. */ #Override public void onConnected(Bundle connectionHint) { mLocationClient.requestLocationUpdates( REQUEST, this); // LocationListener Location location = mLocationClient.getLastLocation(); if (location != null) { if (age(location) < FIVE_MIN) { mPreviousLocation = location; requestDataUpdate(location); } } } /** * Callback called when disconnected from GCore. Implementation of {#link ConnectionCallbacks}. */ #Override public void onDisconnected() { // Do nothing } /** * Implementation of {#link OnConnectionFailedListener}. */ #Override public void onConnectionFailed(ConnectionResult result) { Logger.postMessageToTheUser("Connection failed", mDelegate.get()); } public void Reset(){ mTotalDistance = 0; } public float TotalDistance() { return mTotalDistance; } public void requestDataUpdate(Location location) { double latitude = location.getLatitude(); double longitude = location.getLongitude(); double offset = 0.002; LatLngBounds bounds = LatLngBounds.builder() .include(new LatLng(latitude - offset, longitude - offset)) .include(new LatLng(latitude + offset, longitude + offset)) .build(); updateData(); } private long age(Location location) { return System.currentTimeMillis() - location.getTime(); } #Override public void onProviderDisabled(String provider) { // TODO Auto-generated method stub } #Override public void onProviderEnabled(String provider) { // TODO Auto-generated method stub } #Override public void onStatusChanged(String provider, int status, Bundle extras) { String newStatus = ""; switch (status) { case LocationProvider.OUT_OF_SERVICE: newStatus = "OUT_OF_SERVICE"; break; case LocationProvider.TEMPORARILY_UNAVAILABLE: newStatus = "TEMPORARILY_UNAVAILABLE"; break; case LocationProvider.AVAILABLE: newStatus = "AVAILABLE"; break; } String msg = provider + ": " + newStatus; Logger.postMessageToTheUser(msg, mDelegate.get()); } }
The LocationClient provided by Google Play Services, uses a fused location provider. This means that it will use the best provider available along with the phone's sensors to give you the most accurate location it can. It seems from your code that you are disregarding updates if the location accuracy is less than 30m. Remember that even though GPS is the most accurate way to get a location you cannot control how accurate that location is. Also, calling LocationRequest.create() will create the request with default parameters. I would think you want to call create() last (after setInterval(),etc ) instead of first.
Get GPS data while App is running background in Android using LocationListener
i have problem with my Android application.I need an application that will get in background GPS location while open another application.application run in background but i want to also get GPS location in background. create start and stop button for get gps location it work properly but when click on home button gps stop to gettting location Here is My code.. public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_gps); /* get TextView to display the GPS data */ txtLat = (TextView) findViewById(R.id.textview1); /* the location manager is the most vital part it allows access * to location and GPS status services */ locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER ,10000,10, this); // locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10 * 1000L, 0, this); btnShow = (Button) findViewById(R.id.btnstart); btnStop = (Button) findViewById(R.id.btnstop); btnShow.setOnClickListener(new OnClickListener() { public void onClick(View arg0) { Toast.makeText(getBaseContext(), "Trip Start.", Toast.LENGTH_SHORT).show(); txtLat.setVisibility(View.VISIBLE); onResume(); btnShow.setEnabled(false); btnStop.setEnabled(true); } }); Button btnstop = (Button) findViewById(R.id.btnstop); btnstop.setOnClickListener(new OnClickListener() { public void onClick(View v) { onPause(); Toast.makeText(getBaseContext(), "Trip Ended.", Toast.LENGTH_SHORT).show(); btnShow.setEnabled(true); btnStop.setEnabled(false); } }); } public void onLocationChanged(Location location) { if (location == null) { Toast.makeText(getApplicationContext(),"Searching for your location.", Toast.LENGTH_SHORT).show(); locationManager.requestLocationUpdates(provider, 10000, 10,locationListener); onLocationChanged(location); } else { double cell_lat=location.getLatitude(); double cell_long=location.getLongitude(); double altitude=location.getAltitude(); double accuracy=location.getAccuracy(); String status="true"; sb = new StringBuilder(512); noOfFixes++; /* display some of the data in the TextView */ sb.append("Tracking: "); sb.append(noOfFixes); sb.append('\n'); sb.append('\n'); sb.append("Londitude: "); sb.append(location.getLongitude()); sb.append('\n'); sb.append("Latitude: "); sb.append(location.getLatitude()); sb.append('\n'); sb.append("Altitiude: "); sb.append(location.getAltitude()); sb.append('\n'); sb.append("Accuracy: "); sb.append(location.getAccuracy()); sb.append("ft"); sb.append('\n'); txtLat.setText(sb.toString()); } public void onProviderDisabled(String provider) { /* this is called if/when the GPS is disabled in settings */ Log.v(tag, "Disabled"); /* bring up the GPS settings */ Intent intent = new Intent( android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivity(intent); } public void onProviderEnabled(String provider) { Log.v(tag, "Enabled"); Toast.makeText(this, "GPS Enabled", Toast.LENGTH_SHORT).show(); } public void onStatusChanged(String provider, int status, Bundle extras) { /* This is called when the GPS status alters */ switch (status) { case LocationProvider.OUT_OF_SERVICE: Log.v(tag, "Status Changed: Out of Service"); Toast`enter code here`.makeText(this, "Status Changed: Out of Service", Toast.LENGTH_SHORT).show(); break; case LocationProvider.TEMPORARILY_UNAVAILABLE: Log.v(tag, "Status Changed: Temporarily Unavailable"); Toast.makeText(this, "Status Changed: Temporarily Unavailable", Toast.LENGTH_SHORT).show(); break; case LocationProvider.AVAILABLE: Log.v(tag, "Status Changed: Available"); Toast.makeText(this, "Status Changed: Available", Toast.LENGTH_SHORT).show(); break; } } #Override protected void onResume() { /* * onResume is is always called after onStart, even if the app hasn't been * paused * * add location listener and request updates every 1000ms or 10m */ locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 10f, this); super.onResume(); } #Override protected void onPause() { /* GPS, as it turns out, consumes battery like crazy */ locationManager.removeUp`enter code here`dates(this); super.onPause(); } #Override public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_HOME)) { System.out.println("KEYCODE_HOME"); Toast.makeText(getBaseContext(), "Home Button.", Toast.LENGTH_SHORT).show(); this.moveTaskToBack(true); //showDialog("'HOME'"); return true; } if ((keyCode == KeyEvent.KEYCODE_BACK)) { System.out.println("KEYCODE_BACK"); finish(); showDialog("'BACK'"); return true; } if ((keyCode == KeyEvent.KEYCODE_MENU)) { System.out.println("KEYCODE_MENU"); //showDialog("'MENU'"); return true; } return false; } void showDialog(String the_key){ AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage("You have pressed the " + the_key + " button. Would you like to exit the app?") .setCancelable(true) .setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); finish(); } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); AlertDialog alert = builder.create(); alert.setTitle("GPS."); alert.show(); }
I found this code somewhere It worked for me LINK, I had modified the code according to my requirement, give it a try. It saves data in the database from the background service, you just need to start the service from an activity, NOTE: it will save in Database only if the distance of first location is more than the given minimum distance. public class BackgroundLocationService extends Service implements GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener, LocationListener { private static final String TAG = "BackgroundLocationService"; IBinder mBinder = new LocalBinder(); private LocationClient mLocationClient; private LocationRequest mLocationRequest; // Flag that indicates if a request is underway. private boolean mInProgress; private Boolean servicesAvailable = false; private double previousLatitude = 0; private double previousLongitude = 0; private SharedPreferences stopLocatinServicePreferance; private float[] distance; // public static boolean isStopSelf = false; public class LocalBinder extends Binder { public BackgroundLocationService getServerInstance() { return BackgroundLocationService.this; } } #Override public void onCreate() { super.onCreate(); mInProgress = false; // Create the LocationRequest object mLocationRequest = LocationRequest.create(); // Use high accuracy mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); // Set the update interval to 5 seconds mLocationRequest.setInterval(Constants.UPDATE_INTERVAL); // Set the fastest update interval to 1 second mLocationRequest.setFastestInterval(Constants.FASTEST_INTERVAL); servicesAvailable = servicesConnected(); /* * Create a new location client, using the enclosing class to handle * callbacks. */ mLocationClient = new LocationClient(this, this, this); } private boolean servicesConnected() { // Check that Google Play services is available int resultCode = GooglePlayServicesUtil .isGooglePlayServicesAvailable(this); // If Google Play services is available if (ConnectionResult.SUCCESS == resultCode) { return true; } else { return false; } } public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); if (!servicesAvailable || mLocationClient.isConnected() || mInProgress) return START_STICKY; setUpLocationClientIfNeeded(); if (!mLocationClient.isConnected() || !mLocationClient.isConnecting() && !mInProgress) { appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Started", Constants.LOG_FILE); mInProgress = true; mLocationClient.connect(); } return START_STICKY; } /* * Create a new location client, using the enclosing class to handle * callbacks. */ private void setUpLocationClientIfNeeded() { if (mLocationClient == null) mLocationClient = new LocationClient(this, this, this); } // Define the callback method that receives location updates #Override public void onLocationChanged(Location location) { // Report to the UI that the location was updated String msg = Double.toString(location.getLatitude()) + "," + Double.toString(location.getLongitude()); Log.d("debug", msg); SimpleDateFormat s = new SimpleDateFormat("ddMMyyyyhhmmss"); String timeStamp = s.format(new Date()); System.out.println("TimeStamp ddMMyyyyhhmmss =" + timeStamp); if (isDistanceAccountable(location.getLatitude(), location.getLongitude(), previousLatitude, previousLongitude)) { DatabaseHelper dbm = DatabaseHelper .getInstance(getApplicationContext()); ContentValues cv = new ContentValues(); cv.put(DatabaseHelper.KEY_LATLONG, location.getLatitude() + "#" + location.getLongitude()); cv.put(DatabaseHelper.KEY_TIMESTAMP, timeStamp); cv.put(DatabaseHelper.KEY_STATUS, "0"); cv.put(DatabaseHelper.KEY_USER_ID, ""); dbm.insert(DatabaseHelper.TABLE_TRACKINFO_TABLE, cv); // } // Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); appendLog(msg, Constants.LOCATION_FILE); } previousLatitude = location.getLatitude(); previousLongitude = location.getLongitude(); stopLocatinServicePreferance = getSharedPreferences("SERVICE_PREF", 0); boolean check = stopLocatinServicePreferance.getBoolean("isStop", true); Log.e(TAG, "isStop?" + check); if (check) { Log.e(TAG, "is self stoping "); if (mLocationClient != null) { mLocationClient.removeLocationUpdates(this); // Destroy the current location client mLocationClient = null; } this.stopSelf(); } } /** * Returns true if distance is grater than MINIMUM_DISTANCE_ACCOUNTABLE * NOTE: returns true if there is no previousLatitude,previousLongitude, it * means this is first time it needs to save the data * * #param currentLatitude * #param currentLongitude * #param previousLatitude * #param previousLongitude * #return */ private boolean isDistanceAccountable(double currentLatitude, double currentLongitude, double previousLatitude, double previousLongitude) { distance = new float[1]; if (previousLatitude > 0 && previousLongitude > 0) { Location.distanceBetween(currentLatitude, currentLongitude, previousLatitude, previousLongitude, distance); Log.v(TAG + " > isDistanceAccountable()", "previousLatitude = " + previousLatitude + "previousLongitude = " + previousLongitude + " currentLatitude = " + currentLatitude + " , currentLongitude = " + currentLongitude); } else { Log.v(TAG + " > isDistanceAccountable()", "previousLatitude = " + previousLatitude + "previousLongitude = " + previousLongitude); return true; } if (distance[0] > Constants.MINIMUM_DISTANCE_ACCOUNTABLE) { Log.v(TAG + " > isDistanceAccountable()", "Distance = " + distance[0] + "return true"); return true; } else { Log.v(TAG + " > isDistanceAccountable()", "Distance = " + distance[0] + "return false"); return false; } } #Override public IBinder onBind(Intent intent) { return mBinder; } public String getTime() { SimpleDateFormat mDateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); return mDateFormat.format(new Date()); } public void appendLog(String text, String filename) { File logFile = new File(filename); if (!logFile.exists()) { try { logFile.createNewFile(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { // BufferedWriter for performance, true to set append to file flag BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true)); buf.append(text); buf.newLine(); buf.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } #Override public void onDestroy() { try { // Turn off the request flag mInProgress = false; if (servicesAvailable && mLocationClient != null) { mLocationClient.removeLocationUpdates(this); // Destroy the current location client mLocationClient = null; } appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Stopped", Constants.LOG_FILE); } catch (Exception e) { Log.e(TAG + " > onDestroy()", e.toString()); } super.onDestroy(); } /* * Called by Location Services when the request to connect the client * finishes successfully. At this point, you can request the current * location or start periodic updates */ #Override public void onConnected(Bundle bundle) { // Request location updates using static settings mLocationClient.requestLocationUpdates(mLocationRequest, this); appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Connected", Constants.LOG_FILE); } /* * Called by Location Services if the connection to the location client * drops because of an error. */ #Override public void onDisconnected() { // Turn off the request flag mInProgress = false; // Destroy the current location client mLocationClient = null; appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected", Constants.LOG_FILE); } /* * Called by Location Services if the attempt to Location Services fails. */ #Override public void onConnectionFailed(ConnectionResult connectionResult) { mInProgress = false; /* * Google Play services can resolve some errors it detects. If the error * has a resolution, try sending an Intent to start a Google Play * services activity that can resolve error. */ if (connectionResult.hasResolution()) { // If no resolution is available, display an error dialog } else { } } } Here is the supporting class. public final class Constants { // Milliseconds per second private static final int MILLISECONDS_PER_SECOND = 100; // Update frequency in seconds private static final int UPDATE_INTERVAL_IN_SECONDS = 10; // Update frequency in milliseconds public static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS; // The fastest update frequency, in seconds private static final int FASTEST_INTERVAL_IN_SECONDS = 10; // A fast frequency ceiling in milliseconds public static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS; // Stores the lat / long pairs in a text file public static final String LOCATION_FILE = "sdcard/location.txt"; // Stores the connect / disconnect data in a text file public static final String LOG_FILE = "sdcard/log.txt"; // Minimum accountable distance in meters public static final float MINIMUM_DISTANCE_ACCOUNTABLE = 50; /** * Suppress default constructor for noninstantiability */ private Constants() { throw new AssertionError(); } }