I have a location service which sends location to my server after every 3 minutes.This location service is started from Activity by click of a button.I want this service stops automatically after 6 hours from started time.Here is my service file.Service is starting normally and i am able to stop it by click of a button in activity.But i want to stop it automatically after 6 hours even app is minimized.Any help would be highly appreciated.
public class LocationService extends Service {
private LocationListener listener;
private LocationManager locationManager;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
listener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
Log.i("location:","location is "+location.getLongitude()+" "+location.getLatitude());
LocationApi.sendGpsLocation(getApplicationContext(),location.getLongitude(),location.getLatitude());
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onProviderDisabled(String provider) {
Log.e("disabled provider is :","location is "+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);
if (ContextCompat.checkSelfPermission(DashboardActivity.activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ) {
locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,3000,0,listener);
}
}
/* #Override
public final void stopSelf(){
}*/
#Override
public boolean onUnbind(Intent intent) {
LocationApi.stopLocation(getApplicationContext());
//super.onDestroy();
if (locationManager != null) {
//noinspection MissingPermission
locationManager.removeUpdates(listener);
}
return super.onUnbind(intent);
}
#Override
public void onDestroy() {
LocationApi.stopLocation(getApplicationContext());
super.onDestroy();
if(locationManager != null){
//noinspection MissingPermission
locationManager.removeUpdates(listener);
}
}
}
and i start this service in Activity by below code.
Intent i = new Intent(getApplicationContext(), LocationService.class);
if (Build.VERSION.SDK_INT >= 26) {
startForegroundService(i);
}else{
startService(i);
}
You can add a counter to your 3 min timer and count up til you reach 120 and than stop Locationupdates and shutdown the service.
You could schedule an alarm via AlarmManager when the service gets started - this will be an Intent you receive. When receiving you can stop your running service.
Try this code:
public class LocationService extends Service {
public static final String ACTION_STOP = "com.mycompany.myapp.SERVICE_STOP";
/*private static final long UPDATE_INTERVAL = 3 * 60 * 1000;
private static final long STOP_INTERVAL = 6 * 3600 * 1000;*/
private static final long UPDATE_INTERVAL = 3 * 1000;
private static final long STOP_INTERVAL = 20 * 1000;
private LocationListener listener;
private LocationManager locationManager;
private BroadcastReceiver receiver;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent i, int flags, int startId){
if (Build.VERSION.SDK_INT >= 26){
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = new NotificationChannel("Location",
"Location", NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
Notification notif = new NotificationCompat.Builder(this, "Location")
.setContentTitle("Location service")
.build();
startForeground(3001, notif);
}
return START_STICKY;
}
#Override
public void onCreate() {
listener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
Log.i("location:","location is "+location.getLongitude()+" "+location.getLatitude());
LocationApi.sendGpsLocation(getApplicationContext(),location.getLongitude(),location.getLatitude());
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onProviderDisabled(String provider) {
Log.e("disabled provider is :","location is "+provider);
Intent i = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
};
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ) {
locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,UPDATE_INTERVAL,0,listener);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,UPDATE_INTERVAL,0f,listener);
}
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent i = new Intent(ACTION_STOP);
PendingIntent pi = PendingIntent.getBroadcast(this, 100, i, PendingIntent.FLAG_UPDATE_CURRENT);
am.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + STOP_INTERVAL, pi);
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
stopSelf();
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_STOP);
registerReceiver(receiver, filter);
}
#Override
public void onDestroy() {
Log.i("location:","stopping updates");
unregisterReceiver(receiver);
LocationApi.stopLocation(getApplicationContext());
super.onDestroy();
if(locationManager != null){
locationManager.removeUpdates(listener);
}
}
}
Explanation: use AlarmManager.set() to schedule a broadcast after certain time (STOP_INTERVAL). To receive the broadcast, register a receiver in onCreate(), and unregister it in onDestroy().
Related
I tried to get gps data (speed) when I don't use the app i'm programming.
but always when I close the app it stops asking for gps updates. now I got told, that I have to use a service. so i did, but it still stops asking for updates everytime I close to ui of the app.
here is my code of the service:
package com.example.slartibartfast.kslordered;
public class BackroundService extends Service {
private static float speed;
//initializing the Location Manager and Listener
LocationManager locationManager;
LocationListener locationListener;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#SuppressLint("MissingPermission")
#Override
public void onCreate() {
//Instantiating the device manager an listener
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
//when the location changed
Log.d("Location", ""+location);
Log.d("Float Location", ""+ location.getLongitude() + " " + location.getLatitude());
Log.d("Speed", " "+location.getSpeed());
//initializing the variable speed with the speed number given by the LocationListener
speed = location.getSpeed();
//creating a broadcast reciever
Intent intent = new Intent("speed_update");
intent.putExtra("speed", speed);
//sending speed to main activity
sendBroadcast(intent);
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onProviderDisabled(String s) {
//if gps is disabled, this opens the gps settings
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
};
locationManager.requestLocationUpdates("gps", 5000, 0, locationListener);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
}
and here of my main activity:
package com.example.slartibartfast.kslordered;
public class MainActivity extends AppCompatActivity {
//initializing ui elements
TextView textviewSpeed;
Button button;
//initializing ui BroadcastReciever
private BroadcastReceiver broadcastReceiver;
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//instantiating the ui elements
textviewSpeed = (TextView)findViewById(R.id.textview_speed);
//checking if permission to use gps location is given
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 10);
return;
}else{
}
startService(new Intent(this, BackroundService.class));
}
#Override
protected void onResume() {
super.onResume();
//broadcast reciever gets speed from the backround service
if (broadcastReceiver == null){
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//speed get's set on the textview
textviewSpeed.setText(""+ intent.getExtras().get("speed"));
}
};
}
registerReceiver(broadcastReceiver, new IntentFilter("speed_update"));
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
//asks for the gps user permission
switch (requestCode){
case 10:
if (grantResults.length>0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//(5000);
}
}
}
I think you need to add your code on OnStart instead of OnCreate
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
//when the location changed
Log.d("Location", ""+location);
Log.d("Float Location", ""+ location.getLongitude() + " " + location.getLatitude());
Log.d("Speed", " "+location.getSpeed());
//initializing the variable speed with the speed number given by the LocationListener
speed = location.getSpeed();
//creating a broadcast reciever
Intent intent = new Intent("speed_update");
intent.putExtra("speed", speed);
//sending speed to main activity
sendBroadcast(intent);
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onProviderDisabled(String s) {
//if gps is disabled, this opens the gps settings
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
};
locationManager.requestLocationUpdates("gps", 5000, 0, locationListener);
return START_STICKY;
}
My app is like a tracker. It saves user locations, then sends it to server.
I made this server foreground and sticky. On samsung s4 everything works fine, but on huawei honor 4c service gets killed as fast as i lock screen. Moreover, methods like onDestroy() are not called. If i add app to "Protected apps" it lives more, but nearly 30-45 mins. Is there a way to keep my service alive? Or is there a way to solve my problem without foreground service? I searched tons of posts about this problem, but didnt find solution.
Here is my service
public class LocationService extends Service {
private static final long TIME_BETWEEN_LOCATION_SEND_IN_MILLIS = 60 * 1000;
private static final long TIME_BETWEEN_LOCATION_UPDATES = 10 * 1000;
private List<Location> locations;
private int NOTIFICATION_ID = 31337;
private boolean isAlreadyRunning = false;
public boolean Continue = true;
private GoogleApiClient googleApiClient;
#Override
public void onCreate() {
super.onCreate();
GoogleApiClient.Builder builder = new GoogleApiClient.Builder(getApplicationContext());
googleApiClient = builder
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.wtf("lol", "connected");
LocationRequest locationRequest = new LocationRequest();
locationRequest.setInterval(TIME_BETWEEN_LOCATION_UPDATES);
locationRequest.setFastestInterval(TIME_BETWEEN_LOCATION_UPDATES);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
//noinspection MissingPermission
LocationServices.FusedLocationApi.requestLocationUpdates(
googleApiClient, locationRequest, new LocationListener() {
#Override
public void onLocationChanged(Location location) {
locations.add(location);
}
});
}
#Override
public void onConnectionSuspended(int i) {
Log.wtf("lol", "connection suspended");
}
})
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(
#NonNull ConnectionResult connectionResult
) {
Log.wtf("lol", "connection Failed");
}
})
.addApi(LocationServices.API)
.build();
locations = new ArrayList<>();
}
#Override
public void onLowMemory() {
super.onLowMemory();
Log.wtf("lol","service onlow");
}
#Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
Log.wtf("lol","service ontrim");
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.wtf("lol","service ontaskremoved");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.wtf("lol", "service OnStartCommand");
if (!isAlreadyRunning) {
Intent resultIntent = new Intent(getApplicationContext(), MainActivity.class);
resultIntent.setAction(Intent.ACTION_MAIN);
resultIntent.addCategory(Intent.CATEGORY_LAUNCHER);
PendingIntent resultPendingIntent = PendingIntent.getActivity(
this,
333,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.setContentTitle("Title")
.setContentText("Explanation!")
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(resultPendingIntent);
Notification notification = builder.build();
startForeground(NOTIFICATION_ID, notification);
googleApiClient.connect();
isAlreadyRunning = true;
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (locations.size() > 0) {
sendLocationsAndClearList();
}
if(Continue){
handler.postDelayed(this,TIME_BETWEEN_LOCATION_SEND_IN_MILLIS);
}
}
},TIME_BETWEEN_LOCATION_SEND_IN_MILLIS);
}
return Service.START_STICKY;
}
#Override
public void onDestroy() {
Log.wtf("lol", "service onDestroy");
Continue = false;
googleApiClient.disconnect();
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
You also have to create a CPU wake lock. The CPU can tear down to a low power mode which will stop your app process. It may resume if the CPU powers up again for some reason.
Have a look for the WAKE LOCK topic in the Android documentation.
I have a Bound service which collects locations for 3 minutes every 15 minutes. I start a CountDownTimer once the Service is connected in onServiceConnected of ServiceConnection.
I receive all the Timer callbacks (onFinish) (onTick) perfectly as far the Activity which bindService is visible.
When Device is locked I do not receive any updates from the timer.
MyLocationService
public class MyLocationService extends Service implements MyTimerListener{
private IBinder mBinder = new MyLocationBinder();
public void onCreate() {
locationManager = new MyLocationManager(this);
}
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
public class MyLocationBinder extends Binder
{
public MyLocationService getService()
{
return MyLocationService.this;
}
}
public void startFetchingLocations()
{
if(locationManager != null){
locationManager.startFetchingLocations();
if(publishPeriodCountDownTimer != null) {
publishPeriodCountDownTimer.cancel();
publishPeriodCountDownTimer = null;
}
publishPeriodCountDownTimer = new MyCountTimer(gpsPublishPeriod * 60 * 1000, 1000, MyLocationService.this);
publishPeriodCountDownTimer.start();
}
}
#Override
public void onTimeFinished() {
//Start fetching locations
locationManager.startFetchingLocations(); //Start 3 min CountdownTimer
}
#Override
public void onTick() {
}
public void onAllLocationsRecieved(ArrayList<Location> locations)
{
//Do stuff on Locations
locationManager.stopFetchingGPS(); //Stops 3 min countdownTimer
}
}
MyActivty
public class MyActivity
{
#Override
protected void onStart() {
super.onStart();
btnStop.setVisibility(View.VISIBLE);
MyNoificationManager.cancelAllNotifications();
if (!isLocationServiceBound) {
Intent locServiceIntent = new Intent(this, MyLocationService.class);
bindService(locServiceIntent, locationServiceConnection, Context.BIND_AUTO_CREATE);
}
}
private ServiceConnection locationServiceConnection = new ServiceConnection(){
#Override
public void onServiceDisconnected(ComponentName name) {
isLocationServiceBound = false;
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyLocationBinder locationBinder = (MyLocationBinder) service;
locationService = locationBinder.getService();
isLocationServiceBound = true;
locationService.startFetchingLocations();
}
};
}
It works as expected when the Activity is visible. The timer doesn't provide any onTick() or onTimeFinished() callbacks when the device is locked.
What could be the problem here ?
The CountDownTimer will not work when the phone goes to sleep mode. This is by design and it's to save battery life.
Alternately you can use android.app.AlarmManager instead to achieve your goal. Following is the sample code how to do that. Set the alaram like below
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, MyLocationService.class);
intent.putExtra("need_to_fetch_loc", true);
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
alarmManager.set(AlarmManager.RTC_WAKEUP, gpsPublishPeriod * 60 * 1000, alarmIntent);
Add the following method to your MyLocationService class
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(locationManager!= null && intent.getBooleanExtra("need_to_fetch_loc", false))
{
locationManager.startFetchingLocations();
}
return super.onStartCommand(intent, flags, startId);
}
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.
In a Splash Activity's onResume(), I start the service this way
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent i = new Intent(this, LocationService.class);
PendingIntent pi = PendingIntent.getService(this, 0, i,
PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pi);
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
ystemClock.elapsedRealtime() + 20000, 60000, pi);
and in onStop(), I stop the service this way
stopService(new Intent(this, LocationService.class));
and the Service Class is:
public class LocationService extends Service implements LocationListener {
private LocationManager mgr;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mgr = (LocationManager) getSystemService(LOCATION_SERVICE);
//get Location details
mgr.requestLocationUpdates(LocationManager.GPS_PROVIDER,
10 * 60 * 1000, 50, this);
return START_NOT_STICKY;
}
private void dumpLocation(Location l) {
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onDestroy() {
super.onDestroy();
mgr.removeUpdates(this);
}
}
Once I stop the service in Splash Activity's onStop(), onDestroy() of the LocationService is triggered(which means the service is stopped?), but still after a minute as specified in the AlarmManager the service runs.
Store the pending intent for the alarm in a variable. Call cancel on it when the service ends.