5

I am using an intent service to create a notification when user enters in the defined geofenced area.The problem is that when I first run the application it works fine and I am getting the pending-intent on my Intent Service, but after some days(2-3), I am not getting the required intent on the Intent Service.

I have no clue why it stopped working after some days. If I launch the application, it will start normally again but then stopped again after some days.

Here is my activity code --

public class MainActivity extends AppCompatActivity implements View.OnClickListener, GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks, ResultCallback, OnRequestPermissionsResultCallback {

GoogleApiClient mGoogleApiClient;
Location mGeoLocation;
Geofence mGeofence;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.bind(this);

    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();


    if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION}, 100);

    }
}


@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    mGeoLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
    mGoogleApiClient.connect();
}

@Override
protected void onStart() {
    super.onStart();
}


@Override
protected void onStop() {
    mGoogleApiClient.disconnect();
    super.onStop();
}

@Override
public void onClick(View v) {
}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
   Toast.makeText(MainActivity.this,"",Toast.LENGTH_SHORT);
    Log.e("Here I am","Using geofencing in my mobile on 'onConnectionFailed'  of main activity");
}

@Override
public void onConnected(@Nullable Bundle bundle) {
    if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        return;
    }

    if (mGeoLocation != null) {
        mGeofence = new Geofence.Builder()
                .setRequestId("Appstudioz")
                .setCircularRegion(mGeoLocation.getLatitude(), mGeoLocation.getLongitude(), 100)
                .setExpirationDuration(Geofence.NEVER_EXPIRE)
                .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
                .build();
        mGoogleApiClient.connect();
        Intent intent = new Intent(this, MyIntentServiceGeoFencing.class);
        PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
        builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
        builder.addGeofence(mGeofence);
        LocationServices.GeofencingApi.addGeofences(mGoogleApiClient, builder.build(), pendingIntent).setResultCallback(this);


    }
}
@Override
public void onConnectionSuspended(int i) {
    Log.e("Here I am","Using geofencing in my mobile 'onConnectionSuspended' of main activity");
}

@Override
public void onResult(@NonNull Result result) {
    Log.e("Here I am","Using geofencing in my mobile 'onResult' of main activity");
}
}

And this is my Intent Service --

public class MyIntentServiceGeoFencing extends IntentService {
public MyIntentServiceGeoFencing() {
    super("MyIntentServiceGeoFencing");
}
@Override
protected void onHandleIntent(Intent intent) {
    if (intent != null) {
        String message="";
        Log.e("Here I am","Using geofencing in my mobile 'In intent Service'");
        GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
        if(geofencingEvent.getGeofenceTransition()== Geofence.GEOFENCE_TRANSITION_ENTER)
        {
            message="Entering Appstudioz";
        }
        else if(geofencingEvent.getGeofenceTransition()== Geofence.GEOFENCE_TRANSITION_EXIT)
        {
            message="Exiting Appstudioz";
        }
        NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(this)
                        .setSmallIcon(R.drawable.cast_ic_notification_small_icon)
                        .setContentTitle("Geofence Notification")
                        .setContentText(message);

// Sets an ID for the notification
        int mNotificationId = 001;
// Gets an instance of the NotificationManager service
        NotificationManager mNotifyMgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// Builds the notification and issues it.
        mNotifyMgr.notify(mNotificationId, mBuilder.build());
        if(message.equals("Entering Appstudioz")) {
            ((AudioManager) getSystemService(AUDIO_SERVICE)).setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
        }
        else
        {
            ((AudioManager) getSystemService(AUDIO_SERVICE)).setRingerMode(AudioManager.RINGER_MODE_NORMAL);
        }

    }
}
}
Akash Bisariya
  • 3,855
  • 2
  • 30
  • 42

2 Answers2

5

I have found my solution. Following are the reasons why the App was not getting Pending Intents according to the official google documentation -

1.The device is rebooted.
2.The app is uninstalled and re-installed.
3.The app's data is cleared.
4.Google Play services data is cleared.
5.The app has received a GEOFENCE_NOT_AVAILABLE alert.(When Android Location Provider(GPS) gets switched off)

You have to re-register the geofence after these events.

In my case device rebooting and location provider(GPS) getting switched off, were the reasons for not getting the pending intents.

Akash Bisariya
  • 3,855
  • 2
  • 30
  • 42
0

Service will stop running when you kill your application, So, you can use broadcast receiver to fix this problem

public class GeofenceReceiver extends BroadcastReceiver
implements
    GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener,
    ResultCallback<Status>{

GoogleApiClient mGoogleApiClient;
PendingIntent mGeofencePendingIntent ;
Context mContext;

@Override
public void onReceive(Context context, Intent intent) {
    mContext = context;
    mGoogleApiClient = new GoogleApiClient.Builder(mContext)
            .addOnConnectionFailedListener(this)
            .addConnectionCallbacks(this)
            .addApi(LocationServices.API)
            .build();

    mGoogleApiClient.connect();
}



@Override
public void onConnected(@Nullable Bundle bundle) {
    try {
        LocationServices.GeofencingApi.addGeofences(
                mGoogleApiClient,
                // The GeofenceRequest object.
                getGeofencingRequest(),
                getGeofencePendingIntent()
        ).setResultCallback(this); // Result processed in onResult().
    } catch (SecurityException securityException) {
        Log.i(getClass().getSimpleName(),securityException.getMessage());
    }
}

// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

}

/**
 * Runs when the result of calling addGeofences() and removeGeofences() becomes available.
 * Either method can complete successfully or with an error.
 *
 * Since this activity implements the {@link ResultCallback} interface, we are required to
 * define this method.
 *
 * @param status The Status returned through a PendingIntent when addGeofences() or
 *               removeGeofences() get called.
 */
@Override
public void onResult(@NonNull Status status) {
    if (status.isSuccess()) {
        Log.i(getClass().getSimpleName(),"Success");
    } else {
        // Get the status code for the error and log it using a user-friendly message.
        Log.i(getClass().getSimpleName(),getErrorString(status.getStatusCode()));
    }
}

private GeofencingRequest getGeofencingRequest() {
    GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
    builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER | GeofencingRequest.INITIAL_TRIGGER_DWELL);
    builder.addGeofences(getGeofecne());
    return builder.build();
}

private List<Geofence> getGeofecne(){
    List<Geofence> mGeofenceList = new ArrayList<>();

    //add one object
    mGeofenceList.add(new Geofence.Builder()
            // Set the request ID of the geofence. This is a string to identify this
            // geofence.
            .setRequestId("key")

            // Set the circular region of this geofence.
            .setCircularRegion(
                    25.768466, //lat
                    47.567625, //long
                    50) // radios

            // Set the expiration duration of the geofence. This geofence gets automatically
            // removed after this period of time.
            //1000 millis  * 60 sec * 5 min
            .setExpirationDuration(1000 * 60 * 5)

            // Set the transition types of interest. Alerts are only generated for these
            // transition. We track entry and exit transitions in this sample.
            .setTransitionTypes(
                    Geofence.GEOFENCE_TRANSITION_DWELL)
            //it's must to set time in millis with dwell transition
            .setLoiteringDelay(3000)
            // Create the geofence.
            .build());

    return mGeofenceList;

}

private PendingIntent getGeofencePendingIntent() {
    // Reuse the PendingIntent if we already have it.
    if (mGeofencePendingIntent != null) {
        return mGeofencePendingIntent;
    }
    Intent intent = new Intent(mContext, GeofenceTransitionsIntentService.class);
    return PendingIntent.getService(mContext, 0, intent, PendingIntent.
            FLAG_UPDATE_CURRENT);
}

}

and here your notification service

public class GeofenceTransitionsIntentService extends IntentService {
protected static final String TAG = "GeofenceTransitionsIS";

/**
 * This constructor is required, and calls the super IntentService(String)
 * constructor with the name for a worker thread.
 */
public GeofenceTransitionsIntentService() {
    // Use the TAG to name the worker thread.
    super(TAG);
}

/**
 * Handles incoming intents.
 * @param intent sent by Location Services. This Intent is provided to Location
 *               Services (inside a PendingIntent) when addGeofences() is called.
 */
@Override
protected void onHandleIntent(Intent intent) {
    GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
    if (geofencingEvent.hasError()) {
        Log.e(TAG, getErrorString(geofencingEvent.getErrorCode()));
        return;
    }

    // Get the transition type.
    int geofenceTransition = geofencingEvent.getGeofenceTransition();

    // Test that the reported transition was of interest.
    if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
            geofenceTransition == Geofence.GEOFENCE_TRANSITION_DWELL) {

        // Get the transition details as a String.
        String geofenceTransitionDetails = "Discount 10% for you";

        // Send notification and log the transition details.
        sendNotification(geofenceTransitionDetails);
        Log.i(TAG, geofenceTransitionDetails);
    } else {
        // Log the error.
        Log.e(TAG, getString(R.string.geofence_transition_invalid_type + geofenceTransition));
    }
}

public static String getErrorString(int errorCode) {
    switch (errorCode) {
        case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
            return "not Available";
        case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
            return "Too many Geofences";
        case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
            return "Too many Pending Intents";
        default:
            return "unknown geofence error";
    }
}


/**
 * Posts a notification in the notification bar when a transition is detected.
 * If the user clicks the notification, control goes to the MainActivity.
 */
private void sendNotification(String notificationDetails) {
    // Create an explicit content Intent that starts the main Activity.
    Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);

    // Construct a task stack.
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);

    // Add the main Activity to the task stack as the parent.
    stackBuilder.addParentStack(MainActivity.class);

    // Push the content Intent onto the stack.
    stackBuilder.addNextIntent(notificationIntent);

    // Get a PendingIntent containing the entire back stack.
    PendingIntent notificationPendingIntent =
            stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

    // Get a notification builder that's compatible with platform versions >= 4
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this);

    // Define the notification settings.
    builder.setSmallIcon(R.drawable.common_google_signin_btn_icon_dark_normal)
            // In a real app, you may want to use a library like Volley
            // to decode the Bitmap.
            .setLargeIcon(BitmapFactory.decodeResource(getResources(),
                    R.drawable.cast_abc_scrubber_primary_mtrl_alpha))
            .setColor(Color.RED)
            .setContentTitle(notificationDetails)
            .setContentText(getString(R.string.geofence_transition_notification_text))
            .setContentIntent(notificationPendingIntent);

    // Dismiss notification once the user touches it.
    builder.setAutoCancel(true);

    // Get an instance of the Notification manager
    NotificationManager mNotificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    // Issue the notification
    mNotificationManager.notify(0, builder.build());
}

}

for more information check out my repo there is full example

https://github.com/3zcs/Geofence

3zcs
  • 35
  • 4
  • 18
  • It may be a good solution but then how am I receiving the pending intent for 3 days even after killing my application. – Akash Bisariya Apr 05 '17 at 05:11
  • each time the user enable GPS, and Network make your geofence, as you use broadcast receiver, you don't need your app be in the foreground, It will work in background, and that's all. – 3zcs Apr 05 '17 at 05:25
  • I received pending intent using "Intent service" for 3 days after killing application.But it has unusual behaviour it had stopped receiving intent after some time. – Akash Bisariya Apr 05 '17 at 05:33