5

Goal: Notification appears everyday once, at 2 PM, if certain condition is met.

Example: For simplicity, let's consider that the condition, checked with Internet connection, is met everyday. If today is already after 2 PM, we we'll start notifications from tomorrow. For example, user starts app at 4 PM on Monday, and he gets notifications on Tuesday 2 PM, Wednesday 2 PM, Thursday 2 PM and so on.

Problem: At 2 PM there is a first notification, but then I get the same notification over and over again, at random times.

Problem seems to be only on Android >= 4.0. It works good on earlier Androids.

This is how I send notification:

public class NotifyService extends Service
{       
static final int NOTIFICATION_ID = 1;
// ...

@Override
public IBinder onBind(Intent intent)
{
    return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
    try
    {
        Symbol biggest = getBiggestMover();
        if (biggest != null)
        {
            String title = getString(R.string.app_name);
            String text = getNotificationText(biggest.symbol, biggest.change);
            sendNotification(title, text);
        }
    }
    catch (Exception e)
    {
        // If there is Internet problem we do nothing, don't want to disturb the user.
        e.printStackTrace();
    }

    return super.onStartCommand(intent, flags, startId);
}

/** @return Symbol which is the biggest mover today. If there is no big mover - null is returned.
 * @throws Exception If there is Internet problem. */
private Symbol getBiggestMover() throws Exception
{
    Symbol biggest = null;
    Symbol[] equities = Network.getTraded(SymbolType.EQUITY);
    for (Symbol equity : equities)
    {
        if (Utilities.isToday(equity.lastTraded) && isBigMove(equity.change) && isBigger(equity, biggest))
        {
            biggest = equity;
        }
    }
    return biggest;
}   

private void sendNotification(String title, String text)
{
    Notification notification = new Notification(R.drawable.ic_launcher, text, System.currentTimeMillis());
    notification.flags = Notification.FLAG_AUTO_CANCEL;

    Intent clickIntent = new Intent(this, MainActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, clickIntent, PendingIntent.FLAG_CANCEL_CURRENT);

    notification.setLatestEventInfo(this, title, text, pendingIntent);

    NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    manager.notify(NOTIFICATION_ID, notification);
}   
// ...  
}

sendNotification() is called at 2 PM, because of the AlarmManager:

public class ServiceStarter extends BroadcastReceiver
{

@Override
public void onReceive(Context context, Intent intent)
{
    setNotificationAlarm(context);
}

/** Set repeating notifications every 24 hours. */
public static void setNotificationAlarm(Context context)
{
    Intent intent = new Intent(context, NotifyService.class);
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);

    final int oneDay = 24 * 60 * 60 * 1000;
    alarmManager.setRepeating(AlarmManager.RTC, getTriggerTime(), oneDay, pendingIntent);
}

private static long getTriggerTime()
{
    GregorianCalendar calendar = new GregorianCalendar();
    calendar.set(GregorianCalendar.HOUR_OF_DAY, 14);
    calendar.set(GregorianCalendar.MINUTE, 0);
    calendar.set(GregorianCalendar.SECOND, 0);
    calendar.set(GregorianCalendar.MILLISECOND, 0);

    if (calendar.before(new GregorianCalendar()))
    {
        calendar.add(GregorianCalendar.DAY_OF_MONTH, 1);
    }

    return calendar.getTimeInMillis();
}

}

setNotificationAlarm() is called from 2 places. First, at the start of app. Second, from the code above, when the phone reboots (onReceive() receives BOOT_COMPLETED). I do that, because when the user turns the phone off, AlarmManager clears its alarms.

So all should work, because alarmManager.setRepeating() overrides previous alarm.

I have found that somebody had the same issue, but also no answer:
https://groups.google.com/forum/?fromgroups=#!topic/android-developers/t_tDU4PwR3g

Also here I found similar problem: http://comments.gmane.org/gmane.comp.handhelds.android.devel/171471

Some time ago I asked how to create such notifications, so this is related:
Everyday notifications at certain time

Community
  • 1
  • 1
Adam Stelmaszczyk
  • 19,665
  • 4
  • 70
  • 110
  • 1
    In `sendNotification`, replace `getApplication()` with `this`, replace `getBaseContext()` with `this`, and replace `Intent.FLAG_ACTIVITY_NEW_TASK` with something that belongs there, as `Intent` flags do not go in static methods on `PendingIntent`. Also, do not use `RTC_WAKEUP` with a `getService()` `PendingIntent`, as that is unreliable -- use [my `WakefulIntentService`](https://github.com/commonsguy/cwac-wakeful) or something else that works off of a `getBroadcast()` `PendingIntent`. – CommonsWare Oct 12 '12 at 20:05
  • 1
    Beyond that, use `adb shell dumpsys alarm` to examine your scheduled alarms, use breakpoints to see what is triggering your `sendNotification()` method, etc. – CommonsWare Oct 12 '12 at 20:06
  • 1
    Thank you very much @CommonsWare, I followed your advises. However, the problem still occurs on mobiles with Android 4. Is it possible that there is some bug in their API implementation? Because I have read that in Android 4 they introduced "rich notifications", so they've changed code a little. – Adam Stelmaszczyk Oct 23 '12 at 19:07
  • 1
    Is it possible? Sure. Is it likely? No. Have you provided evidence of it? No. Create and publish a *complete* project that demonstrates the problem, including full instructions of how to use the project to demonstrate the problem. Also, please bear in mind that "rich notifications" were added in 4.1, and you are claiming that your problem occurs on 4.0. – CommonsWare Oct 23 '12 at 19:13
  • I have a similar problem with my app Follow Now (https://play.google.com/store/search?q=follow+now&c=apps). Like you, I have this problem only with Android >= 4 - After the first notification, the others don't make the vibration and sound. But the notification pops up and just left. – Felipe Nov 02 '12 at 02:13

2 Answers2

1

Use AlarmManager.RTC_WAKEUP insted of AlarmManager.RTC

In AlarmManager.RTC

Alarm time in System.currentTimeMillis() (wall clock time in UTC). This alarm does not wake the device up; if it goes off while the device is asleep, it will not be delivered until the next time the device wakes up.

where as in AlarmManager.RTC_WAKEUP

Alarm time in System.currentTimeMillis() (wall clock time in UTC), which will wake up the device when it goes off.

Arvind Kanjariya
  • 2,089
  • 1
  • 18
  • 23
  • This is wrong, according to the first comment to my post which was made by @CommonsWare. "Also, do not use RTC_WAKEUP with a getService() PendingIntent, as that is unreliable." – Adam Stelmaszczyk Oct 30 '12 at 16:46
1

Had the same problem on ICS+ device. My workaround was very simple-> Put the current time in the shared preferences when the notification is shown. Before that always check if the interval is really passed, and if not just abort.

            long lastnotification = sharedPrefs.getLong("lnnd", -1);
            Calendar now = Calendar.getInstance();
            if (!namedayalarmEnabled) {
                    return;
            }
            if (lastnotification > 1) {
                    Calendar last = Calendar.getInstance();
                    last.setTimeInMillis(lastnotification);
                    long distance = (now.getTimeInMillis() - last
                                    .getTimeInMillis());
                    if (distance < YOURINTERVAL) {
                            return;
                    } else {
                            SharedPreferences.Editor editor = sharedPrefs.edit();
                            editor.putLong("lnnd", now.getTimeInMillis());
                            editor.commit();
                    }
            }
stoilkov
  • 1,686
  • 1
  • 11
  • 18