com.robwilliamson.healthyesther.reminder.TimingModel.java Source code

Java tutorial

Introduction

Here is the source code for com.robwilliamson.healthyesther.reminder.TimingModel.java

Source

/**
  *  Robert Williamson 2014-2016.
  * This program is distributed under the terms of the GNU General Public License.
  */
package com.robwilliamson.healthyesther.reminder;

import com.robwilliamson.healthyesther.util.time.Range;
import com.robwilliamson.healthyesther.util.time.RangeSet;

import org.joda.time.DateTime;
import org.joda.time.Duration;

public class TimingModel {
    private static final Duration SIGMA = Duration.standardMinutes(1);
    private final Environment mEnvironment;
    private final Duration mMinTimeBetweenNotifications;
    private final RangeSet mAllowedNotificationTimes;
    private final Duration mPeriod;

    public TimingModel(Environment environment, Duration period, Duration minTimeBetweenNotifications,
            Range allowedNotificationTimes) {
        mEnvironment = environment;
        mPeriod = period;
        mMinTimeBetweenNotifications = minTimeBetweenNotifications;
        mAllowedNotificationTimes = new RangeSet(allowedNotificationTimes.startingYesterday(),
                allowedNotificationTimes, allowedNotificationTimes.startingTomorrow());
    }

    public void onAlarmElapsed() {
        notifyIfAppropriate();
        ensureNotificationIsPending();
    }

    public void onApplicationCreated() {
        ensureNotificationIsPending();
    }

    public void onBootCompleted() {
        notifyIfAppropriate();
        ensureNotificationIsPending();
    }

    public void onNotified() {
        DateTime now = mEnvironment.getNow();
        mEnvironment.setLastNotifiedTime(now);
        mEnvironment.setNextNotificationTime(null);
        setAlarm(getNextNotificationAfter(now));
    }

    public void onScreenOn() {
        notifyIfAppropriate();
        ensureNotificationIsPending();
    }

    public void onUserEntry() {
        setAlarm(getNextNotificationAfter(mEnvironment.getNow()));
    }

    private boolean shouldNotify() {
        DateTime now = mEnvironment.getNow();
        boolean notificationAllowed = allowedTimes().contains(now) && !mEnvironment.appInForeground();

        if (!notificationAllowed) {
            return false;
        }

        if (hasNotifiedBefore()) {
            if (coolOffPeriod().contains(now)) {
                return false;
            }

            DateTime next = mEnvironment.getNextNotificationTime();
            if (next == null || new Range(now, SIGMA).contains(next) || next.isBefore(now)) {
                return true;
            }
        } else {
            return true;
        }

        return false;
    }

    private void notifyIfAppropriate() {
        if (shouldNotify()) {
            mEnvironment.sendReminder();
        }
    }

    private void ensureNotificationIsPending() {
        DateTime now = mEnvironment.getNow();
        DateTime next = mEnvironment.getNextNotificationTime();

        if (next == null || next.isBefore(now) || next.minus(mPeriod).isAfter(now)) {
            setAlarm(getNextNotificationAfter(now));
        } else {
            setAlarm(next);
        }
    }

    private DateTime getNextNotificationAfter(DateTime before) {
        if (before == null) {
            before = mEnvironment.getNow();
        }

        DateTime next = before.plus(mPeriod);

        if (allowedTimes().contains(next)) {
            return next;
        }

        next = allowedTimes().getEdgeAfter(next);

        if (next == null) {
            next = allowedTimes().to;
        }

        return next;
    }

    private boolean hasNotifiedBefore() {
        return mEnvironment.getLastNotifiedTime() != null;
    }

    private Range coolOffPeriod() {
        return new Range(mEnvironment.getLastNotifiedTime(), mMinTimeBetweenNotifications);
    }

    private RangeSet allowedTimes() {
        DateTime yesterday = mEnvironment.getNow().minus(Duration.standardDays(1));
        return mAllowedNotificationTimes.startingFrom(yesterday.getYear(), yesterday.getMonthOfYear(),
                yesterday.getDayOfMonth());
    }

    private void setAlarm(DateTime alarmTime) {
        mEnvironment.setAlarm(alarmTime);
        mEnvironment.setNextNotificationTime(alarmTime);
    }

    public interface Environment {
        DateTime getNow();

        DateTime getLastNotifiedTime();

        void setLastNotifiedTime(DateTime time);

        DateTime getNextNotificationTime();

        void setNextNotificationTime(DateTime time);

        boolean appInForeground();

        void setAlarm(DateTime alarmTime);

        void sendReminder();
    }
}