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
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 69960b0..e90a3ba 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -44,6 +44,7 @@
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 @@
", 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 ====
diff --git a/services/core/java/com/android/server/notification/ScheduleCalendar.java b/services/core/java/com/android/server/notification/ScheduleCalendar.java
index 22ca702..9e8b2e3 100644
--- a/services/core/java/com/android/server/notification/ScheduleCalendar.java
+++ b/services/core/java/com/android/server/notification/ScheduleCalendar.java
@@ -82,15 +82,13 @@
if (end <= start) {
end = addDays(end, 1);
}
- boolean isInSchedule =
- isInSchedule(-1, time, start, end) || isInSchedule(0, time, start, end);
- if (isInSchedule && mSchedule.exitAtAlarm
+ 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) {
- return false;
- } else {
- return isInSchedule;
- }
+ && time >= mSchedule.nextAlarm;
}
private boolean isInSchedule(int daysOffset, long time, long start, long end) {
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index 8197544..32d03ce 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -25,11 +25,15 @@
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 @@
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 @@
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 void onConnected() {
if (DEBUG) Slog.d(TAG, "onConnected");
mConnected = true;
+ readSnoozed();
}
@Override
@@ -126,6 +136,7 @@
public void onUnsubscribe(Uri conditionId) {
if (DEBUG) Slog.d(TAG, "onUnsubscribe " + conditionId);
mSubscriptions.remove(conditionId);
+ removeSnoozed(conditionId);
evaluateSubscriptions();
}
@@ -150,10 +161,16 @@
for (Uri conditionId : mSubscriptions.keySet()) {
final ScheduleCalendar cal = mSubscriptions.get(conditionId);
if (cal != null && cal.isInSchedule(now)) {
- notifyCondition(conditionId, Condition.STATE_TRUE, "meetsSchedule");
+ 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 @@
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 @@
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) {