1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "reminder_request_alarm.h"
17 
18 #include "ans_log_wrapper.h"
19 
20 namespace OHOS {
21 namespace Notification {
22 const uint8_t ReminderRequestAlarm::MINUTES_PER_HOUR = 60;
23 const int8_t ReminderRequestAlarm::DEFAULT_SNOOZE_TIMES = 3;
24 
ReminderRequestAlarm(uint8_t hour,uint8_t minute,const std::vector<uint8_t> daysOfWeek)25 ReminderRequestAlarm::ReminderRequestAlarm(uint8_t hour, uint8_t minute, const std::vector<uint8_t> daysOfWeek)
26     : ReminderRequest(ReminderRequest::ReminderType::ALARM)
27 {
28     SetSnoozeTimes(DEFAULT_SNOOZE_TIMES);
29     hour_ = hour;
30     minute_ = minute;
31     CheckParamValid();
32     SetRepeatDaysOfWeek(true, daysOfWeek);
33     SetTriggerTimeInMilli(GetNextTriggerTime(true));
34 }
35 
ReminderRequestAlarm(const ReminderRequestAlarm & other)36 ReminderRequestAlarm::ReminderRequestAlarm(const ReminderRequestAlarm &other) : ReminderRequest(other)
37 {
38     hour_ = other.hour_;
39     minute_ = other.minute_;
40     repeatDaysOfWeek_ = other.repeatDaysOfWeek_;
41     ANSR_LOGD("hour_=%{public}d, minute_=%{public}d, repeatDaysOfWeek_=%{public}d",
42         hour_, minute_, other.repeatDaysOfWeek_);
43 }
44 
CheckParamValid() const45 void ReminderRequestAlarm::CheckParamValid() const
46 {
47     if (hour_ >= HOURS_PER_DAY) {
48         ANSR_LOGE("setted hour is not between [0, 24)");
49         return;
50     }
51     if (minute_ >= MINUTES_PER_HOUR) {
52         ANSR_LOGE("setted minute is not between [0, 60)");
53         return;
54     }
55 }
56 
IsRepeatReminder() const57 bool ReminderRequestAlarm::IsRepeatReminder() const
58 {
59     if ((repeatDaysOfWeek_ != 0) || ((GetTimeInterval() > 0) && (GetSnoozeTimes() > 0))) {
60         return true;
61     } else {
62         return false;
63     }
64 }
65 
66 
PreGetNextTriggerTimeIgnoreSnooze(bool ignoreRepeat,bool forceToGetNext)67 uint64_t ReminderRequestAlarm::PreGetNextTriggerTimeIgnoreSnooze(bool ignoreRepeat, bool forceToGetNext)
68 {
69     if (ignoreRepeat || (repeatDaysOfWeek_)) {
70         return GetNextTriggerTime(forceToGetNext);
71     } else {
72         return INVALID_LONG_LONG_VALUE;
73     }
74 }
75 
GetNextTriggerTime(bool forceToGetNext) const76 uint64_t ReminderRequestAlarm::GetNextTriggerTime(bool forceToGetNext) const
77 {
78     time_t now;
79     (void)time(&now);  // unit is seconds.
80     struct tm nowTime;
81     (void)localtime_r(&now, &nowTime);
82     ANSR_LOGD("Now: year=%{public}d, mon=%{public}d, day=%{public}d, hour=%{public}d, "
83         "min=%{public}d, sec=%{public}d, week=%{public}d, Target: tar_hour=%{public}d, tar_min=%{public}d",
84         GetActualTime(TimeTransferType::YEAR, nowTime.tm_year),
85         GetActualTime(TimeTransferType::MONTH, nowTime.tm_mon),
86         nowTime.tm_mday, nowTime.tm_hour, nowTime.tm_min, nowTime.tm_sec,
87         GetActualTime(TimeTransferType::WEEK, nowTime.tm_wday), hour_, minute_);
88 
89     struct tm tar;
90     tar.tm_year = nowTime.tm_year;
91     tar.tm_mon = nowTime.tm_mon;
92     tar.tm_mday = nowTime.tm_mday;
93     tar.tm_hour = hour_;
94     tar.tm_min = minute_;
95     tar.tm_sec = 0;
96     tar.tm_isdst = -1;
97 
98     const time_t target = mktime(&tar);
99     if (repeatDaysOfWeek_ > 0) {
100         return GetNextDaysOfWeek(now, target);
101     }
102 
103     time_t nextTriggerTime = 0;
104     if (now >= target) {
105         if (forceToGetNext) {
106             nextTriggerTime = target + 1 * HOURS_PER_DAY * SECONDS_PER_HOUR;
107         }
108     } else {
109         nextTriggerTime = target;
110     }
111     return GetTriggerTime(now, nextTriggerTime);
112 }
113 
SetHour(const uint8_t hour)114 void ReminderRequestAlarm::SetHour(const uint8_t hour)
115 {
116     hour_ = hour;
117 }
118 
SetMinute(const uint8_t minute)119 void ReminderRequestAlarm::SetMinute(const uint8_t minute)
120 {
121     minute_ = minute;
122 }
123 
GetHour() const124 uint8_t ReminderRequestAlarm::GetHour() const
125 {
126     return hour_;
127 }
128 
GetMinute() const129 uint8_t ReminderRequestAlarm::GetMinute() const
130 {
131     return minute_;
132 }
133 
UpdateNextReminder()134 bool ReminderRequestAlarm::UpdateNextReminder()
135 {
136     ANSR_LOGD("UpdateNextReminder alarm time");
137     if (IsRepeatReminder()) {
138         uint8_t letfSnoozeTimes = GetSnoozeTimesDynamic();
139         if ((letfSnoozeTimes > 0) && (GetTimeInterval() > 0)) {
140             ANSR_LOGI("Left times: %{public}d, update next triggerTime", GetSnoozeTimesDynamic());
141             SetTriggerTimeInMilli(GetTriggerTimeInMilli() + GetTimeInterval() * MILLI_SECONDS);
142             SetSnoozeTimesDynamic(--letfSnoozeTimes);
143         } else {
144             SetSnoozeTimesDynamic(GetSnoozeTimes());
145             if (repeatDaysOfWeek_ == 0) {
146                 ANSR_LOGI("No need to update next triggerTime");
147                 SetExpired(true);
148                 return false;
149             }
150             uint64_t nextTriggerTime = GetNextTriggerTime(true);
151             if (nextTriggerTime != INVALID_LONG_LONG_VALUE) {
152                 ANSR_LOGI("Set next trigger time successful, reset dynamic snoozeTimes");
153                 SetTriggerTimeInMilli(nextTriggerTime);
154             } else {
155                 ANSR_LOGW("Set reminder to expired");
156                 SetExpired(true);
157                 return false;
158             }
159         }
160         return true;
161     } else {
162         ANSR_LOGD("Single time reminder, not need to update next trigger time");
163         SetSnoozeTimesDynamic(GetSnoozeTimes());
164         SetExpired(true);
165         return false;
166     }
167 }
168 
Marshalling(Parcel & parcel) const169 bool ReminderRequestAlarm::Marshalling(Parcel &parcel) const
170 {
171     if (ReminderRequest::Marshalling(parcel)) {
172         WRITE_UINT8_RETURN_FALSE_LOG(parcel, hour_, "hour");
173         WRITE_UINT8_RETURN_FALSE_LOG(parcel, minute_, "minute");
174         WRITE_UINT8_RETURN_FALSE_LOG(parcel, repeatDaysOfWeek_, "repeatDaysOfWeek");
175         return true;
176     }
177     return false;
178 }
179 
Unmarshalling(Parcel & parcel)180 ReminderRequestAlarm *ReminderRequestAlarm::Unmarshalling(Parcel &parcel)
181 {
182     ANSR_LOGD("New alarm");
183     auto objptr = new (std::nothrow) ReminderRequestAlarm();
184     if (objptr == nullptr) {
185         ANSR_LOGE("Failed to create reminder alarm due to no memory.");
186         return objptr;
187     }
188     if (!objptr->ReadFromParcel(parcel)) {
189         delete objptr;
190         objptr = nullptr;
191     }
192     return objptr;
193 }
194 
ReadFromParcel(Parcel & parcel)195 bool ReminderRequestAlarm::ReadFromParcel(Parcel &parcel)
196 {
197     if (ReminderRequest::ReadFromParcel(parcel)) {
198         READ_UINT8_RETURN_FALSE_LOG(parcel, hour_, "hour");
199         READ_UINT8_RETURN_FALSE_LOG(parcel, minute_, "minute");
200         READ_UINT8_RETURN_FALSE_LOG(parcel, repeatDaysOfWeek_, "repeatDaysOfWeek");
201 
202         ANSR_LOGD("hour_=%{public}d, minute_=%{public}d", hour_, minute_);
203         return true;
204     }
205     return false;
206 }
207 }
208 }