• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.service.notification;
18 
19 import android.service.notification.ZenModeConfig.ScheduleInfo;
20 import android.util.ArraySet;
21 import android.util.Log;
22 
23 import java.util.Calendar;
24 import java.util.Objects;
25 import java.util.TimeZone;
26 
27 /**
28  * @hide
29  */
30 public class ScheduleCalendar {
31     public static final String TAG = "ScheduleCalendar";
32     public static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG);
33     private final ArraySet<Integer> mDays = new ArraySet<Integer>();
34     private final Calendar mCalendar = Calendar.getInstance();
35 
36     private ScheduleInfo mSchedule;
37 
38     @Override
toString()39     public String toString() {
40         return "ScheduleCalendar[mDays=" + mDays + ", mSchedule=" + mSchedule + "]";
41     }
42 
43     /**
44      * @return true if schedule will exit on alarm, else false
45      */
exitAtAlarm()46     public boolean exitAtAlarm() {
47         return mSchedule.exitAtAlarm;
48     }
49 
50     /**
51      * Sets schedule information
52      */
setSchedule(ScheduleInfo schedule)53     public void setSchedule(ScheduleInfo schedule) {
54         if (Objects.equals(mSchedule, schedule)) return;
55         mSchedule = schedule;
56         updateDays();
57     }
58 
59     /**
60      * Sets next alarm of the schedule
61      * @param now current time in milliseconds
62      * @param nextAlarm time of next alarm in milliseconds
63      */
maybeSetNextAlarm(long now, long nextAlarm)64     public void maybeSetNextAlarm(long now, long nextAlarm) {
65         if (mSchedule != null && mSchedule.exitAtAlarm) {
66             if (nextAlarm == 0) {
67                 // alarm canceled
68                 mSchedule.nextAlarm = 0;
69             } else if (nextAlarm > now) {
70                 // only allow alarms in the future
71                 mSchedule.nextAlarm = nextAlarm;
72             } else if (mSchedule.nextAlarm < now) {
73                 if (DEBUG) {
74                     Log.d(TAG, "All alarms are in the past " + mSchedule.nextAlarm);
75                 }
76                 mSchedule.nextAlarm = 0;
77             }
78         }
79     }
80 
81     /**
82      * Set calendar time zone to tz
83      * @param tz current time zone
84      */
setTimeZone(TimeZone tz)85     public void setTimeZone(TimeZone tz) {
86         mCalendar.setTimeZone(tz);
87     }
88 
89     /**
90      * @param now current time in milliseconds
91      * @return next time this rule changes (starts or ends)
92      */
getNextChangeTime(long now)93     public long getNextChangeTime(long now) {
94         if (mSchedule == null) return 0;
95         final long nextStart = getNextTime(now, mSchedule.startHour, mSchedule.startMinute);
96         final long nextEnd = getNextTime(now, mSchedule.endHour, mSchedule.endMinute);
97         long nextScheduleTime = Math.min(nextStart, nextEnd);
98 
99         return nextScheduleTime;
100     }
101 
getNextTime(long now, int hr, int min)102     private long getNextTime(long now, int hr, int min) {
103         final long time = getTime(now, hr, min);
104         return time <= now ? addDays(time, 1) : time;
105     }
106 
getTime(long millis, int hour, int min)107     private long getTime(long millis, int hour, int min) {
108         mCalendar.setTimeInMillis(millis);
109         mCalendar.set(Calendar.HOUR_OF_DAY, hour);
110         mCalendar.set(Calendar.MINUTE, min);
111         mCalendar.set(Calendar.SECOND, 0);
112         mCalendar.set(Calendar.MILLISECOND, 0);
113         return mCalendar.getTimeInMillis();
114     }
115 
116     /**
117      * @param time milliseconds since Epoch
118      * @return true if time is within the schedule, else false
119      */
isInSchedule(long time)120     public boolean isInSchedule(long time) {
121         if (mSchedule == null || mDays.size() == 0) return false;
122         final long start = getTime(time, mSchedule.startHour, mSchedule.startMinute);
123         long end = getTime(time, mSchedule.endHour, mSchedule.endMinute);
124         if (end <= start) {
125             end = addDays(end, 1);
126         }
127         return isInSchedule(-1, time, start, end) || isInSchedule(0, time, start, end);
128     }
129 
130     /**
131      * @param alarm milliseconds since Epoch
132      * @param now milliseconds since Epoch
133      * @return true if alarm and now is within the schedule, else false
134      */
isAlarmInSchedule(long alarm, long now)135     public boolean isAlarmInSchedule(long alarm, long now) {
136         if (mSchedule == null || mDays.size() == 0) return false;
137         final long start = getTime(alarm, mSchedule.startHour, mSchedule.startMinute);
138         long end = getTime(alarm, mSchedule.endHour, mSchedule.endMinute);
139         if (end <= start) {
140             end = addDays(end, 1);
141         }
142         return (isInSchedule(-1, alarm, start, end)
143                 && isInSchedule(-1, now, start, end))
144                 || (isInSchedule(0, alarm, start, end)
145                 && isInSchedule(0, now, start, end));
146     }
147 
148     /**
149      * @param time milliseconds since Epoch
150      * @return true if should exit at time for next alarm, else false
151      */
shouldExitForAlarm(long time)152     public boolean shouldExitForAlarm(long time) {
153         if (mSchedule == null) {
154             return false;
155         }
156         return mSchedule.exitAtAlarm
157                 && mSchedule.nextAlarm != 0
158                 && time >= mSchedule.nextAlarm
159                 && isAlarmInSchedule(mSchedule.nextAlarm, time);
160     }
161 
isInSchedule(int daysOffset, long time, long start, long end)162     private boolean isInSchedule(int daysOffset, long time, long start, long end) {
163         final int n = Calendar.SATURDAY;
164         final int day = ((getDayOfWeek(time) - 1) + (daysOffset % n) + n) % n + 1;
165         start = addDays(start, daysOffset);
166         end = addDays(end, daysOffset);
167         return mDays.contains(day) && time >= start && time < end;
168     }
169 
getDayOfWeek(long time)170     private int getDayOfWeek(long time) {
171         mCalendar.setTimeInMillis(time);
172         return mCalendar.get(Calendar.DAY_OF_WEEK);
173     }
174 
updateDays()175     private void updateDays() {
176         mDays.clear();
177         if (mSchedule != null && mSchedule.days != null) {
178             for (int i = 0; i < mSchedule.days.length; i++) {
179                 mDays.add(mSchedule.days[i]);
180             }
181         }
182     }
183 
addDays(long time, int days)184     private long addDays(long time, int days) {
185         mCalendar.setTimeInMillis(time);
186         mCalendar.add(Calendar.DATE, days);
187         return mCalendar.getTimeInMillis();
188     }
189 }
190