Search code examples
androidnotificationsbroadcastreceiveralarmmanager

AlarmManager not triggering broadcast receiver


I'm trying to use the Alarm Manager to sechedule a notification, to be displayed to the user in the near future.

My code looks like

Custom notification manager, to trigger the alarm and cancel it if the notification is somehow "unselected" by the user :

import org.joda.time.Duration;
import org.joda.time.LocalDateTime;

import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

/**
 * Singleton Class dealing with the delivery and removal of alarm services to
 * schedule notifications.
 */
public class MyNotificationManager {

    /** unique instance. */
    private static MyNotificationManager instance;

    /** notification id. */
    private int notificationId;

    /**
     * Constructor.
     */
    private MyNotificationManager() {
        // hidden constructor for singleton
        notificationId = 0;
    }

    /**
     * Initializes the instance.
     */
    public static void initInstance() {
        if (instance == null) {
            // Create the instance
            instance = new MyNotificationManager();
        }
    }

    /**
     * @return the unique instance of this class.
     */
    public static MyNotificationManager getInstance() {
        // Return the instance
        return instance;
    }

    /**
     * Schedules a notification
     * 
     * @param context
     *            the context asking for a notification to be scheduled
     * @param notification
     *            the notification to be scheduled
     * @param when
     *            the {@link LocalDateTime} to schedule
     * @return the pending intent scheduled (this allows to cancel it if needed)
     */
    public PendingIntent scheduleNotification(final Context context, final Notification notification, final LocalDateTime when) {
        Intent notificationIntent = new Intent(context, NotificationPublisher.class);
        notificationIntent.putExtra(NotificationPublisher.NOTIFICATION_ID, getNextId());
        notificationIntent.putExtra(NotificationPublisher.NOTIFICATION, notification);
        // Every scheduled intent needs a different ID, else it is just executed
        // once
        long currentTimeMillis = System.currentTimeMillis();

        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, (int) currentTimeMillis, notificationIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        long futureInMillis = new Duration(null, when.toDateTime()).getMillis();
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Log.d(getClass().getSimpleName(), "Scheduling notification at " + futureInMillis + " millis in the future");
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, currentTimeMillis + futureInMillis, pendingIntent);
        return pendingIntent;
    }

    /**
     * Cancels the given pending intent if found.
     * 
     * @param context
     *            the context asking for this cancellation
     * @param pendingIntent
     *            the pending intent to cancel
     */
    public void removePendingNotification(final Context context, final PendingIntent pendingIntent) {
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(pendingIntent);
    }

    /**
     * @return the next free id.
     */
    private int getNextId() {
        return notificationId++;
    }

}

My Broadcast receiver :

import android.app.Notification;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class NotificationPublisher extends BroadcastReceiver {

    public static String NOTIFICATION_ID = "notification-id";
    public static String NOTIFICATION = "notification";

    @Override
    public void onReceive(Context context, Intent intent) {
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        Notification notification = intent.getParcelableExtra(NOTIFICATION);
        int id = intent.getIntExtra(NOTIFICATION_ID, 0);
        Log.d(this.getClass().getSimpleName(), "on Receive for notification ID " + id);
        notificationManager.notify(id, notification);
    }
}

AndroidManifest.xml was updated to have the broadcast receiver registered

<receiver android:name=".NotificationPublisher" android:exported="false"  />

The scheduleNotification is correctly called, with a notification created by the following method :

/**
 * Builds a notification about the departure time
 * 
 * @param departure
 *            the departure time
 * @param physicalStop
 *            the physical stop
 * @return a notification
 */
private Notification getNotification(final JsonDeparture departure, final JsonPhysicalStop physicalStop) {
    final NotificationCompat.Builder builder = new Builder(context);
    final String title = context.getResources().getString(R.string.notificationTitle);
    final String contentText = String.format(context.getResources().getString(R.string.notificationContent), physicalStop.getName(), departure
            .getLine().getShortName(), fmt.print(departure.getDateTime()));
    builder.setSmallIcon(R.drawable.ic_launcher).setContentTitle(title).setContentText(contentText);
    return builder.build();
}

Inside the schedule notification method, I configured the alarm manager to use RTC_WAKUPE type times, and I give it something like currentTime + some delay (computed using Joda Time Duration class)

When all this code is called with a proper notification time in the near future (i.e. LocalDateTime when = now + 5 minutes), the broadcast receiver is never called by the alarm manager


Solution

  • well, the problem was in the androidmanifest

    <receiver android:name=".NotificationPublisher" android:exported="false"  />
    

    is not working

    I have to set the full package name of the receiver

    <receiver android:name="com.xxx.xxx.NotificationPublisher" android:exported="false"  />