11

I have an alarm app using the AlarmManager class that allows user to set a one-time alarm, or a repeating alarm. I would like to expand the capabilities so that the user can exclude the alarm from going off, for example, on the weekend.

I have put the code to block the alarm on weekends into AlarmReceiver.java.

  1. I am not sure if AlarmReceiver.java is the correct place to put the code that blocks alarms on the weekend.
  2. I am not sure if the code I am using to block the alarm on weekends is correct. Basically I tell AlarmReceiver to do nothing if today is Saturday or Sunday. Else, fire off the alarm.

AlarmActivity.java code that sets the alarm:

  //Set a one time alarm
            if (repeatInterval == 0) {
                    alarmManager.set(AlarmManager.RTC, alarmTime.getTimeInMillis(), pendingIntent);
                    AlarmReceiver alarmReceiver = new AlarmReceiver(this); //http://stackoverflow.com/questions/16678763/the-method-getapplicationcontext-is-undefined

                    Toast.makeText(AlarmActivity.this, "Your one time reminder is now set for " + hourSet + ":" + minuteSetString + amPmlabel, Toast
                            .LENGTH_LONG)
                            .show();
            }

            //Set a repeating alarm
            else {
                alarmManager.setRepeating(AlarmManager.RTC, alarmTime.getTimeInMillis(), repeatIntervalMilliseconds, pendingIntent);
                AlarmReceiver alarmReceiver = new AlarmReceiver(this); //http://stackoverflow.com/questions/16678763/the-method-getapplicationcontext-is-undefined

                    Toast.makeText(AlarmActivity.this, "Your reminder is now set for " + hourSet + ":" + minuteSetString + amPmlabel + " and will " +
                            "repeat " +
                            "every " +
                            repeatInterval + " minutes.", Toast.LENGTH_LONG).show();
        }

AlarmService.Java:

package com.joshbgold.move.backend;

import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;

import com.joshbgold.move.R;
import com.joshbgold.move.main.AlarmActivity;

public class AlarmService extends IntentService {
    private NotificationManager alarmNotificationManager;

    public AlarmService() {
        super("AlarmService");
    }

    @Override
    public void onHandleIntent(Intent intent) {

            sendNotification("Move reminder");

    }

    private void sendNotification(String msg) {
        alarmNotificationManager = (NotificationManager) this
                .getSystemService(Context.NOTIFICATION_SERVICE);

        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                new Intent(this, AlarmActivity.class), 0);

        NotificationCompat.Builder alarmNotificationBuilder = new NotificationCompat.Builder(
                this).setContentTitle("Reminder").setSmallIcon(R.mipmap.ic_launcher)
                .setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
                .setContentText(msg);


        alarmNotificationBuilder.setContentIntent(contentIntent);
        alarmNotificationManager.notify(1, alarmNotificationBuilder.build());
    }

}

AlarmReceiver.Java:

package com.joshbgold.move.backend;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v4.content.WakefulBroadcastReceiver;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class AlarmReceiver extends WakefulBroadcastReceiver {

    Context myContext;
    public AlarmReceiver(Context context){
        myContext = context;
    }

    public AlarmReceiver(){

    }

    //get the current day
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEEE");
    Date date = new Date();
    String dayOfTheWeek = simpleDateFormat.format(date);

    Calendar calendar = Calendar.getInstance();
    int currentHour = calendar.HOUR_OF_DAY;

    boolean noWeekends = true;
    boolean workHoursOnly = true;

    @Override
    public void onReceive(final Context context, Intent intent) {


        try {  //this value could be null if user has not set it...
            noWeekends = loadPrefs("noWeekends", noWeekends);
            workHoursOnly = loadPrefs("workHoursOnly", workHoursOnly);
        } catch (Exception e) {
            e.printStackTrace();
        }


        if(dayOfTheWeek == "Saturday" || dayOfTheWeek == "Sunday"  && noWeekends == true) {
            //Alarm is not wanted on the weekend
            try {
                wait(1);  //waits for one-thousandth of a millisecond
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        else if ((currentHour < 9 || currentHour > 17)  && workHoursOnly == true){
            //Alarm outside of work hours
            try {
                wait(1);  //waits for one-thousandth of a millisecond
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        else {

            Intent myIntent = new Intent();
            myIntent.setClassName("com.joshbgold.move", "com.joshbgold.move.main.ReminderActivity");
            myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(myIntent);
        }
    }

    //get prefs
    private boolean loadPrefs(String key,boolean value) {
        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(myContext);
        boolean data = sharedPreferences.getBoolean(key, value);
        return data;
    }
}

AlarmReceiver.java (corrected code)

package com.joshbgold.move.backend;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v4.content.WakefulBroadcastReceiver;
import java.util.Calendar;

public class AlarmReceiver extends WakefulBroadcastReceiver {

    Context myContext;
    public AlarmReceiver(Context context){
        myContext = context;
    }

    public AlarmReceiver() {

    }

    private boolean workHoursOnly = false;
    private boolean noWeekends = false;

    @Override
    public void onReceive(final Context context, Intent intent) {

        Calendar calendar = Calendar.getInstance();
        int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
        int today = calendar.get(Calendar.DAY_OF_WEEK);
        boolean isWeekend = (today == Calendar.SUNDAY) || (today == Calendar.SATURDAY);
        boolean isOutsideWorkHours = (currentHour < 9) || (currentHour > 16);

        //checkPrefs checks whether a preferences key exists
        if (checkPrefs("workHoursOnlyKey")){
            workHoursOnly = loadPrefs("workHoursOnlyKey", workHoursOnly);
        }

        if(checkPrefs("noWeekendsKey")){
            noWeekends = loadPrefs("noWeekendsKey", noWeekends);
        }

        /* try {  //this value could be null if user has not set it...
            workHoursOnly = loadPrefs("workHoursOnly", workHoursOnly);
        } catch (Exception e) {
            e.printStackTrace();
        }
       */

        /*try {  //this value could be null if user has not set it...
        noWeekends = loadPrefs("noWeekends", noWeekends);
        } catch (Exception e) {
            e.printStackTrace();
        }*/

        if(isWeekend && noWeekends) {
            //Alarm is not wanted on the weekend
            try {
                Thread.sleep(1);  //waits for millisecond
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        else if (isOutsideWorkHours  && workHoursOnly){
            //Alarm not wanted outside of work hours
            try {
                Thread.sleep(1);  //waits for millisecond
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        else {
            //Alarm is wanted, and should go off
            Intent myIntent = new Intent();
            myIntent.setClassName("com.joshbgold.move", "com.joshbgold.move.main.ReminderActivity");
            myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(myIntent);
        }
    }

    //check if a prefs key exists
    private boolean checkPrefs(String key){
        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(myContext);
        boolean exists = sharedPreferences.contains(key);
        return exists;
    }

    //get prefs
    private boolean loadPrefs(String key,boolean value) {
        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(myContext);
        boolean data = sharedPreferences.getBoolean(key, value);
        return data;
    }
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
joshgoldeneagle
  • 4,616
  • 2
  • 23
  • 30
  • Total nit picking. wait(1) is one millisecond, not one-thousandth of a millisecond. – dnellis74 Oct 19 '15 at 17:31
  • What is going wrong? Did you test it on a weekend and the alarm was fired? Did you debug it on a weekend and checked the "dayOfTheWeek"'s value to see what is inside of it? What is the value of repeatIntervalMilliseconds? – Christian Oct 19 '15 at 20:42

4 Answers4

9

Your approach is fine. Anyway I suggest you to avoid using hardcoded strings for the weekend check. You already have a Calendar object defined in your code, just use it:

Calendar calendar = Calendar.getInstance();
//..
int today  = calendar.get(Calendar.DAY_OF_WEEK);
boolean isWeekend = (today == Calendar.SUNDAY) || (today == Calendar.SATURDAY);

And update your code accordingly:

  //...
  int today  = calendar.get(Calendar.DAY_OF_WEEK);
  boolean isWeekend = (today == Calendar.SUNDAY) || (today == Calendar.SATURDAY);
  if(isWeekend && noWeekends == true) {
        //Alarm is not wanted on the weekend
        try {
            Thread.sleep(1);  
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
  //...
bonnyz
  • 13,458
  • 5
  • 46
  • 70
  • I am successfully able to fire off an alarm request, and then filter out the request in the AlarmReceiver now, using pretty much the code you have posted above. I changed wait() method to Thread.sleep due to error "IllegalMonitorStateException: object not locked by thread before wait()". I set up a dummy if condition for testing since it is not the weekend now. Previously when the either of the if conditions were true, app was crashing, but OK now. – joshgoldeneagle Oct 19 '15 at 23:36
  • Changing from using try catch block to check if sharedPreferences exist, to using the built in sharedPreferences method contains() to check for the existence of sharedPreferences keys. – joshgoldeneagle Oct 21 '15 at 23:56
  • Also another issue I found with the sharedPreferences is that since AlarmReceiver extends wakefulBroadcastReceiver, it does not receive the application context automatically. I had to pass in the application context from mainactivity to the onReceive method, and from the onReceive method to the sharedPrefences methods – joshgoldeneagle Oct 23 '15 at 18:14
3

In addition to dnellis74's answer you also need some brackets here:

if(dayOfTheWeek == "Saturday" || dayOfTheWeek == "Sunday"  && noWeekends == true)

becomes

if((dayOfTheWeek == "Saturday" || dayOfTheWeek == "Sunday")  && noWeekends == true)

also I think you do not need

 try {
      wait(1);  //waits for one-thousandth of a millisecond
     } catch (InterruptedException e) {
                e.printStackTrace();
     }
leonardkraemer
  • 6,573
  • 1
  • 31
  • 54
0

Totally spitballing here, I'm not an Android developer. Your day of the week variable:

Date date = new Date();
String dayOfTheWeek = simpleDateFormat.format(date);

is a member variable of the class. It will only get set when the class is instantiated. If this is only happening in some sort of startup cycle, dayOfTheWeek WILL NEVER CHANGE. So if I'm correct, if you set your alarm on a Wednesday, this code will always think it's Wednesday, even on Saturday.

Move those two lines of code inside the actual function onReceive() and I'll bet that day of the week will start to get picked up.

dnellis74
  • 112
  • 4
0

1.) It is perfectly fine to fire an event and then filter/process it in a subscriber(BroadcastReceiver). That's what they are made for.

2.)

if((dayOfTheWeek == "Saturday" || dayOfTheWeek == "Sunday")  && noWeekends == true)

notice the parentheses fix.

LeChiffre
  • 596
  • 5
  • 7