1 /*
2 * Copyright (C) 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 // LCOV_EXCL_START
16 #include "accessibility_notification_helper.h"
17 #include "timer_info.h"
18 #include "time_service_client.h"
19
20 #include "notification_helper.h"
21 #include "want_agent_helper.h"
22 #include "want_agent_info.h"
23 #include "os_account_manager.h"
24
25 #include "hilog_wrapper.h"
26 #include "locale_config.h"
27 #include "locale_info.h"
28
29 #include <ctime>
30
31 #include "pixel_map.h"
32 #include "image_source.h"
33
34 namespace OHOS {
35 namespace Accessibility {
36
37 namespace {
38 constexpr uint64_t TWELVE_CLOCK = 12 * 60 * 60 * 1000;
39 constexpr uint64_t NOTIFICATION_DATA_2 = 2 * 24 * 60 * 60 * 1000;
40 constexpr uint64_t NOTIFICATION_DATA_5 = 5 * 24 * 60 * 60 * 1000;
41 constexpr uint64_t NOTIFICATION_DATA_8 = 8 * 24 * 60 * 60 * 1000;
42 constexpr uint64_t NOTIFICATION_DATA_15 = 15 * 24 * 60 * 60 * 1000;
43 constexpr uint64_t NOTIFICATION_DATA_22 = 22 * 24 * 60 * 60 * 1000;
44 constexpr uint64_t NOTIFICATION_DATA_30 = static_cast<uint64_t>(29) * static_cast<uint64_t>(24) *
45 static_cast<uint64_t>(60) * static_cast<uint64_t>(60) *
46 static_cast<uint64_t>(1000);
47 std::vector<uint64_t> NOTIFICATION_DATE{NOTIFICATION_DATA_2,
48 NOTIFICATION_DATA_5,
49 NOTIFICATION_DATA_8,
50 NOTIFICATION_DATA_15,
51 NOTIFICATION_DATA_22,
52 NOTIFICATION_DATA_30};
53
54 const std::string SETTING_BUNDLE_NAME = "com.ohos.settings";
55 const std::string SETTING_ABILITY_NAME = "com.ohos.settings.MainAbility";
56 const std::string SERVICE_EXTENSION_ABILITY_NAME = "IgnoreRepeatClickExtService";
57 const std::string ACCESSIBILITY_SCREEN_TOUCH_URI = "accessibility_touchscreen_entry";
58 const std::string HAP_PATH = "/system/app/Settings/Settings.hap";
59 const std::string ICON_NAME = "ic_accessibility_notify";
60 const std::string IGNORE_REPEAT_CLICK_NOTIFICATION = "ignore_repeat_click_notification";
61 constexpr int32_t REQUEST_CODE = 8;
62 const std::string IGNORE_REPEAT_CLICK_NOTIFICATION_TITLE = "ignore_repeat_click_notification_title";
63 const std::string IGNORE_REPEAT_CLICK_NOTIFICATION_CONTENT = "ignore_repeat_click_notification_content";
64 const std::string IGNORE_REPEAT_CLICK_NOTIFICATION_CONTENT_BUTTON_CANCEL =
65 "ignore_repeat_click_notification_button_cancel";
66 const std::string IGNORE_REPEAT_CLICK_NOTIFICATION_CONTENT_BUTTON_DISABLE =
67 "ignore_repeat_click_notification_button_disable";
68 const std::string INGORE_REPEAT_CLICK_KEY = "ignore_repeat_click_switch";
69 constexpr int ACCESSIBILITY_SA_UID = 1103;
70 constexpr int ACCESSIBILITY_NOTIFICATION_UID = 1103801;
71 constexpr uint32_t NOTIFICATION_FLAG = 1 << 9;
72 constexpr float ICON_SIZE = 0.3;
73
74 std::map<std::string, std::string> notificationMap_ = {{IGNORE_REPEAT_CLICK_NOTIFICATION_TITLE, ""},
75 {IGNORE_REPEAT_CLICK_NOTIFICATION_CONTENT, ""},
76 {IGNORE_REPEAT_CLICK_NOTIFICATION_CONTENT_BUTTON_CANCEL, ""},
77 {IGNORE_REPEAT_CLICK_NOTIFICATION_CONTENT_BUTTON_DISABLE, ""}};
78
79 std::vector<uint64_t> timersVec;
80 } // namespace
81
GetWantAgent()82 static std::shared_ptr<OHOS::AbilityRuntime::WantAgent::WantAgent> GetWantAgent()
83 {
84 std::shared_ptr<OHOS::AAFwk::Want> want = std::make_shared<OHOS::AAFwk::Want>();
85 want->SetElementName(SETTING_BUNDLE_NAME, SERVICE_EXTENSION_ABILITY_NAME);
86 want->SetAction("disableIgnoreRepeatClick");
87 std::vector<std::shared_ptr<OHOS::AAFwk::Want>> wants;
88 wants.push_back(want);
89 std::vector<OHOS::AbilityRuntime::WantAgent::WantAgentConstant::Flags> flags;
90 flags.push_back(OHOS::AbilityRuntime::WantAgent::WantAgentConstant::Flags::UPDATE_PRESENT_FLAG);
91 OHOS::AbilityRuntime::WantAgent::WantAgentInfo wantAgentInfo(REQUEST_CODE,
92 AbilityRuntime::WantAgent::WantAgentConstant::OperationType::START_ABILITY,
93 flags,
94 wants,
95 nullptr);
96 return OHOS::AbilityRuntime::WantAgent::WantAgentHelper::GetWantAgent(wantAgentInfo);
97 }
98
GetCanceluttonWantAgent()99 static std::shared_ptr<OHOS::AbilityRuntime::WantAgent::WantAgent> GetCanceluttonWantAgent()
100 {
101 std::shared_ptr<OHOS::AAFwk::Want> want = std::make_shared<OHOS::AAFwk::Want>();
102 want->SetAction("disableNotificaiton");
103 want->SetElementName(SETTING_BUNDLE_NAME, SERVICE_EXTENSION_ABILITY_NAME);
104
105 std::vector<std::shared_ptr<OHOS::AAFwk::Want>> wants;
106 wants.push_back(want);
107 std::vector<OHOS::AbilityRuntime::WantAgent::WantAgentConstant::Flags> flags;
108 flags.push_back(OHOS::AbilityRuntime::WantAgent::WantAgentConstant::Flags::UPDATE_PRESENT_FLAG);
109 OHOS::AbilityRuntime::WantAgent::WantAgentInfo wantAgentInfo(REQUEST_CODE,
110 AbilityRuntime::WantAgent::WantAgentConstant::OperationType::START_ABILITY,
111 flags,
112 wants,
113 nullptr);
114 return OHOS::AbilityRuntime::WantAgent::WantAgentHelper::GetWantAgent(wantAgentInfo);
115 }
116
GetSettingsWantAgent()117 static std::shared_ptr<OHOS::AbilityRuntime::WantAgent::WantAgent> GetSettingsWantAgent()
118 {
119 std::shared_ptr<OHOS::AAFwk::Want> want = std::make_shared<OHOS::AAFwk::Want>();
120 want->SetElementName(SETTING_BUNDLE_NAME, SETTING_ABILITY_NAME);
121 want->SetUri(ACCESSIBILITY_SCREEN_TOUCH_URI);
122 std::vector<std::shared_ptr<OHOS::AAFwk::Want>> wants;
123 wants.push_back(want);
124 std::vector<OHOS::AbilityRuntime::WantAgent::WantAgentConstant::Flags> flags;
125 flags.push_back(OHOS::AbilityRuntime::WantAgent::WantAgentConstant::Flags::UPDATE_PRESENT_FLAG);
126 OHOS::AbilityRuntime::WantAgent::WantAgentInfo wantAgentInfo(REQUEST_CODE,
127 AbilityRuntime::WantAgent::WantAgentConstant::OperationType::START_ABILITY,
128 flags,
129 wants,
130 nullptr);
131 return OHOS::AbilityRuntime::WantAgent::WantAgentHelper::GetWantAgent(wantAgentInfo);
132 }
133
134
GetIcon()135 static std::shared_ptr<OHOS::Media::PixelMap> GetIcon()
136 {
137 std::shared_ptr<Global::Resource::ResourceManager> resourceManager(Global::Resource::CreateResourceManager());
138 if (resourceManager == nullptr) {
139 HILOG_ERROR("resourceManager is null");
140 return nullptr;
141 }
142 if (!resourceManager->AddResource(HAP_PATH.c_str())) {
143 HILOG_ERROR("AddResource failed");
144 return nullptr;
145 }
146 size_t len = 0;
147 std::unique_ptr<uint8_t[]> data;
148 resourceManager->GetMediaDataByName(ICON_NAME.c_str(), len, data);
149 Media::SourceOptions opts;
150 uint32_t errorCode = 0;
151 std::unique_ptr<Media::ImageSource> imageSource =
152 Media::ImageSource::CreateImageSource(data.get(), len, opts, errorCode);
153 Media::DecodeOptions decodeOpts;
154 std::shared_ptr<OHOS::Media::PixelMap> icon;
155 if (imageSource) {
156 auto pixelMapPtr = imageSource->CreatePixelMap(decodeOpts, errorCode);
157 icon = std::shared_ptr<Media::PixelMap>(pixelMapPtr.release());
158 }
159 if (errorCode != 0) {
160 HILOG_ERROR("Failed to get icon");
161 return nullptr;
162 }
163 if (icon == nullptr) {
164 HILOG_ERROR("icon is null");
165 return nullptr;
166 }
167 icon->scale(ICON_SIZE, ICON_SIZE);
168 return icon;
169 }
170
GetReource()171 static void GetReource()
172 {
173 std::shared_ptr<Global::Resource::ResourceManager> resourceManager(Global::Resource::CreateResourceManager());
174 if (resourceManager == nullptr) {
175 HILOG_ERROR("resourceManager is null");
176 return;
177 }
178 std::unique_ptr<Global::Resource::ResConfig> resConfig(Global::Resource::CreateResConfig());
179 if (resConfig == nullptr) {
180 HILOG_ERROR("resConfig is null");
181 return;
182 }
183 std::map<std::string, std::string> configs;
184 OHOS::Global::I18n::LocaleInfo locale(Global::I18n::LocaleConfig::GetSystemLocale(), configs);
185 std::string language = locale.GetLanguage();
186 std::string script = locale.GetScript();
187 std::string region = locale.GetRegion();
188
189 resConfig->SetLocaleInfo(language.c_str(), script.c_str(), region.c_str());
190 resourceManager->UpdateResConfig(*resConfig);
191 if (!resourceManager->AddResource(HAP_PATH.c_str())) {
192 HILOG_ERROR("AddResource failed");
193 return;
194 }
195 for (auto &iter : notificationMap_) {
196 std::string outValue;
197 resourceManager->GetStringByName(iter.first.c_str(), outValue);
198 HILOG_ERROR("outValue = %{public}s", outValue.c_str());
199 notificationMap_[iter.first] = outValue;
200 }
201 }
202
CancelNotification()203 void IgnoreRepeatClickNotification::CancelNotification()
204 {
205 Notification::NotificationHelper::CancelNotification(ACCESSIBILITY_NOTIFICATION_UID);
206 }
207
PublishIgnoreRepeatClickReminder()208 int32_t IgnoreRepeatClickNotification::PublishIgnoreRepeatClickReminder()
209 {
210 GetReource();
211 Notification::NotificationRequest request;
212 std::shared_ptr<Notification::NotificationActionButton> cancelButtion =
213 Notification::NotificationActionButton::Create(nullptr,
214 notificationMap_[IGNORE_REPEAT_CLICK_NOTIFICATION_CONTENT_BUTTON_CANCEL],
215 GetCanceluttonWantAgent());
216 request.AddActionButton(cancelButtion);
217 std::shared_ptr<Notification::NotificationActionButton> closeButton =
218 Notification::NotificationActionButton::Create(
219 nullptr, notificationMap_[IGNORE_REPEAT_CLICK_NOTIFICATION_CONTENT_BUTTON_DISABLE], GetWantAgent());
220 request.AddActionButton(closeButton);
221
222 std::shared_ptr<Notification::NotificationLongTextContent> content =
223 std::make_shared<Notification::NotificationLongTextContent>();
224 content->SetTitle(notificationMap_[IGNORE_REPEAT_CLICK_NOTIFICATION_TITLE]);
225 content->SetLongText(notificationMap_[IGNORE_REPEAT_CLICK_NOTIFICATION_CONTENT]);
226 std::shared_ptr<Notification::NotificationContent> notificationContent =
227 std::make_shared<Notification::NotificationContent>(content);
228 request.SetContent(notificationContent);
229 request.SetCreatorUid(ACCESSIBILITY_SA_UID);
230 request.SetCreatorPid(getpid());
231 int32_t userId;
232 AccountSA::OsAccountManager::GetOsAccountLocalIdFromUid(ACCESSIBILITY_SA_UID, userId);
233
234 request.SetCreatorUserId(userId);
235 request.SetCreatorBundleName("");
236 request.SetSlotType(OHOS::Notification::NotificationConstant::SlotType::SERVICE_REMINDER);
237 request.SetInProgress(true);
238 request.SetDistributed(true);
239 request.SetNotificationControlFlags(NOTIFICATION_FLAG);
240 request.SetNotificationId(ACCESSIBILITY_NOTIFICATION_UID);
241
242 auto icon = GetIcon();
243 if (icon) {
244 request.SetLittleIcon(icon);
245 }
246
247 request.SetWantAgent(GetSettingsWantAgent());
248
249 ErrCode ret = Notification::NotificationHelper::PublishNotification(request);
250 HILOG_ERROR("PublishReminder ret = %{public}d", ret);
251 return 0;
252 }
253
RegisterTimers(uint64_t beginTime)254 int32_t IgnoreRepeatClickNotification::RegisterTimers(uint64_t beginTime)
255 {
256 uint64_t millisecondsToMidnight = CalculateTimeToMidnight(beginTime);
257 for (const auto &interval : NOTIFICATION_DATE) {
258 uint64_t intervalMs = millisecondsToMidnight + TWELVE_CLOCK + interval + beginTime;
259 std::shared_ptr<TimerInfo> timer = std::make_shared<TimerInfo>();
260 timer->SetCallbackInfo(TimerCallback);
261 timer->SetDisposable(true);
262 timer->SetType(
263 static_cast<uint32_t>(timer->TIMER_TYPE_EXACT) | static_cast<uint32_t>(timer->TIMER_TYPE_WAKEUP));
264 uint64_t timerId = MiscServices::TimeServiceClient::GetInstance()->CreateTimer(timer);
265 if (!timerId) {
266 HILOG_ERROR("createTimerFailed");
267 continue;
268 }
269 HILOG_INFO("timeId = %{public}" PRId64 "", timerId);
270 MiscServices::TimeServiceClient::GetInstance()->StartTimer(timerId, intervalMs);
271 timersVec.emplace_back(timerId);
272 }
273 return 0;
274 }
275
CalculateTimeToMidnight(uint64_t nowTime)276 uint64_t IgnoreRepeatClickNotification::CalculateTimeToMidnight(uint64_t nowTime)
277 {
278 time_t nowSec = static_cast<int64_t>(nowTime / 1000);
279 struct tm *utcTime = gmtime((const time_t *)&nowSec);
280 if (!utcTime) {
281 return 0;
282 }
283
284 utcTime->tm_hour = 0;
285 utcTime->tm_min = 0;
286 utcTime->tm_sec = 0;
287 utcTime->tm_mday += 1;
288 time_t midnight_seconds = mktime(utcTime);
289 if (midnight_seconds < 0) {
290 return 0;
291 }
292 uint64_t midnight_millis = (uint64_t)midnight_seconds * 1000;
293 if (midnight_millis > nowTime) {
294 uint64_t millisecondsToMidnight = midnight_millis - nowTime;
295 return millisecondsToMidnight;
296 } else {
297 return 0;
298 }
299 }
300
TimerCallback()301 void IgnoreRepeatClickNotification::TimerCallback()
302 {
303 IgnoreRepeatClickNotification::PublishIgnoreRepeatClickReminder();
304 HILOG_ERROR("IgnoreRepeatClickNotification::TimerCallback");
305 }
306
DestoryTimers()307 void IgnoreRepeatClickNotification::DestoryTimers()
308 {
309 for (const auto &timerId : timersVec) {
310 MiscServices::TimeServiceClient::GetInstance()->DestroyTimer(timerId);
311 }
312 timersVec.clear();
313 }
314 } // namespace Accessibility
315 } // namespace OHOS
316 // LCOV_EXCL_STOP