1530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock/**
2530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock * Copyright (c) 2014, The Android Open Source Project
3530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock *
4530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock * Licensed under the Apache License, Version 2.0 (the "License");
5530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock * you may not use this file except in compliance with the License.
6530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock * You may obtain a copy of the License at
7530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock *
8530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock *     http://www.apache.org/licenses/LICENSE-2.0
9530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock *
10530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock * Unless required by applicable law or agreed to in writing, software
11530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock * distributed under the License is distributed on an "AS IS" BASIS,
12530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock * See the License for the specific language governing permissions and
14530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock * limitations under the License.
15530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock */
16530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock
17530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlockpackage com.android.server.notification;
18530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock
19b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockimport android.service.notification.ZenModeConfig.ScheduleInfo;
20b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockimport android.util.ArraySet;
21b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock
22530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlockimport java.util.Calendar;
23530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlockimport java.util.Objects;
24530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlockimport java.util.TimeZone;
25530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock
26b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockpublic class ScheduleCalendar {
27530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    private final ArraySet<Integer> mDays = new ArraySet<Integer>();
28530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    private final Calendar mCalendar = Calendar.getInstance();
29530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock
30b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock    private ScheduleInfo mSchedule;
31530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock
32530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    @Override
33530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    public String toString() {
347f73308f50791740beb380fecc17903301054ad3Julia Reynolds        return "ScheduleCalendar[mDays=" + mDays + ", mSchedule=" + mSchedule + "]";
35530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    }
36530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock
37b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock    public void setSchedule(ScheduleInfo schedule) {
38b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock        if (Objects.equals(mSchedule, schedule)) return;
39b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock        mSchedule = schedule;
40530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        updateDays();
41530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    }
42530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock
431998ee56285419ff7fea0ec9a247e31d1d27a0abJulia Reynolds    public void maybeSetNextAlarm(long now, long nextAlarm) {
441998ee56285419ff7fea0ec9a247e31d1d27a0abJulia Reynolds        if (mSchedule != null) {
45837697a82f65e9a6865d9a37dda4ec6520d1e6ccJulia Reynolds            if (mSchedule.exitAtAlarm
46837697a82f65e9a6865d9a37dda4ec6520d1e6ccJulia Reynolds                    && (now > mSchedule.nextAlarm || nextAlarm < mSchedule.nextAlarm)) {
471998ee56285419ff7fea0ec9a247e31d1d27a0abJulia Reynolds                mSchedule.nextAlarm = nextAlarm;
48530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock            }
49530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        }
50530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    }
51530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock
52530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    public void setTimeZone(TimeZone tz) {
53530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        mCalendar.setTimeZone(tz);
54530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    }
55530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock
56b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock    public long getNextChangeTime(long now) {
57b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock        if (mSchedule == null) return 0;
58b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock        final long nextStart = getNextTime(now, mSchedule.startHour, mSchedule.startMinute);
59b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock        final long nextEnd = getNextTime(now, mSchedule.endHour, mSchedule.endMinute);
601998ee56285419ff7fea0ec9a247e31d1d27a0abJulia Reynolds        long nextScheduleTime = Math.min(nextStart, nextEnd);
611998ee56285419ff7fea0ec9a247e31d1d27a0abJulia Reynolds
629eb2c1e85cd5def851ebe833a7f56a49f00e448fJulia Reynolds        return nextScheduleTime;
63b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock    }
64b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock
65b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock    private long getNextTime(long now, int hr, int min) {
66530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        final long time = getTime(now, hr, min);
67530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        return time <= now ? addDays(time, 1) : time;
68530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    }
69530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock
70530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    private long getTime(long millis, int hour, int min) {
71530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        mCalendar.setTimeInMillis(millis);
72530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        mCalendar.set(Calendar.HOUR_OF_DAY, hour);
73530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        mCalendar.set(Calendar.MINUTE, min);
74530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        mCalendar.set(Calendar.SECOND, 0);
75530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        mCalendar.set(Calendar.MILLISECOND, 0);
76530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        return mCalendar.getTimeInMillis();
77530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    }
78530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock
79b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock    public boolean isInSchedule(long time) {
80b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock        if (mSchedule == null || mDays.size() == 0) return false;
81b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock        final long start = getTime(time, mSchedule.startHour, mSchedule.startMinute);
82b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock        long end = getTime(time, mSchedule.endHour, mSchedule.endMinute);
83530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        if (end <= start) {
84530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock            end = addDays(end, 1);
85530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        }
86fe58f1f3862eb98837d2da6826dc17b67bf029cfJulia Reynolds        return isInSchedule(-1, time, start, end) || isInSchedule(0, time, start, end);
87fe58f1f3862eb98837d2da6826dc17b67bf029cfJulia Reynolds    }
88fe58f1f3862eb98837d2da6826dc17b67bf029cfJulia Reynolds
89fe58f1f3862eb98837d2da6826dc17b67bf029cfJulia Reynolds    public boolean shouldExitForAlarm(long time) {
90fe58f1f3862eb98837d2da6826dc17b67bf029cfJulia Reynolds        return mSchedule.exitAtAlarm
911998ee56285419ff7fea0ec9a247e31d1d27a0abJulia Reynolds                && mSchedule.nextAlarm != 0
92fe58f1f3862eb98837d2da6826dc17b67bf029cfJulia Reynolds                && time >= mSchedule.nextAlarm;
93530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    }
94530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock
95b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock    private boolean isInSchedule(int daysOffset, long time, long start, long end) {
96530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        final int n = Calendar.SATURDAY;
97530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        final int day = ((getDayOfWeek(time) - 1) + (daysOffset % n) + n) % n + 1;
98530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        start = addDays(start, daysOffset);
99530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        end = addDays(end, daysOffset);
100530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        return mDays.contains(day) && time >= start && time < end;
101530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    }
102530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock
103530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    private int getDayOfWeek(long time) {
104530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        mCalendar.setTimeInMillis(time);
105530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        return mCalendar.get(Calendar.DAY_OF_WEEK);
106530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    }
107530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock
108530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    private void updateDays() {
109530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        mDays.clear();
110b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock        if (mSchedule != null && mSchedule.days != null) {
111b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock            for (int i = 0; i < mSchedule.days.length; i++) {
112b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock                mDays.add(mSchedule.days[i]);
113530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock            }
114530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        }
115530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    }
116530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock
117530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    private long addDays(long time, int days) {
118530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        mCalendar.setTimeInMillis(time);
119530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        mCalendar.add(Calendar.DATE, days);
120530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock        return mCalendar.getTimeInMillis();
121530052a2fe3b6a6a4246ce28ab0ced647fe7f470John Spurlock    }
1229eb2c1e85cd5def851ebe833a7f56a49f00e448fJulia Reynolds}
123