Search code examples
androidnotificationsalertandroid-pendingintentproximity

Impossible to remove proximity alert


The users have a switch to activate or deactivate proximity alerts.

When the user active this switch, the proximity alert will show in a notification way. With this notification on the action bar, if the user change the switch to "deactivate" mode, the notification disappears. It works ok.

But my problem is this:

I active the alerts, but it not shows anything in that moment because I'm not near of a POI. I've changed my mind and now, I don't want any alert, so I change the switch to "deactivate" mode (any notification has appeared on the action bar).

However, with the switch on the "deactivate" mode, the alert will appear on the action bar when I'm near of a POI, and I don't know why. I'm using the removeProximityAlert with the value of the pending intent for each POI.

To activate alerts:

public void activateAlerts() {

    Database db = new Database(getApplicationContext());
    Cursor cursor = db.getPois();

    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);


    while (cursor.moveToNext()) {

        ...
        Intent intent = new Intent(PROX_ALERT_INTENT);

        String idSubstring = id.substring(7);
        int lastDigitsOfID = Integer.parseInt(idSubstring);
        PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), lastDigitsOfID, intent, PendingIntent.FLAG_ONE_SHOT);

        try {
            locationManager.addProximityAlert(latitude, longitude, Utils.RADIOALERTS, -1, pi);
        } catch (Exception e) {
            Log.e(getClass().getSimpleName().toString(), e.toString());
        }
        notifications.add(new NotificationObject(cursor.getString(idIndex), lastDigitsOfID));
    }
    db.addNotifications(notifications);
}

To deactivate alerts:

public void deactivateAlerts() {

    Database db = new Database(getApplicationContext());
    Cursor cursor = db.getIdPendingIntents();

    int idPendingIntentIndex = cursor.getColumnIndex("id_pendingintent");
    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    while (cursor.moveToNext()) {
        Intent intent = new Intent(PROX_ALERT_INTENT); 
        PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
                cursor.getInt(idPendingIntentIndex), intent, 0);
        locationManager.removeProximityAlert(pendingIntent);
    }

    NotificationManager notificationManager =
            (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.cancelAll();
}

I've read this posts:

Post1

Post2

Post3


Solution

  • Your problem is the use of PendingIntent.FLAG_ONE_SHOT. This isn't well documented, but it should work if you remove that flag.

    When you create a PendingIntent with FLAG_ONE_SHOT, Android doesn't keep track of this PendingIntent (as it is only allowed to be used once). In my opinion this is an "optimization" which is actually an Android bug :-(

    When you call removeProximityAlert() and pass it the PendingIntent, the code in that method tries to cancel all proximity alerts that have a matching PendingIntent. Since Android doesn't keep track of PendingIntents created with FLAG_ONE_SHOT, the "matching" code never finds your proximity alert so it doesn't cancel it.