1 /*
2  * Copyright (c) 2021-2024 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 #ifdef NOTIFICATION_SMART_REMINDER_SUPPORTED
16 #include "reminder_swing_decision_center.h"
17 #include "notification_preferences.h"
18 #include "smart_reminder_center.h"
19 #include "reminder_affected.h"
20 
21 namespace OHOS {
22 namespace Notification {
23 using namespace std;
24 mutex ReminderSwingDecisionCenter::swingMutex_;
25 sptr<ISwingCallBack> ReminderSwingDecisionCenter::swingCallback_ = nullptr;
26 
ReminderSwingDecisionCenter()27 ReminderSwingDecisionCenter::ReminderSwingDecisionCenter()
28 {}
29 
~ReminderSwingDecisionCenter()30 ReminderSwingDecisionCenter::~ReminderSwingDecisionCenter() {}
31 
GetInstance()32 ReminderSwingDecisionCenter &ReminderSwingDecisionCenter::GetInstance()
33 {
34     return DelayedRefSingleton<ReminderSwingDecisionCenter>::GetInstance();
35 }
36 
RegisterSwingCallback(const sptr<IRemoteObject> & swingCallback)37 ErrCode ReminderSwingDecisionCenter::RegisterSwingCallback(const sptr<IRemoteObject> &swingCallback)
38 {
39     if (swingCallback == nullptr) {
40         ANS_LOGW("swingCallback is null.");
41         return ERR_INVALID_VALUE;
42     }
43     swingRecipient_ = new (nothrow) SwingCallbackRecipient();
44     if (!swingRecipient_) {
45         ANS_LOGE("Failed to create death Recipient ptr SwingCallbackRecipient!");
46         return ERR_NO_INIT;
47     }
48     swingCallback->AddDeathRecipient(swingRecipient_);
49     lock_guard<mutex> lock(swingMutex_);
50     swingCallback_ = iface_cast<ISwingCallBack>(swingCallback);
51     ANS_LOGI("RegisterSwingCallback OK");
52     return ERR_OK;
53 }
54 
ResetSwingCallbackProxy()55 void ReminderSwingDecisionCenter::ResetSwingCallbackProxy()
56 {
57     ANS_LOGD("enter");
58     lock_guard<mutex> lock(swingMutex_);
59     if (swingCallback_ == nullptr || swingCallback_->AsObject() == nullptr) {
60         ANS_LOGE("invalid proxy state");
61         return;
62     }
63     swingCallback_->AsObject()->RemoveDeathRecipient(swingRecipient_);
64     swingCallback_ = nullptr;
65 }
66 
GetCcmSwingRemind()67 void ReminderSwingDecisionCenter::GetCcmSwingRemind()
68 {
69     nlohmann::json root;
70     string swingJsonPoint = "/";
71     swingJsonPoint.append(NotificationConfigParse::CFG_KEY_NOTIFICATION_SERVICE);
72     swingJsonPoint.append("/");
73     swingJsonPoint.append(SWING_FILTER);
74     swingJsonPoint.append("/");
75     swingJsonPoint.append(AFFTECED_BY);
76     isSupportSwingSmartRemind_ = false;
77     if (!NotificationConfigParse::GetInstance()->GetConfigJson(swingJsonPoint, root)) {
78         ANS_LOGI("Failed to get swingJsonPoint CCM config file.");
79         return;
80     }
81 
82     nlohmann::json affects = root[NotificationConfigParse::CFG_KEY_NOTIFICATION_SERVICE][SWING_FILTER][AFFTECED_BY];
83 
84     if (affects.is_null() || !affects.is_array() || affects.empty()) {
85         ANS_LOGI("GetCcmSwingRemind failed as invalid ccmSwingRemind json.");
86         return;
87     }
88 
89     for (auto &affect : affects) {
90         if (affect.is_null() || !affect.is_object()) {
91             continue;
92         }
93         if (affect[ReminderAffected::DEVICE_TYPE].is_null() ||
94             !affect[ReminderAffected::DEVICE_TYPE].is_string() ||
95             affect[ReminderAffected::STATUS].is_null() ||
96             !affect[ReminderAffected::STATUS].is_string()) {
97             continue;
98         }
99         enableSwingDeviceType_ = affect[ReminderAffected::DEVICE_TYPE].get<string>();
100         enableSwingDeviceStatus_ = affect[ReminderAffected::STATUS].get<string>();
101         ANS_LOGI("GetCcmSwingRemind deviceType: %{public}s  status: %{public}s", enableSwingDeviceType_.c_str(),
102             enableSwingDeviceStatus_.c_str());
103         isSupportSwingSmartRemind_ = true;
104     }
105 }
106 
GetSwingDeviceType()107 string ReminderSwingDecisionCenter::GetSwingDeviceType()
108 {
109     return enableSwingDeviceType_;
110 }
111 
UpdateCrossDeviceNotificationStatus(bool isEnable)112 void ReminderSwingDecisionCenter::UpdateCrossDeviceNotificationStatus(bool isEnable)
113 {
114     isCrossDeviceNotificationEnable_ = isEnable;
115     ANS_LOGD("UpdateCrossDeviceNotificationStatus %{public}d", isEnable);
116 }
117 
OnSmartReminderStatusChanged()118 void ReminderSwingDecisionCenter::OnSmartReminderStatusChanged()
119 {
120     SwingExecuteDecision(false);
121 }
122 
DisableSwingStatus()123 void ReminderSwingDecisionCenter::DisableSwingStatus()
124 {
125     if (!isSwingExecuting_) {
126         return;
127     }
128     isSwingExecuting_ = false;
129     lock_guard<mutex> lock(swingMutex_);
130     if (swingCallback_ == nullptr) {
131         return;
132     }
133     ANS_LOGD("DisableSwingStatus");
134     swingCallback_->OnUpdateStatus(false, NONE_UNLOCK_TRIGGER);
135 }
136 
SwingExecuteDecision(bool isScreenUnlockTrigger)137 void ReminderSwingDecisionCenter::SwingExecuteDecision(bool isScreenUnlockTrigger)
138 {
139     ANS_LOGD("SwingExecuteDecision");
140     if (!isSupportSwingSmartRemind_) {
141         ANS_LOGI("is not SupportSwingSmartRemind");
142         return;
143     }
144 
145     if (!isCrossDeviceNotificationEnable_) {
146         ANS_LOGI("crossDeviceNotification disable");
147         DisableSwingStatus();
148         return;
149     }
150 
151     bool isSmartReminderEnable = false;
152     if (ERR_OK != NotificationPreferences::GetInstance()->IsSmartReminderEnabled(enableSwingDeviceType_,
153         isSmartReminderEnable)) {
154         ANS_LOGI("IsSmartReminderEnable error");
155         return;
156     }
157 
158     if (!isSmartReminderEnable) {
159         ANS_LOGI("IsSmartReminderEnable false");
160         DisableSwingStatus();
161         return;
162     }
163     lock_guard<mutex> lock(swingMutex_);
164     if (swingCallback_ == nullptr) {
165         ANS_LOGI("swingCallback_ is null");
166         return;
167     }
168 
169     int triggerMode = isScreenUnlockTrigger ? UNLOCK_TRIGGER : NONE_UNLOCK_TRIGGER;
170     bool isSwingCrossDeviceStatusStatified = IsStatifySwingCrossDeviceStatus();
171     if (isScreenUnlock_ && isSwingCrossDeviceStatusStatified) {
172         if (!isSwingExecuting_) {
173             isSwingExecuting_ = true;
174             swingCallback_->OnUpdateStatus(true, triggerMode);
175             ANS_LOGI("swing OnUpdateStatus enable triggerMode %{public}d", triggerMode);
176         } else {
177             ANS_LOGD("isSwingExecuting_ %{public}d", isSwingExecuting_);
178         }
179     } else {
180         if (isSwingExecuting_) {
181             isSwingExecuting_ = false;
182             swingCallback_->OnUpdateStatus(false, triggerMode);
183             ANS_LOGI("swing OnUpdateStatus disable triggerMode %{public}d", triggerMode);
184         } else {
185             ANS_LOGD("isScreenUnlock_  %{public}d  isSwingCrossDeviceStatusStatified %{public}d ",
186                 isScreenUnlock_, isSwingCrossDeviceStatusStatified);
187         }
188     }
189 }
190 
IsStatifySwingCrossDeviceStatus()191 bool ReminderSwingDecisionCenter::IsStatifySwingCrossDeviceStatus()
192 {
193     uint32_t status =
194         DelayedSingleton<DistributedDeviceStatus>::GetInstance()->GetDeviceStatus(enableSwingDeviceType_);
195     bool isSatisfied = SmartReminderCenter::GetInstance()->CompareStatus(enableSwingDeviceStatus_, bitset<4>(status));
196     return isSatisfied;
197 }
198 
OnUpdateDeviceStatus(const std::string & deviceType)199 void ReminderSwingDecisionCenter::OnUpdateDeviceStatus(const std::string &deviceType)
200 {
201     if (deviceType.empty() || enableSwingDeviceType_.empty()) {
202         return;
203     }
204     if (deviceType.compare(enableSwingDeviceType_) == 0) {
205         SwingExecuteDecision(false);
206     }
207 }
208 
OnScreenLock()209 void ReminderSwingDecisionCenter::OnScreenLock()
210 {
211     ANS_LOGI("OnScreenLock");
212     if (isScreenUnlock_) {
213         isScreenUnlock_ = false;
214         SwingExecuteDecision(true);
215     }
216 }
217 
OnScreenUnlock()218 void ReminderSwingDecisionCenter::OnScreenUnlock()
219 {
220     ANS_LOGI("OnScreenUnlock");
221     if (!isScreenUnlock_) {
222         isScreenUnlock_ = true;
223         SwingExecuteDecision(true);
224     }
225 }
226 
OnRemoteDied(const wptr<IRemoteObject> & remote)227 void SwingCallbackRecipient::OnRemoteDied(const wptr<IRemoteObject> &remote)
228 {
229     ANS_LOGI("Swing Callback died, remove the proxy object");
230     ReminderSwingDecisionCenter::GetInstance().ResetSwingCallbackProxy();
231 }
232 
SwingCallbackRecipient()233 SwingCallbackRecipient::SwingCallbackRecipient() {}
234 
~SwingCallbackRecipient()235 SwingCallbackRecipient::~SwingCallbackRecipient() {}
236 }
237 }
238 #endif