0

I have done some research and tried to implement a one time alarm that sends a notification to the user, but for some reason I cannot understand, when the time comes, the alarm is not being activated. I think the onReceive method is not being called, but I don't know why, since it's the first time I try to implement an alarm.

=== Edit: it seems that the alarm's onReceive is working after all, I got the toast message "Alarm!!" at the right time (don't know why it didn't the first time I tested), but no notification was received, though... Any clues?

This is the code for the Alarm class:

public class Alarm extends BroadcastReceiver {

    public static final String PREFS_FILE_NAME = MainActivity.PREFS_FILE_NAME;

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub
        // send notification

        Toast.makeText(context, "Alarm!!", Toast.LENGTH_SHORT).show();

        // API < 16 so have to use compat
        NotificationCompat.Builder mBuilder =
            new NotificationCompat.Builder(context)
            .setContentTitle(context.getResources().getString(R.string.memo_test_ready))
            .setContentText(context.getResources().getString(R.string.click_to_start));

        Intent resultIntent = new Intent(context, UpcomingTest.class);

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
        stackBuilder.addParentStack(UpcomingTest.class);
        stackBuilder.addNextIntent(resultIntent);
        PendingIntent resultPendingIntent =
                stackBuilder.getPendingIntent(
                    0,
                    PendingIntent.FLAG_UPDATE_CURRENT
                );
        mBuilder.setContentIntent(resultPendingIntent);
        NotificationManager mNotificationManager =
            (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.notify(123, mBuilder.build());

    }

    public void Set(Context context)
    {
        DatabaseHandler db = new DatabaseHandler(context);
        MemoryTestLevel memoTestLevel = new MemoryTestLevel();
        long timeInterval;
        long memoryTest_dateTime;

        String alarmMemoLevel;
        List<Phrase> studyPhrasesList = db.getPhrasesWithState(Phrase.START_STUDYING);
        if (studyPhrasesList.size() > 0 ){ // if there are any phrases here, update them; dateTime == level 1
            alarmMemoLevel = "Level 1 ";
            memoTestLevel = db.getMemoryTestLevelWithLevel(MemoryTestLevel.LEVEL_1);
            timeInterval = memoTestLevel.getTimeInterval();
            TestDateTimeCalculator datetimeCalc = new TestDateTimeCalculator();
            memoryTest_dateTime = datetimeCalc.calculate(timeInterval);
            for(Phrase phrase : studyPhrasesList){  
                phrase.setMemoryTestPending(memoTestLevel.getMemoryTest_id(), memoryTest_dateTime);
                db.updatePhrase(phrase);
            }
        } else {
            // if there are no phrases to be set at level 1, then get the lowest memoTest_datime of
            // the ones that are pending
            alarmMemoLevel = "next after L1 ";
            memoryTest_dateTime = db.getLowestMemoTestDateTime();
        }
        /* 2. Set new Alarm
         * 2.1. Determine which phrases will go into this new alarm */
        List<Phrase> nextMemoryTestPhrases = db.getNextMemoryTestPhrases(memoryTest_dateTime);

        for(Phrase phrase : nextMemoryTestPhrases) {
            phrase.setState(Phrase.MEMORY_TEST_SCHEDULED);
            db.updatePhrase(phrase);
        }
        // 2.3 set alarm for required dateTime
        AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(context, Alarm.class);
        PendingIntent pendingInt = PendingIntent.getBroadcast(context, 0, intent, 0);
        alarmMgr.set(AlarmManager.RTC_WAKEUP, memoryTest_dateTime, pendingInt);

        // 2.4 save the alarm.dateTime in the preferences so it can be used in the "upcoming test" activity

        SharedPreferences preferences = context.getSharedPreferences(PREFS_FILE_NAME, Context.MODE_PRIVATE);
        Editor editor = preferences.edit();
        editor.putLong("NEXT_TEST_DATETIME", memoryTest_dateTime);
        SimpleDateFormat sdf = new SimpleDateFormat("EEE, MMM d, yyyy hh:mm");
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(memoryTest_dateTime);
        String nextTestDateStr = sdf.format(calendar.getTime());
        Toast.makeText(context, "Alarm set to " + alarmMemoLevel + nextTestDateStr, Toast.LENGTH_LONG).show();
        editor.commit();

    }

    public void Cancel(Context context)
    {
        Intent intent = new Intent(context, MyBroadcastReceiver.class);
        PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(sender);
    }
}

And I have a broadcast receiver in case the phone is rebooted:

public class MyBroadcastReceiver extends BroadcastReceiver {

public static final String PREFS_FILE_NAME = MainActivity.PREFS_FILE_NAME;

@Override
public void onReceive(Context context, Intent intent) {
    // TODO setup alarm again (get datetime from system)
    Alarm alarm = new Alarm();
    if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED"))
    {
        SharedPreferences preferences = context.getSharedPreferences(PREFS_FILE_NAME, Context.MODE_PRIVATE);
        long nextTestDateInMillis = preferences.getLong("NEXT_TEST_DATETIME", 0);
            if(nextTestDateInMillis > 0){
            alarm.Set(context);
        }
    }

}

}

From the research I found, it seems that something is missing/wrong in my manifest. This is what I have there:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>

The below is inside application:

<receiver android:name="liliana.phrasememo.util.MyBroadcastReceiver">  
    <intent-filter>  
        <action android:name="android.intent.action.BOOT_COMPLETED" />  
    </intent-filter>  
</receiver>
<receiver android:process=":remote" android:name="liliana.phrasememo.util.Alarm"/>

Also, if you see anything else that's wrong in my implementation of Alarm + Notification it would be brilliant to give me the heads up. Thank you very much :-)

PrincessLilly
  • 415
  • 1
  • 8
  • 21

2 Answers2

0

to set alarm may be this code helps you

   Intent myIntent = new Intent(yourcontext, Alarm.class);
   PendingIntent pendingIntent = PendingIntent.getService(act, 0, myIntent, 0);
   AlarmManager alarmManager = (AlarmManager)act.getSystemService(act.ALARM_SERVICE);
   Calendar calendar = Calendar.getInstance();
   calendar.set(Calendar.HOUR_OF_DAY, 8);
   calendar.set(Calendar.MINUTE,22);
   calendar.set(Calendar.SECOND, 0);


   alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);

also you must implement service instead of broadcastreciever to run at alarm time

Alireza
  • 105
  • 8
  • Your code seems to suggest that I set the alarm time in a different way. I know this is not necessary because the time I am retrieving from my database is correctly reflected when I convert it to a String and also because it is giving me the right behaviour in other parts of the app when I have to compare times, etc. Also, please see my last update: I got the alarm "toast" message up finally, but the notification didn't show... If you have any idea it's much appreciated. Thanks – PrincessLilly May 05 '14 at 11:39
  • can u tell this line is excuted or not ? Toast.makeText(context, "Alarm!!", Toast.LENGTH_SHORT).show(); – Alireza May 05 '14 at 11:47
  • Yes it is; it's what I was trying to say in my previous comment :-) – PrincessLilly May 05 '14 at 12:17
  • Is there anything else I need to add to my manifest regarding the notification prompt? – PrincessLilly May 05 '14 at 12:23
  • I found the issue. You can see my answer above. Thanks anyway for taking the time. – PrincessLilly May 05 '14 at 12:48
0

Thanks very much to answer posted here, what is missing in my code is the notification icon, which I have added like this:

NotificationCompat.Builder mBuilder =
        new NotificationCompat.Builder(context)
        .setSmallIcon(R.drawable.ic_launcher) // this was missing
        .setContentTitle(context.getResources().getString(R.string.memo_test_ready))
        .setContentText(context.getResources().getString(R.string.click_to_start));

And in fact, if we look at the documentation, it does specify that the small icon must be in the notification:

Required notification contents

A Notification object must contain the following:

A small icon, set by setSmallIcon()
A title, set by setContentTitle()
Detail text, set by setContentText()

The LogCat does have a file not found error:

05-05 12:39:39.191: A/NetworkStats(89): Caused by: java.io.FileNotFoundException: /proc/net/xt_qtaguid/stats: open failed: ENOENT (No such file or directory)

But it doesn't cause any crashes so you might not realise it. I'm not sure anything could be added to the notification constructor itself that would allow the user to see right away that something is missing. I don't have very advanced Java knowledge.

Community
  • 1
  • 1
PrincessLilly
  • 415
  • 1
  • 8
  • 21