1 /**
2  * Copyright (c) 2014, 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 com.android.server.notification;
18 
19 import android.service.notification.ZenModeConfig.ScheduleInfo;
20 import android.util.ArraySet;
21 
22 import java.util.Calendar;
23 import java.util.Objects;
24 import java.util.TimeZone;
25 
26 public class ScheduleCalendar {
27     private final ArraySet<Integer> mDays = new ArraySet<Integer>();
28     private final Calendar mCalendar = Calendar.getInstance();
29 
30     private ScheduleInfo mSchedule;
31 
32     @Override
toString()33     public String toString() {
34         return "ScheduleCalendar[mDays=" + mDays + "]";
35     }
36 
setSchedule(ScheduleInfo schedule)37     public void setSchedule(ScheduleInfo schedule) {
38         if (Objects.equals(mSchedule, schedule)) return;
39         mSchedule = schedule;
40         updateDays();
41     }
42 
nextScheduleStart(long time)43     public long nextScheduleStart(long time) {
44         if (mSchedule == null || mDays.size() == 0) return Long.MAX_VALUE;
45         final long start = getTime(time, mSchedule.startHour, mSchedule.startMinute);
46         for (int i = 0; i < Calendar.SATURDAY; i++) {
47             final long t = addDays(start, i);
48             if (t > time && isInSchedule(t)) {
49                 return t;
50             }
51         }
52         return Long.MAX_VALUE;
53     }
54 
setTimeZone(TimeZone tz)55     public void setTimeZone(TimeZone tz) {
56         mCalendar.setTimeZone(tz);
57     }
58 
getNextChangeTime(long now)59     public long getNextChangeTime(long now) {
60         if (mSchedule == null) return 0;
61         final long nextStart = getNextTime(now, mSchedule.startHour, mSchedule.startMinute);
62         final long nextEnd = getNextTime(now, mSchedule.endHour, mSchedule.endMinute);
63         return Math.min(nextStart, nextEnd);
64     }
65 
getNextTime(long now, int hr, int min)66     private long getNextTime(long now, int hr, int min) {
67         final long time = getTime(now, hr, min);
68         return time <= now ? addDays(time, 1) : time;
69     }
70 
getTime(long millis, int hour, int min)71     private long getTime(long millis, int hour, int min) {
72         mCalendar.setTimeInMillis(millis);
73         mCalendar.set(Calendar.HOUR_OF_DAY, hour);
74         mCalendar.set(Calendar.MINUTE, min);
75         mCalendar.set(Calendar.SECOND, 0);
76         mCalendar.set(Calendar.MILLISECOND, 0);
77         return mCalendar.getTimeInMillis();
78     }
79 
isInSchedule(long time)80     public boolean isInSchedule(long time) {
81         if (mSchedule == null || mDays.size() == 0) return false;
82         final long start = getTime(time, mSchedule.startHour, mSchedule.startMinute);
83         long end = getTime(time, mSchedule.endHour, mSchedule.endMinute);
84         if (end <= start) {
85             end = addDays(end, 1);
86         }
87         return isInSchedule(-1, time, start, end) || isInSchedule(0, time, start, end);
88     }
89 
isInSchedule(int daysOffset, long time, long start, long end)90     private boolean isInSchedule(int daysOffset, long time, long start, long end) {
91         final int n = Calendar.SATURDAY;
92         final int day = ((getDayOfWeek(time) - 1) + (daysOffset % n) + n) % n + 1;
93         start = addDays(start, daysOffset);
94         end = addDays(end, daysOffset);
95         return mDays.contains(day) && time >= start && time < end;
96     }
97 
getDayOfWeek(long time)98     private int getDayOfWeek(long time) {
99         mCalendar.setTimeInMillis(time);
100         return mCalendar.get(Calendar.DAY_OF_WEEK);
101     }
102 
updateDays()103     private void updateDays() {
104         mDays.clear();
105         if (mSchedule != null && mSchedule.days != null) {
106             for (int i = 0; i < mSchedule.days.length; i++) {
107                 mDays.add(mSchedule.days[i]);
108             }
109         }
110     }
111 
addDays(long time, int days)112     private long addDays(long time, int days) {
113         mCalendar.setTimeInMillis(time);
114         mCalendar.add(Calendar.DATE, days);
115         return mCalendar.getTimeInMillis();
116     }
117 }