Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe58f1f3 authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Snooze schedule rules that were canceled by alarms.

So a reboot or snoozed alarm doesn't cause them to
reactivate.

Bug: 30087850
Change-Id: I83fdb88009b515d442993944aec40df7365e830f
parent 9fd8d75e
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Objects;
@@ -896,9 +897,13 @@ public class ZenModeConfig implements Parcelable {
                    ", endHour=" + endHour +
                    ", endMinute=" + endMinute +
                    ", exitAtAlarm=" + exitAtAlarm +
                    ", nextAlarm=" + nextAlarm +
                    ", nextAlarm=" + ts(nextAlarm) +
                    '}';
        }

        protected static String ts(long time) {
            return new Date(time) + " (" + time + ")";
        }
    }

    // ==== Built-in system condition: event ====
+6 −8
Original line number Diff line number Diff line
@@ -82,15 +82,13 @@ public class ScheduleCalendar {
        if (end <= start) {
            end = addDays(end, 1);
        }
        boolean isInSchedule =
                isInSchedule(-1, time, start, end) || isInSchedule(0, time, start, end);
        if (isInSchedule && mSchedule.exitAtAlarm
                && mSchedule.nextAlarm != 0
                && time >= mSchedule.nextAlarm) {
            return false;
        } else {
            return isInSchedule;
        return isInSchedule(-1, time, start, end) || isInSchedule(0, time, start, end);
    }

    public boolean shouldExitForAlarm(long time) {
        return mSchedule.exitAtAlarm
                && mSchedule.nextAlarm != 0
                && time >= mSchedule.nextAlarm;
    }

    private boolean isInSchedule(int daysOffset, long time, long start, long end) {
+75 −2
Original line number Diff line number Diff line
@@ -25,11 +25,15 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Binder;
import android.provider.Settings;
import android.service.notification.Condition;
import android.service.notification.IConditionProvider;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;

@@ -53,9 +57,13 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
    private static final String ACTION_EVALUATE =  SIMPLE_NAME + ".EVALUATE";
    private static final int REQUEST_CODE_EVALUATE = 1;
    private static final String EXTRA_TIME = "time";
    private static final String SEPARATOR = ";";
    private static final String SCP_SETTING = "snoozed_schedule_condition_provider";


    private final Context mContext = this;
    private final ArrayMap<Uri, ScheduleCalendar> mSubscriptions = new ArrayMap<>();
    private ArraySet<Uri> mSnoozed = new ArraySet<>();

    private AlarmManager mAlarmManager;
    private boolean mConnected;
@@ -90,6 +98,7 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
            pw.print("            ");
            pw.println(mSubscriptions.get(conditionId).toString());
        }
        pw.println("      snoozed due to alarm: " + TextUtils.join(SEPARATOR, mSnoozed));
        dumpUpcomingTime(pw, "mNextAlarmTime", mNextAlarmTime, now);
    }

@@ -97,6 +106,7 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
    public void onConnected() {
        if (DEBUG) Slog.d(TAG, "onConnected");
        mConnected = true;
        readSnoozed();
    }

    @Override
@@ -126,6 +136,7 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
    public void onUnsubscribe(Uri conditionId) {
        if (DEBUG) Slog.d(TAG, "onUnsubscribe " + conditionId);
        mSubscriptions.remove(conditionId);
        removeSnoozed(conditionId);
        evaluateSubscriptions();
    }

@@ -150,10 +161,16 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
        for (Uri conditionId : mSubscriptions.keySet()) {
            final ScheduleCalendar cal = mSubscriptions.get(conditionId);
            if (cal != null && cal.isInSchedule(now)) {
                if (conditionSnoozed(conditionId) || cal.shouldExitForAlarm(now)) {
                    notifyCondition(conditionId, Condition.STATE_FALSE, "alarmCanceled");
                    addSnoozed(conditionId);
                } else {
                    notifyCondition(conditionId, Condition.STATE_TRUE, "meetsSchedule");
                }
                cal.maybeSetNextAlarm(now, nextUserAlarmTime);
            } else {
                notifyCondition(conditionId, Condition.STATE_FALSE, "!meetsSchedule");
                removeSnoozed(conditionId);
                if (nextUserAlarmTime == 0) {
                    cal.maybeSetNextAlarm(now, nextUserAlarmTime);
                }
@@ -194,7 +211,7 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
        return info != null ? info.getTriggerTime() : 0;
    }

    private static boolean meetsSchedule(ScheduleCalendar cal, long time) {
    private boolean meetsSchedule(ScheduleCalendar cal, long time) {
        return cal != null && cal.isInSchedule(time);
    }

@@ -237,6 +254,62 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
        return new Condition(id, summary, line1, line2, 0, state, Condition.FLAG_RELEVANT_ALWAYS);
    }

    private boolean conditionSnoozed(Uri conditionId) {
        synchronized (mSnoozed) {
            return mSnoozed.contains(conditionId);
        }
    }

    private void addSnoozed(Uri conditionId) {
        synchronized (mSnoozed) {
            mSnoozed.add(conditionId);
            saveSnoozedLocked();
        }
    }

    private void removeSnoozed(Uri conditionId) {
        synchronized (mSnoozed) {
            mSnoozed.remove(conditionId);
            saveSnoozedLocked();
        }
    }

    public void saveSnoozedLocked() {
        final String setting = TextUtils.join(SEPARATOR, mSnoozed);
        final int currentUser = ActivityManager.getCurrentUser();
        Settings.Secure.putStringForUser(mContext.getContentResolver(),
                SCP_SETTING,
                setting,
                currentUser);
    }

    public void readSnoozed() {
        synchronized (mSnoozed) {
            long identity = Binder.clearCallingIdentity();
            try {
                final String setting = Settings.Secure.getStringForUser(
                        mContext.getContentResolver(),
                        SCP_SETTING,
                        ActivityManager.getCurrentUser());
                if (setting != null) {
                    final String[] tokens = setting.split(SEPARATOR);
                    for (int i = 0; i < tokens.length; i++) {
                        String token = tokens[i];
                        if (token != null) {
                            token = token.trim();
                        }
                        if (TextUtils.isEmpty(token)) {
                            continue;
                        }
                        mSnoozed.add(Uri.parse(token));
                    }
                }
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    }

    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {