1 /*
2 * Copyright (c) 2024-2025 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 "disturb_manager.h"
17
18 #include <functional>
19 #include <iomanip>
20 #include <sstream>
21
22 #include "advanced_notification_service.h"
23 #include "notification_preferences.h"
24 #include "os_account_manager_helper.h"
25
26 #include "../advanced_notification_inline.cpp"
27
28 namespace OHOS {
29 namespace Notification {
30 constexpr int32_t HOURS_IN_ONE_DAY = 24;
31
HandleSetDoNotDisturbDate(MessageParcel & data,MessageParcel & reply)32 ErrCode DisturbManager::HandleSetDoNotDisturbDate(MessageParcel &data, MessageParcel &reply)
33 {
34 sptr<NotificationDoNotDisturbDate> date = data.ReadParcelable<NotificationDoNotDisturbDate>();
35 if (date == nullptr) {
36 ANS_LOGE("[HandleSetDoNotDisturbDate] fail: read date failed.");
37 return ERR_ANS_PARCELABLE_FAILED;
38 }
39
40 ErrCode result = SetDoNotDisturbDate(date);
41 if (!reply.WriteInt32(result)) {
42 ANS_LOGE("[HandleSetDoNotDisturbDate] fail: write result failed, ErrCode=%{public}d", result);
43 return ERR_ANS_PARCELABLE_FAILED;
44 }
45
46 return ERR_OK;
47 }
HandleSetDoNotDisturbDateByUser(MessageParcel & data,MessageParcel & reply)48 ErrCode DisturbManager::HandleSetDoNotDisturbDateByUser(MessageParcel &data, MessageParcel &reply)
49 {
50 int32_t userId = SUBSCRIBE_USER_INIT;
51 if (!data.ReadInt32(userId)) {
52 ANS_LOGE("[HandleSetDoNotDisturbDateByUser] fail: read userId failed.");
53 return ERR_ANS_PARCELABLE_FAILED;
54 }
55
56 sptr<NotificationDoNotDisturbDate> date = data.ReadParcelable<NotificationDoNotDisturbDate>();
57 if (date == nullptr) {
58 ANS_LOGE("[HandleSetDoNotDisturbDateByUser] fail: read date failed.");
59 return ERR_ANS_PARCELABLE_FAILED;
60 }
61
62 ErrCode result = SetDoNotDisturbDateByUserSyncQueue(userId, date);
63 if (!reply.WriteInt32(result)) {
64 ANS_LOGE("[HandleSetDoNotDisturbDateByUser] fail: write result failed, ErrCode=%{public}d", result);
65 return ERR_ANS_PARCELABLE_FAILED;
66 }
67
68 return ERR_OK;
69 }
70
SetDoNotDisturbDate(const sptr<NotificationDoNotDisturbDate> & date)71 ErrCode DisturbManager::SetDoNotDisturbDate(const sptr<NotificationDoNotDisturbDate> &date)
72 {
73 ANS_LOGD("%{public}s", __FUNCTION__);
74
75 int32_t userId = SUBSCRIBE_USER_INIT;
76 if (OsAccountManagerHelper::GetInstance().GetCurrentActiveUserId(userId) != ERR_OK) {
77 ANS_LOGW("No active user found!");
78 return ERR_ANS_GET_ACTIVE_USER_FAILED;
79 }
80
81 return SetDoNotDisturbDateByUserSyncQueue(userId, date);
82 }
83
SetDoNotDisturbDateByUserSyncQueue(const int32_t & userId,const sptr<NotificationDoNotDisturbDate> & date)84 ErrCode DisturbManager::SetDoNotDisturbDateByUserSyncQueue(const int32_t &userId,
85 const sptr<NotificationDoNotDisturbDate> &date)
86 {
87 ANS_LOGD("%{public}s enter, userId = %{public}d", __FUNCTION__, userId);
88 if (userId <= SUBSCRIBE_USER_INIT) {
89 ANS_LOGE("Input userId is invalidity.");
90 return ERR_ANS_INVALID_PARAM;
91 }
92
93 if (date == nullptr) {
94 ANS_LOGE("Invalid date param");
95 return ERR_ANS_INVALID_PARAM;
96 }
97 int64_t beginDate = ResetSeconds(date->GetBeginDate());
98 int64_t endDate = ResetSeconds(date->GetEndDate());
99 switch (date->GetDoNotDisturbType()) {
100 case NotificationConstant::DoNotDisturbType::NONE:
101 beginDate = 0;
102 endDate = 0;
103 break;
104 case NotificationConstant::DoNotDisturbType::ONCE:
105 AdjustDateForDndTypeOnce(beginDate, endDate);
106 break;
107 case NotificationConstant::DoNotDisturbType::CLEARLY:
108 if (beginDate >= endDate) {
109 return ERR_ANS_INVALID_PARAM;
110 }
111 break;
112 default:
113 break;
114 }
115 ANS_LOGD("Before set SetDoNotDisturbDate beginDate = %{public}" PRId64 ", endDate = %{public}" PRId64,
116 beginDate, endDate);
117 const sptr<NotificationDoNotDisturbDate> newConfig = new (std::nothrow) NotificationDoNotDisturbDate(
118 date->GetDoNotDisturbType(), beginDate, endDate);
119 if (newConfig == nullptr) {
120 ANS_LOGE("Failed to create NotificationDoNotDisturbDate instance");
121 return ERR_NO_MEMORY;
122 }
123
124 sptr<NotificationBundleOption> bundleOption = AdvancedNotificationService::GenerateBundleOption();
125 if (bundleOption == nullptr) {
126 ANS_LOGE("Generate invalid bundle option!");
127 return ERR_ANS_INVALID_BUNDLE;
128 }
129 AdvancedNotificationService::GetInstance()->SubmitSyncTask(std::bind([&]() {
130 SetDoNotDisturbDateByUserInner(userId, newConfig);
131 }));
132 return ERR_OK;
133 }
134
SetDoNotDisturbDateByUserInner(const int32_t & userId,const sptr<NotificationDoNotDisturbDate> & date)135 ErrCode DisturbManager::SetDoNotDisturbDateByUserInner(const int32_t &userId,
136 const sptr<NotificationDoNotDisturbDate> &date)
137 {
138 ANS_LOGD("ffrt enter!");
139 ErrCode result = NotificationPreferences::GetInstance()->SetDoNotDisturbDate(userId, date);
140 if (result == ERR_OK) {
141 NotificationSubscriberManager::GetInstance()->NotifyDoNotDisturbDateChanged(userId, date);
142 }
143 return result;
144 }
145
AdjustDateForDndTypeOnce(int64_t & beginDate,int64_t & endDate)146 void DisturbManager::AdjustDateForDndTypeOnce(int64_t &beginDate, int64_t &endDate)
147 {
148 std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
149 time_t nowT = std::chrono::system_clock::to_time_t(now);
150 tm nowTm = GetLocalTime(nowT);
151
152 auto beginDateMilliseconds = std::chrono::milliseconds(beginDate);
153 auto beginDateTimePoint =
154 std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>(beginDateMilliseconds);
155 time_t beginDateT = std::chrono::system_clock::to_time_t(beginDateTimePoint);
156 tm beginDateTm = GetLocalTime(beginDateT);
157
158 auto endDateMilliseconds = std::chrono::milliseconds(endDate);
159 auto endDateTimePoint =
160 std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>(endDateMilliseconds);
161 time_t endDateT = std::chrono::system_clock::to_time_t(endDateTimePoint);
162 tm endDateTm = GetLocalTime(endDateT);
163
164 tm todayBeginTm = nowTm;
165 todayBeginTm.tm_sec = 0;
166 todayBeginTm.tm_min = beginDateTm.tm_min;
167 todayBeginTm.tm_hour = beginDateTm.tm_hour;
168
169 tm todayEndTm = nowTm;
170 todayEndTm.tm_sec = 0;
171 todayEndTm.tm_min = endDateTm.tm_min;
172 todayEndTm.tm_hour = endDateTm.tm_hour;
173
174 time_t todayBeginT = mktime(&todayBeginTm);
175 if (todayBeginT == -1) {
176 return;
177 }
178 time_t todayEndT = mktime(&todayEndTm);
179 if (todayEndT == -1) {
180 return;
181 }
182
183 auto newBeginTimePoint = std::chrono::system_clock::from_time_t(todayBeginT);
184 auto newEndTimePoint = std::chrono::system_clock::from_time_t(todayEndT);
185 if (newBeginTimePoint >= newEndTimePoint) {
186 newEndTimePoint += std::chrono::hours(HOURS_IN_ONE_DAY);
187 }
188
189 if (newEndTimePoint < now) {
190 newBeginTimePoint += std::chrono::hours(HOURS_IN_ONE_DAY);
191 newEndTimePoint += std::chrono::hours(HOURS_IN_ONE_DAY);
192 }
193
194 auto newBeginDuration = std::chrono::duration_cast<std::chrono::milliseconds>(newBeginTimePoint.time_since_epoch());
195 beginDate = newBeginDuration.count();
196
197 auto newEndDuration = std::chrono::duration_cast<std::chrono::milliseconds>(newEndTimePoint.time_since_epoch());
198 endDate = newEndDuration.count();
199 }
200
201 } // namespace Notification
202 } // namespace OHOS
203