Open pramodit opened 5 years ago
+1
+1
Any updates on this one?
@janbrodhaecker Hey You could probably use the solution which am using for now. It worked for me like a charm.
@pramodit Thanks a lot for your feedback.
Could you be so kind and provide some snippets? I read a lot about this issue and I also tried to schedule a Job - but I am not quite sure what to do when the Job is executed? Just request another location update? Is there any chance to trigger the API, so that the Geofences are evaluated again?
Thanks in advance!
Sure @janbrodhaecker This is how i am doing it . I use this JobService and reschedule it every 1 secs in Android O to make sure the OS dont kill my service. /**
JobService for Geofences above Android Oreo @author Pramod @SInCE 16-Sept-2018. */ @TargetApi(21) public class OreoJobService extends JobService {
private JobParameters mParams;
//Assuming it takes maximum 5 seconds for private String TAG = "OreoJobService";
public boolean onStartJob(JobParameters params) {
this.mParams = params;
String command = params.getExtras().getString("command");
if (command != null && command.equals("stop")) {
this.endJob();
return false;
} else {
if (MyApplication.getInstance().geoFencePendingIntent == null) {
if (params.getExtras().containsKey("fromJobScheduler")) {
String geoFences = MyApplication.getInstance().fetchGeoFences();
if (geoFences != null) {
List<Fence> fencesList = new Gson().fromJson(geoFences, new TypeToken<List<Fence>>() {
}.getType());
MyApplication.getInstance().createGeoFences(fencesList);
}
}
} else {
Log.e(TAG, "onStartJob: scheduling job ");
this.scheduleJob(10000);
}
return true;
}
}
void endJob() { this.jobFinished(this.mParams, false); }
void scheduleJob(long interval) {
ComponentName serviceName = new ComponentName(this.getPackageName(), OreoJobService.class.getName());
PersistableBundle extras = new PersistableBundle();
extras.putString("command", "start");
extras.putInt("fromJobScheduler", 1);
JobInfo jobInfo = (new JobInfo.Builder(VariableConstants_Fortees.GEOFENCE_JOB_ID, serviceName))
.setExtras(extras).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setMinimumLatency(interval)
.setOverrideDeadline(interval)
.build();
JobScheduler jobScheduler = (JobScheduler) this.getSystemService(Context.JOB_SCHEDULER_SERVICE);
assert jobScheduler != null;
jobScheduler.schedule(jobInfo);
this.endJob();
}
public boolean onStopJob(JobParameters params) {
return false;
} }
###################### And here's my logic for scheduling ##########################
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ComponentName serviceName = new ComponentName(this, OreoJobService.class.getName());
PersistableBundle extras = new PersistableBundle();
extras.putString("command", "start");
JobInfo jobInfo = (new JobInfo.Builder(VariableConstants_Fortees.GEOFENCE_JOB_ID, serviceName))
.setExtras(extras).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setMinimumLatency(1L)
.setOverrideDeadline(1L)
.build();
JobScheduler jobScheduler = (JobScheduler) this.getSystemService(Context.JOB_SCHEDULER_SERVICE);
try {
jobScheduler.schedule(jobInfo);
} catch (IllegalArgumentException errorMessage) {
errorMessage.printStackTrace();
}
}
@pramodit - thanks a lot for your answer. Could you just explain what you are doing, when the job is executed? Maybe you can give me some more hints for these lines:
if (MyApplication.getInstance().geoFencePendingIntent == null) {
if (params.getExtras().containsKey("fromJobScheduler")) {
String geoFences = MyApplication.getInstance().fetchGeoFences();
if (geoFences != null) {
List<Fence> fencesList = new Gson().fromJson(geoFences, new TypeToken<List<Fence>>() {}.getType());
MyApplication.getInstance().createGeoFences(fencesList);
}
}
Best regards, Jan.
Hey @janbrodhaecker , I am just creating the Geofences and adding to the GeofencingPendingIntent to trigger those transition events .
Here is the snippet for my createGeofences method -
public void createGeoFences(List
for (int i = 0; i < fencesList.size(); i++) {
String type = fencesList.get(i).getType();
if (type != null && !"".equals(type)) {
if ("circle".equals(type)) {
Shape shape = fencesList.get(i).getShape();
String GEOFENCE_REQ_ID = fencesList.get(i).getName();
// mGeoList.add(GEOFENCE_REQ_ID); // String GEOFENCE_IDS = fencesList.get(i).getId(); // mGeoIdList.add(GEOFENCE_IDS);
Foreground.fencesMap.put(fencesList.get(i).getName(), fencesList.get(i).getId());
if (shape != null) {
double radius = shape.getRadius();
double latitude = 0.0f, longitude = 0.0f;
Center center = shape.getCenter();
if (center != null) {
latitude = center.getLatitude();
longitude = center.getLongitude();
}
LatLng latLng = new LatLng(latitude, longitude);
float radius_float = ((float) radius);
Geofence geofence = geoFenceUtils.createGeofence(GEOFENCE_REQ_ID, latLng, radius_float);
GeofencingRequest geofenceRequest = geoFenceUtils.createGeofenceRequest(geofence);
if (ContextCompat.checkSelfPermission(mInstance, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
addGeoFences(geofenceRequest);
}
}
} else if ("polygon".equals(type)) {
Shape shape = fencesList.get(i).getShape();
String GEOFENCE_POLYGON_REQ_ID = fencesList.get(i).getName();
// mGeoList.add(GEOFENCE_POLYGON_REQ_ID); // // String GEOFENCE_POLYGON_ID = fencesList.get(i).getId(); // mGeoIdList.add(GEOFENCE_POLYGON_ID);
Foreground.fencesMap.put(fencesList.get(i).getName(), fencesList.get(i).getId());
ArrayList<LatLng> newLatLngList = new ArrayList<LatLng>();
if (shape != null) {
List<Point> pointsList = shape.getPoints();
if (pointsList.size() > 0) {
for (int j = 0; j < pointsList.size(); j++) {
double latitude = pointsList.get(j).getLatitude();
double longitude = pointsList.get(j).getLongitude();
LatLng latLng = new LatLng(latitude, longitude);
newLatLngList.add(latLng);
}
LatLng centerPointLatLng = geoFenceUtils.getPolygonCenterPoint(newLatLngList);
double center_lat = centerPointLatLng.latitude;
double center_long = centerPointLatLng.longitude;
List<Float> distanceList = new ArrayList<>();
float res[] = new float[3];
for (int m = 0; m < newLatLngList.size(); m++) {
LatLng latLng = newLatLngList.get(m);
double lat = latLng.latitude;
double longitude = latLng.longitude;
Location.distanceBetween(center_lat, center_long, lat, longitude, res);
if (res.length > 0) {
for (float f : res) {
distanceList.add(f);
}
}
}
Float max_dist = Collections.max(distanceList);
Geofence geofence = geoFenceUtils.createGeofence(GEOFENCE_POLYGON_REQ_ID, centerPointLatLng, max_dist);
GeofencingRequest geofenceRequest = geoFenceUtils.createGeofenceRequest(geofence);
if (ContextCompat.checkSelfPermission(mInstance, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
addGeoFences(geofenceRequest);
}
}
}
}
}
}
}
@pramodit - thanks for your response, I really appreciate your support!
I don't actually get the point. You are asking each second, whether the GeofencePendingIntent
still exists - if not you will recreate all the registered Geofences? I thought we need to poll the current Location in the background or anything? I think just recreating them in the background will not actually help for a long term perspective - or I am still not getting it right ...
Thanks a lot! Kind regards, Jan.
Manage to get this working with the example. Turns out my issue was the lat and long were passed incorrectly. I was passing long then lat, when it should of been lat then long.
Sadly I have still no idea why it should help to register the geofences within the JobService ...
Sadly I have still no idea why it should help to register the geofences within the JobService ...
In the example it uses JobIntentService, with a BroadcastReceiver. I think if you just use IntentService, maybe this might help you https://www.raywenderlich.com/7372-geofencing-api-tutorial-for-android
@pramodit thanks for your response. I guess it's clear, why we need to use the BroadcastReceiver
. The thing is, if I use the example provided in this project with a BroadcastReceiver
- the Geofences are not triggered when the app is killed or in the background (Android Pie, Pixel 1). That's why @pramodit provided an example, where the Geofences are registered within a JobIntentService
. And I don't understand why we need to use the JobIntentService
to register the Geofences at all.
@janbrodhaecker Sorry was busy and couldn't respond you ASAP. There's no requirement of polling your current lat long here . There was something called GeofenceHelper which was checking for the GeofenceTransitions internally with the current lat long. So i'll register the fences to the GeofencingAPI only once by that GeofencingPendingIntent and thats the reason why i do have the check if the pendingIntent is null or not . if its null only then i do re-register them . else am just scheduling the job to make sure the services doesnt get killed.
I hope its clear now. @ergun-p @janbrodhaecker
@pramodit - thanks a lot for your response again! Just one last question: How are you creating the PendingIntent
for the Geofences - via .getService
or via .getBroadcast
? Really looking forward to try out your approach! Is ist still working fine on your devices? Are you also testing on Android Pie?
I hope its clear now. @ergun-p
@pramodit Thanks, but my issue was different and is resolved.
@janbrodhaecker Yes its working on Android Pie and Android O as well. I used PendingIntent.getBroadcast for the Geofences Creation.
@pramodit thanks a lot! I will give it a try!
Hi have a basic question on this App: it does not show anything. When I click on "add geofences" nothing happen. Do you guys use the code as is, or you make some change?
You could use the code from this thread as a workaround solution for the add the geofences which keeps running in Android O and Android Pie. And from this example. it shows a notification when you enter into the geofence region. Please ensure you have changed the radius and lat longs as per your requirement according to your location in the example. @mcanonic
ok, I see many different contributions and some link to external resource code. Is there a place where I can find the complete source code working? Thanks
Anyone tried with work manager - beta?
I tried work manager on Android P, seems fine to me so far. Hopefully, it will stays that way. fingers crossed My geofences will expires after 24 hours, which i will register the geofences again at the 23rd hour by removing all geofences and register again.
@secureCam2018 can you describe what you want to achieve with the work manager? Or what you've implemented in detail?
@janbrodhaecker,
I used workmanager with a one time work request to register Geofences.
And instead of jobIntentService, I used workmanager to handle the triggering events. (After broadcast receiver received the events)
So a total of 2 workmanagers is used.
I think using one workmanager would suffice too, changing the jobIntentService to workmanager. But have not had the chance to try it out yet.
Hope this clears your doubt
Geofencing Sample doenst seems to be working with Android Oreo devices as per the background execution limits . My GeofenceIntentService gets killed at a later time unknowingly and i get a log as GeofenceHelper : removeGeofences - which i havent done explicitly in my app . I want my fences live forever in the app until the user uninstalls my app.
For now am using JobScheduler API to schedule it every 5 secs to get the transition triggers. Can anyone at Google Please assist me with this.
Thanks in advance.