0

I have a IntentService for Geofences, that I would simply just start. but it has to run in the background, so in Android 8 it sometimes gets whitelisted. So I hard I need to use the JobIntentService: https://developer.android.com/reference/android/support/v4/app/JobIntentService Also looked at this: Android 8.0: java.lang.IllegalStateException: Not allowed to start service Intent

This was my onHandleIntent() where I would get my Geofence calls:

  //HANDLING INTENTS
protected void onHandleIntent(Intent intent) {
    GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
    if (geofencingEvent != null) {
        int transitionType = geofencingEvent.getGeofenceTransition();
        if (transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
            Location triggering = geofencingEvent.getTriggeringLocation();
            if (triggering != null) {
                Utils.appendLog("GEOFENCE onHandleIntent got an EXIT transition: " + triggering.getLatitude() + ", " + triggering.getLongitude() + " / accuracy: " + triggering.getAccuracy(), "D", "#updategeo " + Constants.GEOFENCE);
            } else
                Utils.appendLog("GEOFENCE onHandleIntent got an EXIT transition null", "D", "#updategeo " + Constants.GEOFENCE);
            Utils.appendLog("removing geofence after exit", "I", Constants.TRACKER + "#updategeo");
            removeGeofencesAndStartTracking();
        }
    }
}

This was my code for my Intent service, Add geofence logic:

  //ADDING/REMOVING GEOFENCES
public void addGeofence(final Context context, final Location location, float radius) {
    if (!isSettingGeofence) {
        isSettingGeofence = true;
        ArrayList geofences = new ArrayList<>();
        geofences.add(new Geofence.Builder()
                .setRequestId(geofenceRequestID)
                .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_EXIT)
                .setCircularRegion(
                        location.getLatitude(), location.getLongitude(), radius)
                .setExpirationDuration(Geofence.NEVER_EXPIRE)
                .build());

        if (geofences.size() > 0) {
            if (mGeofencingClient == null)
                mGeofencingClient = LocationServices.getGeofencingClient(this);

            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                Utils.appendLog("Geofence Transitions Service addGeofence checkSelfPermission ERROR", "E", Constants.GEOFENCE);
                return;
            }

            Utils.appendLog("addGeofences is being called, wait for success or failure callbacks", "I", Constants.TRACKER + "#updategeo");
            mGeofencingClient.addGeofences(getGeofencingRequest(location, geofences), getGeofencePendingIntent(context)).addOnSuccessListener(new OnSuccessListener<Void>() {
                @Override
                public void onSuccess(Void aVoid) {
                    PSLocationService.getInstance(context).lastTimeDidExitRegion = null;
                    isSettingGeofence = false;
                    final RealmLocation realmLocation = new RealmLocation(location.getLatitude(), location.getLongitude(), location.getTime(), null, true);
                    Log.i("#geofenceRequestID", "addGeofence geofence realm location: " + realmLocation.getLocation());
                    final GeofenceRealmLocation geofenceRealmLocation = new GeofenceRealmLocation(geofenceRequestID, realmLocation);
                    Log.i("#geofenceRequestID", "addGeofence geofence geofence location: " + geofenceRealmLocation.getRealmLocation().getLocation());
                    realmLocation.setAccuracy(location.getAccuracy());
                    realmLocation.setSpeed(location.getSpeed());
                    Log.i("", "GLOBAL intances  before addGeofences:" + Realm.getGlobalInstanceCount(PSApplicationClass.Config));
                    Realm realm = Realm.getInstance(PSApplicationClass.Config);
                    realm.executeTransaction(new Realm.Transaction() {
                        @Override
                        public void execute(Realm realm) {
                            realm.copyToRealmOrUpdate(geofenceRealmLocation);
                        }
                    });
                    realm.close();
                    try {
                        final NotificationManager notifManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
                        notifManager.cancel(1010);
                    } catch (Exception e) {
                        Utils.appendLog("Error removing notification: " + e.getMessage(), "I", Constants.GEOFENCE);
                    }

                    Log.i("", "GEOFENCETEST addGeofences SUCCESSS");
                    Utils.appendLog("Geofence Transitions Service setGeofenceRequest Success adding geofences!" +
                                    location.getLatitude() +
                                    " , " + location.getLongitude() + " / accuracy: " + location.getAccuracy(),
                            "I",
                            "#updategeo " + Constants.GEOFENCE);
                }
            }).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    Log.i("", "GEOFENCETEST addGeofences FAILURE: " + e.getMessage());
                    isSettingGeofence = false;
                    try {
                        LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
                        boolean networkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
                        if (!networkEnabled) {
                            new Handler(Looper.getMainLooper()).post(new Runnable() {
                                @Override
                                public void run() {
                                    MyFirebaseMessagingService.generateNotificationStandard(context, null, context.getString(R.string.Error) + ": " + context.getString(R.string.geofence_error), null, null, false, false, MyFirebaseMessagingService.NETWORK_ERROR_NOTIFICATION);
                                }
                            });
                        }
                    } catch (Exception ex) {
                        Log.e("", "");
                        // catch Exception
                    }
                    Utils.appendLog("Geofence Transitions Service setGeofenceRequest FAILURE adding geofences!" +
                                    e.getMessage(),
                            "E",
                            "#updategeo " + Constants.GEOFENCE);
                }
            });
        } else {
            Utils.appendLog("Geofence Transitions Service geofences size Error: " + geofences.size(), "E", Constants.GEOFENCE);
        }
    } else
        Utils.appendLog("Geofence Transitions Service setGeofenceRequest is already setting a geofence", "I", Constants.GEOFENCE);
}

Now I changed to a JobIntentService.

I run the service like this:

   Intent bindIntent = new Intent(context, PSGeofenceTransitionsIntentService.class);
        enqueueWork(context, bindIntent);

  public static final int JOB_ID = 1;

public static void enqueueWork(Context context, Intent work) {
    enqueueWork(context, PSGeofenceTransitionsIntentService.class, JOB_ID, work);
}

I also added this to my Android Manifest:

  <service android:name=".core.tracking.PSGeofenceTransitionsIntentService"
        android:permission="android.permission.BIND_JOB_SERVICE"/>

And I handle the content of onHandleIntent in the NEW onHandleWork

  @Override
protected void onHandleWork(@NonNull Intent intent) {
    GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
    if (geofencingEvent != null) {
        int transitionType = geofencingEvent.getGeofenceTransition();
        if (transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
            Location triggering = geofencingEvent.getTriggeringLocation();
            if (triggering != null) {
                Utils.appendLog("GEOFENCE onHandleIntent got an EXIT transition: " + triggering.getLatitude() + ", " + triggering.getLongitude() + " / accuracy: " + triggering.getAccuracy(), "D", "#updategeo " + Constants.GEOFENCE);
            } else
                Utils.appendLog("GEOFENCE onHandleIntent got an EXIT transition null", "D", "#updategeo " + Constants.GEOFENCE);
            Utils.appendLog("removing geofence after exit", "I", Constants.TRACKER + "#updategeo");
            removeGeofencesAndStartTracking();
        }
    }
}

Now I get events onHandleWork, from the Geofence, but only with transition Type = -1. So I do not get ENTER or EXIT events. Why, or how can I fix this Geofence Service?

RobertoAllende
  • 8,744
  • 4
  • 30
  • 49
rosu alin
  • 5,674
  • 11
  • 69
  • 150

2 Answers2

1

Had the same issue. Since Android 8 background work is more limited. There is a new way of calling PendingIntent. You do not need to change it to JobIntentService. Check out newest Android guidelines for implementing Geofence listener:

https://developer.android.com/training/location/geofencing

In short, you just need to use GeofencingClient for calling PendingIntent.

private PendingIntent getGeofencePendingIntent() {
    // Reuse the PendingIntent if we already have it.
    if (mGeofencePendingIntent != null) {
        return mGeofencePendingIntent;
    }
    Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
    // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
    // calling addGeofences() and removeGeofences().
    mGeofencePendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.
            FLAG_UPDATE_CURRENT);
    return mGeofencePendingIntent;
}

Use link provided above for full example.

  • Thanks, I think this works. I had this, but also would try to start my service from the getInstance of the singleton if it would not be working, so I'm assuming that caused the issue for me. I will come back with more data, after testing thoroughly – rosu alin Dec 18 '18 at 12:22
0

First, you need to set up a Broadcast Receiver where in your onReceive method, you enqueueWork for your JobIntentService. So, instead of starting your IntentService directly, you call the broadcast receiver in your PendingIntent.

mechdon
  • 517
  • 1
  • 10
  • 23