i'm currently writing an app that should to the following:
The UI only contains one toggle button. If it is turned on the GPS Position shall be sent to an external server. If it is turned off, nothing shall happen.
If the Button was turned on and the app (activity) is closed the location should still be send until the Button is turned off again.
How can i achieve this ? I read a lot of threads and tutorials and on dev.google.com, but i was not able to find the best solution for my problem.
My current approach:
MainActivity.java
public void onClick(View v) {
if (onOffButton.isChecked()) {
Intent startIntent = new Intent(this, LocationService.class);
startService(startIntent);
} else {
stopService(new Intent(this, LocationService.class));
}
}
LocationService.java
public class LocationService extends Service implements LocationListener {
final public static String START_ACTION = "START_LOCATION";
final public static int NOTE_ID = 1;
private int updateRate;
private LocationManager locationManager;
private NotificationManager notifyManager;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
// show popup message
Toast.makeText(this, getText(R.string.start_message), Toast.LENGTH_SHORT).show();
// display icon in status bar
requestLocationUpdates();
}
private void requestLocationUpdates() {
if(locationManager != null)
locationManager.removeUpdates(this);
// get location service
Criteria crit = new Criteria();
crit.setPowerRequirement(Criteria.ACCURACY_FINE);
String bestProvider = getLocationManager().getBestProvider(crit, true);
getLocationManager().requestLocationUpdates(bestProvider, updateRate * 1000,
0 /* minDist */, this);
LocationService.running = true;
}
#Override
public void onDestroy() {
super.onDestroy();
getLocationManager().removeUpdates(this);
notifyManager.cancel(NOTE_ID);
Toast.makeText(this, getText(R.string.stop_message), Toast.LENGTH_SHORT).show();
LocationService.running = false;
}
#Override
public void onLocationChanged(Location location) {
//Send Location to Server
}
#Override
public void onProviderDisabled(String provider) {
// TODO stop service, notify user
}
#Override
public void onProviderEnabled(String provider) {
requestLocationUpdates();
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO notify user
}
private LocationManager getLocationManager() {
if (this.locationManager == null)
this.locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
return this.locationManager;
}
}
I got this from a very old gps tracker i found on the Internet (i know that onStart() is deprecated and should replaced with onCommandStart()) I just want to know if the general approach is good..
Regards.
The approach looks fine. You just need to implement the call-back methods to report your location.
Related
I want to implement location tracking in android but in a small time interval (seconds), after searching and reading the documentation i found that there is restrictions on location access when app is in the background, and the solution is to use foreground service, But i need another legal and efficient solution without the need to show notification to the user.
You could use something like that
public class GPSService extends Service {
private LocationListener listener;
private LocationManager locationManager;
public IBinder onBind(Intent intent){
return null;
}
#SuppressLint("MissingPermission")
#Override
public void onCreate() {
super.onCreate();
listener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
Intent i = new Intent("location_update");
i.putExtra("coordinates",location);
sendBroadcast(i);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
Intent i = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
};
locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,5000,0,listener);
}
#Override
public void onDestroy() {
super.onDestroy();
if (locationManager != null){
locationManager.removeUpdates(listener);
}
}
}
And retreive by broadcaster
I'm starting a GPS location service on several devices, the service works correctly in devices with Android Version <= 7 even when the power button is pressed and in the lockscreen status, but I tried in a Nokia 3 with Android 8.0.0 and the service stops after push the power button but it doesn't stop when the device locks by itself after some time. When I push the power button and unlock the device the service starts to send the GPS data again. This is my code:
public class GPS_Service extends Service {
private static final String TAG = GPS_Service.class.getName();
private static final int minTimeSecondsSamplingRate = AppConfig.GPS_MIN_TIME;
private static final int minDistMetersSamplingRate = AppConfig.GPS_MIN_DISTANCE;
private LocationManager locationManager;
private LocationListener locationListener;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#SuppressLint("MissingPermission")
#Override
public void onCreate() {
locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, "Location changed");
Intent intentSendToMainActivity = new Intent(AppConfig.C_STR_INTENT_FILTER_LOCATION_CHANGED);
intentSendToMainActivity.putExtra(AppConfig.C_STR_LATITUDE, location.getLatitude());
intentSendToMainActivity.putExtra(AppConfig.C_STR_LONGITUDE, location.getLongitude());
sendBroadcast(intentSendToMainActivity);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
};
locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
if (locationManager != null) {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, minTimeSecondsSamplingRate, minDistMetersSamplingRate, locationListener);
Log.i(TAG, "Starting Location Service");
} else {
Log.e(TAG, "Can't Start Location Service");
}
}
#Override
public void onDestroy() {
super.onDestroy();
if (locationManager != null) {
locationManager.removeUpdates(locationListener);
}
}
}
I've tried dissabling the battery optimization for my application but the problem persists
stop/start location update if no location is received in 2 minutes
also create a service an make it foreground and put location updates methods inside it
all the best
I am starting my background service from the MainActivity with startService(intent) which sends the location of the user to the server. I want to enable the user to stops this service (also stoping requestLocationUpdates of firing the data from the onLocationChanged method) if he does not wish it by clicking button in the Menu.
I have tried the code in the onOptionsItemSelected method but the service it still works when I click button.
How can I stop this service?
MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.route_available);
Intent i = new Intent(this, TrackingService.class);
startService(i);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.disconnect_id:
System.out.println("test onCreateOptionsMenu was invoked.");
// Stop the service when the Menu button clicks.
Intent i = new Intent(this, TrackingService.class);
stopService(i);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Tracking Service class:
public class TrackingService extends Service {
....
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Toast.makeText(this, "Location Updation has started", Toast.LENGTH_LONG)
.show();
Log.v("X", "Response:in onStartCommand()");
detectLocation();
stopSelf();
return START_STICKY;
}
private void detectLocation() {
// TODO Auto-generated method stub
Toast.makeText(this, "Inside detectlocation()", Toast.LENGTH_SHORT)
.show();
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
LocationListener ll = new MyLocationListener(this);
// location updates: at least 0 meter and 60 seconds change.
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 30 * 1000, 0,
ll);
Log.v("X", "Response:After lm1.requestLocationUpdates ");
enableGPS(lm);
}
}
It looks like the way you have it coded now, your Service isn't really doing anything.
Because you have registered your MyLocationListener instance as the LocationListener, stopping the Service doesn't do anything.
Also, since you call stopSelf() in onStartCommand(), you're stopping the Service immediately every time it starts.
I would recommend making the Service the LocationListener, and don't call stopSelf() in onStartCommand()
.
Also, override onDestroy() in the Service, and explicitly call removeUpdates() in order to ensure your app releases it's request to keep the GPS radio active.
Something like this:
public class TrackingService extends Service implements LocationListener{
LocationManager lm; //make instance variable
//....
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Toast.makeText(this, "Location Updation has started", Toast.LENGTH_LONG)
.show();
Log.v("X", "Response:in onStartCommand()");
detectLocation();
//stopSelf(); //don't stop the service here
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
lm.removeUpdates(this);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void detectLocation() {
// TODO Auto-generated method stub
Toast.makeText(this, "Inside detectlocation()", Toast.LENGTH_SHORT)
.show();
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
//LocationListener ll = new MyLocationListener(this);
// location updates: at least 0 meter and 60 seconds change.
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 30 * 1000, 0,
this);
Log.v("X", "Response:After lm1.requestLocationUpdates ");
enableGPS(lm);
}
#Override
public void onLocationChanged(Location location) {
//put your location changed code here
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
}
I am trying to make a location tracking application on an android phone, it will be just same as the built-in google map in the phone. It will continue to track the phone even the app is close, so it will be running in the background of other applications.
I am thinking of splitting up both the classes, User Interface (Google Map) and location tracking, where the location tracking will always run but the google map will only display when the user open the application. Thus this is what I reached so far.
MapDisplay class for Google Map
public class MapDisplay extends Activity {
private GoogleMap map;
private LocationService locationService;
private Intent locationServiceIntent;
private Location myLocation;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_display);
map = ((MapFragment) getFragmentManager().findFragmentById(R.id.googleMap)).getMap();
map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
map.setMyLocationEnabled(true);
locationServiceIntent = new Intent(this, LocationService.class);
x=0;
}
#Override
protected void onPause() {
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
startService(locationServiceIntent);
bindService(locationServiceIntent, locationServiceConnection, Context.BIND_AUTO_CREATE);
}
#Override
public void updateLocation()
{
// for testing purpose, to make sure it will update periodically
Toast.makeText(MapDisplay.this, String.valueOf(myLocation.getLatitude()), Toast.LENGTH_SHORT).show();
}
private ServiceConnection locationServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
locationService = ((LocationService.LocationBinder)service).getService();
myLocation = locationService.getMyLocation();
updateLocation();
}
#Override
public void onServiceDisconnected(ComponentName name) {
locationService = null;
}
};
}
LocationService class
public class LocationService extends Service implements LocationListener
{
private LocationManager locationManager;
private Location myLocation;
private IBinder locationBinder = new LocationBinder();
public class LocationBinder extends Binder
{
public LocationService getService()
{
return LocationService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return locationBinder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
myLocation = null;
boolean networkProviderAvailable = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
boolean gpsProviderAvailable = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if(networkProviderAvailable)
{
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
}
else if(gpsProviderAvailable)
{
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}
else
{
stopSelf();
}
return super.onStartCommand(intent, flags, startId);
}
public Location getMyLocation()
{
return myLocation;
}
#Override
public void onLocationChanged(Location location) {
myLocation = location;
}
#Override
public void onProviderDisabled(String arg0) {
}
#Override
public void onProviderEnabled(String arg0) {
}
#Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
}
}
Using code above I experienced application crash because of this line
myLocation = locationService.getMyLocation();
String.valueOf(myLocation.getLatitude())
It can't get the location from LocationService class.
So, my questions are:
1) is this a good way to make the application?
2) how to periodically call the updateLocation() in MapDisplay when there are new updates in onLocationChanged method?
I will be much appreciate if someone can help me on this.
You have to account for the case that you have not yet received a location. To do that, your client code needs to check the return of getLocation for null, and handle accordingly.
Additionally you may want some more intelligence in onLocationChanged. Right now if a gps location comes in and then a network location comes in, the network location will overwrite the gps location, despite being less accurate. I'd take a look at some code I wrote at http://gabesechansoftware.com/location-tracking/ You'll see a class FallbackLocationTracker which will track both gps and network location, returning the most accurate location received so far. I think it does what you're trying to do.
i want a background service class that which will get the user current location sends as a notification to the user if the user changes its location then the updated location will sends back to the user as a notification..even if the user close the application then also will receive the notification (the service will trace the location in background even application closed)
currently i am using this service for tracing the location which works if the application in foreground
can u pls. help me to get out of this i am struggling for 4 hours
in your activity unlike the one that you are using make your buttons start and stop the service and it will run in the background unless the user reopens the app and stops it
Intent i = new Intent(MainActivity.this,gpsservice.class);
startService(new Intent(i));
or to stop
Intent j = new Intent(MainActivity.this,gpsservice.class);
stopService(new Intent(j));
use this service
public class gpsservice extends Service{
private LocationManager locationManager;
MyLocationListener locationListenerp;
public gpsservice() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
locationManager = (LocationManager)
getSystemService(Context.LOCATION_SERVICE);
locationListenerp = new MyLocationListener();
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 5000, 10, locationListenerp);
}
#Override
public void onDestroy() {
locationManager.removeUpdates(locationListenerp);
}
#Override
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "location Service Started", Toast.LENGTH_LONG).show();
}
public class MyLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location location) {
Toast.makeText(getApplicationContext(), "I was here", Toast.LENGTH_LONG).show();
}
#Override
public void onProviderDisabled(String s) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
// TODO Auto-generated method stub
}
}
}