Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Usage of PendingIntent.cancel() and AlarmManager.cancel()

Tags:

android

How does PendingIntent.cancel() affect AlarmManager if there is a pending alarm.

Should I call cancel on both objects(intent and alarmmanager) to cancel an alarm? Can someone explain how they work together.

Thanks in advance.

like image 347
Sridhar Chidurala Avatar asked Sep 29 '22 02:09

Sridhar Chidurala


1 Answers

Registering PendingIntents

PendingIntent instance can be obtained via factory methods PendingIntent.getActivity(), PendingIntent.getService(), PendingIntent.getBroadcast().

However, apart from just obtaining PendingIntent instance, ActivityManager registers the PendingIntent in internal cache/meta data file if it does not exist. In contrary, if it does exist, then previously registered instance is returned.

For instance,

 public static PendingIntent getActivity(Context context, int requestCode,
        Intent intent, int flags) {
    String packageName = context.getPackageName();
    String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
            context.getContentResolver()) : null;
    try {
        intent.setAllowFds(false);
        IIntentSender target =
            ActivityManagerNative.getDefault().getIntentSender(
                IActivityManager.INTENT_SENDER_ACTIVITY, packageName,
                null, null, requestCode, new Intent[] { intent },
                resolvedType != null ? new String[] { resolvedType } : null, flags);
        return target != null ? new PendingIntent(target) : null;
    } catch (RemoteException e) {
    }
    return null;
}

As the documentation states:

/**
 * Retrieve a PendingIntent that will start a new activity, like calling
 * {@link Context#startActivity(Intent) Context.startActivity(Intent)}.
 * Note that the activity will be started outside of the context of an
 * existing activity, so you must use the {@link Intent#FLAG_ACTIVITY_NEW_TASK
 * Intent.FLAG_ACTIVITY_NEW_TASK} launch flag in the Intent. 
...
* @return Returns an existing or new PendingIntent matching the given
 * parameters.  May return null only if {@link #FLAG_NO_CREATE} has been
 * supplied.

Cancelling PendingIntent only

Here's how the cancellation looks like:

 /**
 * Cancel a currently active PendingIntent.  Only the original application
 * owning an PendingIntent can cancel it.
 */
public void cancel() {
    try {
        ActivityManagerNative.getDefault().cancelIntentSender(mTarget);
    } catch (RemoteException e) {
    }
}

The documentation states that the application can cancel the PendingIntent for you. Essentially, it means that ActivityManager attempts to match the PendingIntent and remove the meta data /cache entry on condition that the matching PendingIntent exists.

If you attempt to get the previously cancelled or unregistered PendingIntent with the flag FLAG_NO_CREATE applied, a null is returned then.

Cancelling PendingIntent via AlarmManager

Cancellation via AlarmManager differs obviously because it removes registered PendingIntent in IAlarmManager's cache/meta data files and from what I noticed diving deeper into Android source code there is no cancellation being done via ActivityManager when an alarm is removed.

public void cancel(PendingIntent operation) {
    try {
        mService.remove(operation); IAlarmManager instance
    } catch (RemoteException ex) {
    }
}

Conclusion

You must cancel your alarm via AlarmManager once you register it, cancelling PendingIntent itself and the AlarmManager's alarms cancellation process have nothing in common.

Hope, that I clarified your doubts.

like image 154
dawid gdanski Avatar answered Oct 05 '22 08:10

dawid gdanski