Android periodic location updates using workmanager - android

I am using a WorkManager as follows -
class LocationWorker(
ctx: Context, params: WorkerParameters
) : CoroutineWorker(ctx, params), KoinComponent {
private val locationDataRepository: LocationDataRepository by inject()
override suspend fun doWork(): Result {
return try {
locationDataRepository.triggerLocationUpdates()
Result.success()
} catch (e: Exception) {
Result.failure()
}
}
}
I trigger the Worker as -
val myWorker =
PeriodicWorkRequestBuilder<LocationWorker>(
15,
TimeUnit.MINUTES
).addTag(
"location"
).build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"location",
ExistingPeriodicWorkPolicy.KEEP,
myWorker
)
As you see, the WorkManager minimum period is 15 minutes. I want to track the location for very short intervals say every few seconds and also I want the location to be tracked even when the phone screen is off. Is WorkManager the right choice for my requirements or would you suggest me some other API?

It might help you it works even when the app is killed..I'm just a tad
concerned when device enters doze mode as gps cannot be accessed when
device is stationary
foreground service main purpose is to run with a persistent notification when the app is killed
LocationService.class
public class LocationService extends Service implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000 * 30; //30 secs
public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
UPDATE_INTERVAL_IN_MILLISECONDS / 2;
protected static final String TAG = "LocationUpdateService";
public static final int HORIZONTAL_ACCURACY_IN_METERS = 100;
/**
* The identifier for the notification displayed for the foreground service.
*/
private static final int NOTIFICATION_ID = 12345678;
public static boolean mRequestingLocationUpdates = false;
public boolean isEnded = false;
protected GoogleApiClient mGoogleApiClient;
protected LocationRequest mLocationRequest;
private SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
private double latitude = 0;
private double longitude = 0;
private float[] results1 = new float[1];
private float distanceInMeters = 0;
private Handler mHandler;
#Override
public void onCreate() {
super.onCreate();
String CHANNEL_ID = "FOREGROUND_CHANNEL";
if (Build.VERSION.SDK_INT >= 26) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
"location_notification",
NotificationManager.IMPORTANCE_DEFAULT);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
}
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setOngoing(true)
.setContentTitle("G Star")
.setSmallIcon(R.drawable.gm_noti_logo)
.setContentText("Running").build();
startForeground(NOTIFICATION_ID, notification);
Utility.getInstance().makeDescriptiveLogs("ON CREATE WAS HIT");
sendLocationDataToServerPeriodically();
}
private void sendLocationDataToServerPeriodically() {
//getting the alarm manager
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
//creating a new intent specifying the broadcast receiver
Intent intentLR = new Intent(this, PostLocationReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, intentLR,
PendingIntent.FLAG_UPDATE_CURRENT);
if (android.os.Build.VERSION.SDK_INT >= 23) {
assert am != null;
am.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
AlarmManager.INTERVAL_FIFTEEN_MINUTES, pi);
} else if (Build.VERSION.SDK_INT >= 19) {
if (am != null) {
am.setInexactRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pi);
}
} else {
if (am != null) {
am.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pi);
}
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
isEnded = false;
Utility.getInstance().makeDescriptiveLogs("ONSTART COMMAND WAS HIT");
buildGoogleApiClient();
if (mGoogleApiClient.isConnected() && mRequestingLocationUpdates) {
startLocationUpdates();
}
mHandler = new Handler();
return START_STICKY;
}
#Override
public void onConnected(Bundle bundle) {
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
mGoogleApiClient.connect();
}
#Override
public void onLocationChanged(Location location) {
if (location.getAccuracy() < HORIZONTAL_ACCURACY_IN_METERS)
updateUI(location);
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
createLocationRequest();
}
/**
* Updates the latitude, the longitude, and the last location time in the UI.
*/
private void updateUI(Location mCurrentLocation) {
mHandler.post(() -> {
/*GET DEVICE CURRENT BATTERY LEVEL*/
int batteryPercent = Utility.getInstance().getBatteryPercentage(LocationService.this);
/* CALCULATE DISTANCE BETWEEN LAT LONG INTERVALS*/
if (latitude != 0 && longitude != 0) {
Location.distanceBetween(latitude, longitude, mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude(), results1);
distanceInMeters = results1[0];
}
latitude = mCurrentLocation.getLatitude();
longitude = mCurrentLocation.getLongitude();
/*CHECK IF DEVICE HAS ACTIVE INTERNET CONNECTION*/
String networkStatus = Utility.getInstance().checkConnection(LocationService.this) ? "1" : "0";
/*CHECK NETWORK SIGNAL STRENGTH*/
String signalStrength = Utility.getInstance().getSignalStrength(LocationService.this);
SQLiteDBHandler db = SQLiteDBHandler.getInstance(LocationService.this);
db.insertDeviceLocation(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude(), Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? mCurrentLocation.getSpeedAccuracyMetersPerSecond() : mCurrentLocation.getSpeed(), sdf.format(Calendar.getInstance().getTime()), distanceInMeters, batteryPercent, networkStatus, signalStrength);
});
}
protected void createLocationRequest() {
mGoogleApiClient.connect();
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setSmallestDisplacement(5);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
/**
* Requests location updates from the FusedLocationApi.
*/
public void startLocationUpdates() {
if (!mRequestingLocationUpdates) {
mRequestingLocationUpdates = true;
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
isEnded = true;
}
}
/**
* Removes location updates from the FusedLocationApi.
*/
public void stopLocationUpdates() {
if (mRequestingLocationUpdates) {
mRequestingLocationUpdates = false;
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
#Override
public void onDestroy() {
mHandler.removeCallbacksAndMessages(null);
stopLocationUpdates();
super.onDestroy();
}
}

I think that this codelab is the best solution. Without the WorkManager, but for me it works in AccessibilityService ( I realized it like an alternative to ForegroundService) to escape the permanent notification https://codelabs.developers.google.com/codelabs/background-location-updates-android-o/#0

Related

GeofenceIntentService not getting triggered on geofence enter

I'm trying to create geofences without google maps (just service that triggers PendingIntent when user is in geofence area). The problem is that I'm not able to get response when user enters geofence location. Here is my code from service class:
public class GeofenceBackgroundService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener,
ResultCallback<Status> {
private GoogleApiClient googleApiClient;
private GeofencingClient mGeofencingClient;
private LocationRequest locationRequest;
private PendingIntent geoFencePendingIntent;
private final int GEOFENCE_REQ_CODE = 0;
private static final String GEOFENCE_REQ_ID = "My Geofence";
private static final float GEOFENCE_RADIUS = 500.0f;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
/*mGeofencingClient = LocationServices.getGeofencingClient(this);*/
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
googleApiClient.connect();
locationRequest = LocationRequest.create()
.setInterval(10000)
.setFastestInterval(5000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
return START_STICKY;
}
#Override
public void onConnected(Bundle dataBundle) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
Geofence geofence = createGeofence();
GeofencingRequest geofenceRequest = createGeofenceRequest(geofence);
addGeofence(geofenceRequest);
}
#Override
public void onConnectionSuspended(int i) {
googleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
#Override
public void onLocationChanged(Location location) {
if (location != null) {
Log.e("TAG", "Location changed " + location.getLatitude() +" " + location.getLongitude());
}
}
private Geofence createGeofence() {
return new Geofence.Builder()
.setRequestId(GEOFENCE_REQ_ID)
.setCircularRegion(35.3140045, 103.4839695, GEOFENCE_RADIUS)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setNotificationResponsiveness(1000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
.build();
}
private GeofencingRequest createGeofenceRequest(Geofence geofence) {
return new GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.addGeofence(geofence)
.build();
}
private PendingIntent createGeofencePendingIntent() {
if (geoFencePendingIntent != null)
return geoFencePendingIntent;
/*Intent intent = new Intent("com.receive.ACTION_RECEIVE_GEOFENCE");
PendingIntent geoFencePendingIntent = PendingIntent.getBroadcast( getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return geoFencePendingIntent;*/
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
return PendingIntent.getService(this, GEOFENCE_REQ_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
private void addGeofence(GeofencingRequest request) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.GeofencingApi.addGeofences(googleApiClient, request, createGeofencePendingIntent()).setResultCallback(this);
}
#Override
public void onResult(#NonNull Status status) {
if ( status.isSuccess() ) {
} else {
}
}
#Override
public void onDestroy() {
super.onDestroy();
googleApiClient.disconnect();
}}
Also I tried to use both IntentService and Broadcast receiver and declared them properly in android manifest file

Can not get accurate location while travelling in bus without internet

I am developing offline car tracker android application. It will update location after 5 min and stores it in SQLite.I used FusedLocationAPI but can not get accurate location while travelling in bus without Internet. I am getting accuracy 999m and getting same location after every 5 minutes.
I set alarm manager to 5 minutes.
public static void startAlarmManager(Context context)
{
preferences =context.getSharedPreferences(Constant.SHARED_PREF_NAME, Context.MODE_PRIVATE);
int duration= Integer.parseInt(preferences.getString(Constant.DURATION_SHARED_PREF,Constant.CONSTANT_DURATION_SHARED_PREF));
Log.d("duration",duration+"");
alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
gpsTrackerIntent = new Intent(context, GpsTrackerAlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(context, 0, gpsTrackerIntent, 0);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(),
5*60000,
pendingIntent);
}
It will fire broadcast receiver.
public class GpsTrackerAlarmReceiver extends WakefulBroadcastReceiver {
private static final String TAG = "GpsTrackerAlarmReceiver";
#Override
public void onReceive(Context context, Intent intent) {
LocationManager manager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE );
boolean statusOfGPS = manager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if(statusOfGPS) {
context.startService(new Intent(context, LocationService.class));
}
}
}
This is location service. I am getting location with this way.
public class LocationService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private static final String TAG = "LocationService";
public static GoogleApiClient googleApiClient;
private LocationRequest locationRequest;
public Context context;
private DatabaseHelper db;
private boolean currentlyProcessingLocation = false;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
if (!currentlyProcessingLocation) {
currentlyProcessingLocation = true;
startTracking();
}
return START_NOT_STICKY;
}
private void startTracking() {
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
if (!googleApiClient.isConnected() || !googleApiClient.isConnecting()) {
googleApiClient.connect();
}
} else {
Log.e(TAG, "unable to connect to google play services.");
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.d(TAG, "onConnected");
locationRequest = LocationRequest.create();
locationRequest.setInterval(1000); // milliseconds
locationRequest.setFastestInterval(1000); // the fastest rate in milliseconds at which your app can handle location updates
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(
googleApiClient, locationRequest, this);
}
#Override
public void onConnectionSuspended(int i) {
Log.e(TAG, "GoogleApiClient connection has been suspend");
}
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, "onLocationChanged");
startupdate(location);
}
private void startupdate(Location location) {
if (location != null) {
db=new DatabaseHelper(this);
db.insertLocation(location.getLatitude(), location.getLongitude(), "FusedApi Provider", location.getAccuracy());
stopLocationUpdates();
stopSelf();
}
}
public void stopLocationUpdates() {
if (googleApiClient != null && googleApiClient.isConnected()) {
googleApiClient.disconnect();
}
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.e(TAG, "onConnectionFailed");
stopLocationUpdates();
stopSelf();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Please help...if i am wrong. Thanks in advance.
When GPS is not practical you can use LocationManager.NETWORK_PROVIDER, this is location from the phone carrier that is less accurate than GPS but is available everywhere the carrier has a tower. The way I do it is a set a flag isGpsAvailable() to see if that is true I use GPS otherwise I use network provided location. This Google's doc provides detailed solutions including code snippets that you can use and change the way you it fits your needs.

GPS icon disappear when open location popup or the app is killed

I am developing an app that should send gps data to a server once every 10 minutes. The problem is that when I kill the app when the GPS is ON, the GPS icon disappear from the status bar (while the GPS is still ON) and the data are not sent anymore. If I do the same with the google maps app the icon doesn't disappear.
Can someone explain me why this is happening?
here is the code that I use
AlarmManager
/**
* ALARM_MANAGER_GPS_TIME_INTERVAL = 10 min
*/
PendingIntent mPendingIntent = PendingIntent
.getService(
context,
PENDING_INTENT_REQUEST_CODE_FOR_GPS,
new Intent(context, GpsDataService.class),
PendingIntent.FLAG_IMMUTABLE);
AlarmManager mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mAlarmManager.setInexactRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(),
ALARM_MANAGER_GPS_TIME_INTERVAL,
mPendingIntent);
Service
public class GpsDataService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
/**
* Provides the entry point to Google Play services.
*/
protected GoogleApiClient mGoogleApiClient;
/**
* Stores parameters for requests to the FusedLocationProviderApi.
*/
protected LocationRequest mLocationRequest;
/**
* Represents a geographical location.
*/
protected Location mCurrentLocation;
private String mPayLoad;
private GpsPojoBuilder mGpsPojoBuilder;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(mGoogleApiClient == null)
buildGoogleApiClient();
mGoogleApiClient.connect();
if (mGoogleApiClient.isConnected())
startLocationUpdates();
return Service.START_NOT_STICKY;
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
createLocationRequest();
}
/**
* UPDATE_INTERVAL_IN_MILLISECONDS = 4 sec
* FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 2 sec
*/
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest
.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS)
.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
#Override
public void onConnected(#Nullable Bundle bundle) {
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
// The connection to Google Play services was lost for some reason. Call connect() to
// attempt to re-establish the connection.
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
/**
* Requests location updates from the FusedLocationApi.
*/
protected void startLocationUpdates() {
checkForPermission();
}
private void checkForPermission() {
Location location;
if (Build.VERSION.SDK_INT >= 23) {
if (ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
//permission denied
} else {
location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (location != null)
handleLocation(location);
else
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
}else {
location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if(location != null)
handleLocation(location);
else
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
}
#Override
public void onLocationChanged(Location location) {
handleLocation(location);
}
private void handleLocation(Location location){
mCurrentLocation = location;
Toast.makeText(this, "location foound: " + location.toString(), Toast.LENGTH_SHORT).show();
Thread thread = new Thread() {
#Override
public void run() {
try {
mGpsPojoBuilder = new GpsPojoBuilder(getApplicationContext());
mPayLoad = mGpsPojoBuilder
.getCheckInJson(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude());
sendJSON(mPayLoad, CHECKINS_URL);
} catch (GooglePlayServicesRepairableException e) {
e.printStackTrace();
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(mGoogleApiClient.isConnected()) {
stopLocationUpdates();
mGoogleApiClient.disconnect();
}
}
}
};
thread.start();
}
public void sendJSON(String payLoadData, String url_suffix) {
HttpConnectionCreator mHttpConncectionClass = new HttpConnectionCreator(payLoadData, url_suffix);
mHttpConncectionClass.connect();
}
/**
* Removes location updates from the FusedLocationApi.
*/
protected void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
if (mGoogleApiClient.isConnected()) {
stopLocationUpdates();
mGoogleApiClient.disconnect();
}
super.onDestroy();
}
}
According to android.developer, if you want to keep your services alive, you need to use START_STICKY.
int START_STICKY
Constant to return from onStartCommand(Intent, int, int): if this service's process is killed while it is started (after returning from onStartCommand(Intent, int, int)), then leave it in the started state but don't retain this delivered intent. Later the system will try to re-create the service.
inside the following function:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(mGoogleApiClient == null)
buildGoogleApiClient();
mGoogleApiClient.connect();
if (mGoogleApiClient.isConnected())
startLocationUpdates();
return Service.START_NOT_STICKY;
}
change to this:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(mGoogleApiClient == null)
buildGoogleApiClient();
mGoogleApiClient.connect();
if (mGoogleApiClient.isConnected())
startLocationUpdates();
return Service.START_STICKY;
}

FusedLocaionAPI Searching GPS signal stops

I have a service that when it creates and starts, initiates prerequisites of using FusedLocationAPI . buildGoogleApiClient() and createLocationRequest() with parameters that initiated by my getConfig() method from database.
This solution works great and accurate with parameters like:
UPDATE_INTERVAL= 10000 (10 sec) , FASTEST_INTERVAL= 5000 (5 sec) , DISPLACEMENT= 10 ( m )
But I need to set interval up to 5 minutes. So when i set prameters like :
UPDATE_INTERVAL= 300000 (5 min) , FASTEST_INTERVAL= 180000 (3 min) , DISPLACEMENT= 10 ( m )
GPS behaves differently and after 30 seconds stops searching GPS and location notification that blinks, disappears.
And starts searching again after device locked and unlocked or this Service stops and starts again.
Here is my service. Please tell me why searching GPS stops right after 30 seconds.
Thanks in advanece.
public class MainService extends Service implements ConnectionCallbacks,
OnConnectionFailedListener, LocationListener {
private final static String TAG = MainActivity.class.getSimpleName();
private static int UPDATE_INTERVAL;
private static int FASTEST_INTERVAL;
private static int DISPLACEMENT;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private Location mLastLocation;
public String deviceIMEI;
public boolean isGpsEnabled = false;
DatabaseHelper mDBHelper;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
getDeviceIMEI();
getConfig();
startForeGroundService();
if (checkPlayServices() && checkLocationServices()) {
buildGoogleApiClient();
createLocationRequest();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mGoogleApiClient != null)
mGoogleApiClient.connect();
else {
stopForeground(true);
stopSelf();
}
return (START_NOT_STICKY);
}
#Override
public void onDestroy() {
stopForeground(true);
if (mGoogleApiClient != null)
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
#SuppressWarnings("deprecation")
public void startForeGroundService() {
Notification note = new Notification(
R.drawable.track_notification_alert,
"GPS tracking started ...", System.currentTimeMillis());
Intent i = new Intent();
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pi = PendingIntent.getActivity(this, 0, i, 0);
note.setLatestEventInfo(this, "GPS is active.",
"Now this tablet is under tracking. ", pi);
note.flags |= Notification.FLAG_NO_CLEAR;
startForeground(1337, note);
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setSmallestDisplacement(DISPLACEMENT);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
private boolean checkLocationServices() {
LocationManager lm = (LocationManager) getApplicationContext()
.getSystemService(LOCATION_SERVICE);
isGpsEnabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
return isGpsEnabled;
}
private boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil
.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
return false;
}
return true;
}
#Override
public void onConnected(Bundle arg0) {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
if (Globals.isSatelliteFix && Globals.isGPSEnable)
setPoint();
}
#Override
public void onConnectionSuspended(int arg0) {
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = "
+ result.getErrorCode());
}
#Override
public void onLocationChanged(Location location) {
mLastLocation = location;
if (Globals.isSatelliteFix && Globals.isGPSEnable)
setPoint();
}
private void setPoint() {
mDBHelper = new DatabaseHelper(getApplicationContext());
mLastLocation = LocationServices.FusedLocationApi
.getLastLocation(mGoogleApiClient);
if (mLastLocation != null) {
double latitude = mLastLocation.getLatitude();
double longitude = mLastLocation.getLongitude();
try {
Point p = new Point();
p.setId(UUID.randomUUID().toString());
p.setIMEI(deviceIMEI);
p.setLatitude(String.valueOf(latitude));
p.setLongitude(String.valueOf(longitude));
p.setTimeStamp(createTimeStamp());
long result = mDBHelper.addPoint(p);
if (result != -1) {
Log.i(TAG, "Insertion Successfull With RowId: " + result);
} else
Log.e(TAG, "Insertion Error");
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "Insertion Error: " + e.getMessage());
}
}
}
public String createTimeStamp() {
String strTimeStamp = new SimpleDateFormat("yyyy-MM-dd_kk:mm:ss")
.format(new Date());
return strTimeStamp;
}
public void getDeviceIMEI() {
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
deviceIMEI = telephonyManager.getDeviceId();
}
public long getTimeInMiliSeconds() {
Calendar calendar = Calendar.getInstance();
Date date = calendar.getTime();
return date.getTime();
}
public void getConfig() {
Config config = new Config();
mDBHelper = new DatabaseHelper(getApplicationContext());
config = mDBHelper.getConfig();
UPDATE_INTERVAL = config.getUpdateInterval();
FASTEST_INTERVAL = config.getFastestInterval();
DISPLACEMENT = config.getSmallestDisplacement();
}
}

Use less battery with GPS location every 15 minutes

I'm implementing an application which need to send a location to GCM every 15 minutes. I implemented an AlarmManager which will be called every 15 minute.
Here is my class of my alarmmanager
public class LocationAlarmManager {
Context mContext = null;
public LocationAlarmManager (Context context) {
mContext = context;
}
private AlarmManager alarmManager;
private Intent gpsTrackerIntent;
private PendingIntent pendingIntent;
private static final String TAG = "LocationAlarmManager";
public void startAlarmManager() {
Log.d(TAG, "startAlarmManager");
alarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
gpsTrackerIntent = new Intent(mContext, GpsTrackerAlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(mContext, 0, gpsTrackerIntent, 0);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(),
15 * 60000, // 60000 = 1 minute
pendingIntent);
}
public void cancelAlarmManager() {
Log.d(TAG, "cancelAlarmManager");
Intent gpsTrackerIntent = new Intent(mContext, GpsTrackerAlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, gpsTrackerIntent, 0);
AlarmManager alarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
}
That one calls GpsTrackerAlarmReceiver
// make sure we use a WakefulBroadcastReceiver so that we acquire a partial wakelock
public class GpsTrackerAlarmReceiver extends WakefulBroadcastReceiver {
private static final String TAG = "GpsTrackerAlarmReceiver";
#Override
public void onReceive(Context context, Intent intent) { context.startService(new Intent(context, SmartLocationService.class));
}
}
For handling my location I implemented the following in my SmartLocationService.
public class SmartLocationService extends Service implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener,
LocationListener {
private static final String TAG = "SmartLocationService";
// use the websmithing defaultUploadWebsite for testing and then check your
// location with your browser here: https://www.websmithing.com/gpstracker/displaymap.php
private String defaultUploadWebsite;
private boolean currentlyProcessingLocation = false;
private LocationRequest locationRequest;
private LocationClient locationClient;
public LocationManager locationManager;
Context context;
// flag for GPS status
public boolean isGPSEnabled = false;
// flag for network status
boolean isNetworkEnabled = false;
// flag for GPS status
boolean canGetLocation = false;
Location location; // location
double latitude; // latitude
double longitude; // longitude
public Location previousBestLocation;
private double mLastLatitudeLocation = 0;
private double mLastLongitudeLocation = 0;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// if we are currently trying to get a location and the alarm manager has called this again,
// no need to start processing a new location.
if (!currentlyProcessingLocation) {
currentlyProcessingLocation = true;
startTracking();
}
return START_NOT_STICKY;
}
private void startTracking() {
Log.d(TAG, "startTracking");
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
locationClient = new LocationClient(this,this,this);
if (!locationClient.isConnected() || !locationClient.isConnecting()) {
locationClient.connect();
}
} else {
Log.e(TAG, "unable to connect to google play services.");
}
}
protected void sendLocationDataToWebsite(Location loc) {
MessageHandler messageHandler = new MessageHandler(SmartLocationService.this);
messageHandler.sendLocationMessage(loc); //send location to GCM
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onLocationChanged(Location location) {
if (location != null) {
Log.e(TAG, "position: " + location.getLatitude() + ", " + location.getLongitude() + " accuracy: " + location.getAccuracy());
sendLocationDataToWebsite(location);
}
}
private void stopLocationUpdates() {
if (locationClient != null && locationClient.isConnected()) {
locationClient.removeLocationUpdates(this);
locationClient.disconnect();
}
}
/**
* 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) {
context = getApplicationContext();
Log.d(TAG, "onConnected");
locationRequest = LocationRequest.create();
locationRequest.setInterval(900000); // milliseconds
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationClient.requestLocationUpdates(locationRequest, this);
}
/**
* Called by Location Services if the connection to the
* location client drops because of an error.
*/
#Override
public void onDisconnected() {
Log.e(TAG, "onDisconnected");
stopLocationUpdates();
stopSelf();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.e(TAG, "onConnectionFailed");
stopLocationUpdates();
stopSelf();
}
}
This works, but my locationservice get called more then once in my timeslot of 15 minutes. Anyone know why? Is this a good way to use less battery power (GPS)?
Thanks

Categories

Resources