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 #include "ani_request_enable.h"
16
17 #include "ani_ans_dialog_callback.h"
18 #include "ans_log_wrapper.h"
19 #include "ets_error_utils.h"
20 #include "notification_helper.h"
21 #include "ani_common_util.h"
22 #include "sts_throw_erro.h"
23
24 namespace OHOS {
25 namespace NotificationManagerSts {
26 using namespace OHOS::Notification;
GetEnableNotificationInfo(ani_env * env,ani_object content,std::shared_ptr<EnableNotificationInfo> & info)27 bool GetEnableNotificationInfo(ani_env *env, ani_object content, std::shared_ptr<EnableNotificationInfo> &info)
28 {
29 ANS_LOGD("enter");
30 if (content == nullptr) {
31 ANS_LOGD("content is null");
32 return true;
33 }
34 ani_status status = ANI_OK;
35 ani_boolean stageMode = ANI_FALSE;
36 status = OHOS::AbilityRuntime::IsStageContext(env, content, stageMode);
37 ANS_LOGD("status %{public}d, stageMode %{public}d", status, stageMode);
38 if (ANI_OK != status || stageMode != ANI_TRUE) {
39 ANS_LOGE("Only support stage mode");
40 std::string msg = "Incorrect parameter types.Only support stage mode.";
41 OHOS::NotificationSts::ThrowError(env, ERROR_PARAM_INVALID, msg);
42 return false;
43 }
44 info->stageMode = true;
45 info->context = OHOS::AbilityRuntime::GetStageModeContext(env, content);
46 if (info->context != nullptr) {
47 info->callerToken = info->context->GetToken();
48 }
49 return true;
50 }
51
RequestEnableExecute(std::shared_ptr<EnableNotificationInfo> & info)52 void RequestEnableExecute(std::shared_ptr<EnableNotificationInfo> &info)
53 {
54 ANS_LOGD("enter");
55 sptr<AnsDialogHostClient> client = nullptr;
56 if (!AnsDialogHostClient::CreateIfNullptr(client)) {
57 ANS_LOGD("create client fail");
58 info->errorCode = ERR_ANS_DIALOG_IS_POPPING;
59 return;
60 }
61 if (client == nullptr) {
62 ANS_LOGD("client is nullptr");
63 info->errorCode = ERROR_INTERNAL_ERROR;
64 return;
65 }
66 if (info->context != nullptr) {
67 ANS_LOGD("stage mode");
68 bool canPop = false;
69 std::string bundleName = "";
70 ErrCode errCode = NotificationHelper::CanPopEnableNotificationDialog(client, canPop, bundleName);
71 ANS_LOGI("CanPopEnableNotificationDialog result , errCode = %{public}d , canPop = %{public}d",
72 errCode, canPop);
73 if (canPop == false) {
74 info->errorCode = errCode;
75 AnsDialogHostClient::Destroy();
76 return;
77 }
78 info->bundleName = bundleName;
79 } else {
80 ANS_LOGD("un stage mode");
81 std::string deviceId {""};
82 info->errorCode = NotificationHelper::RequestEnableNotification(deviceId, client, info->callerToken);
83 }
84 ANS_LOGI("ipcCall done, code is %{public}d.", info->errorCode);
85 }
86
StsAsyncCompleteCallbackRequestEnableNotification(ani_env * env,std::shared_ptr<EnableNotificationInfo> info)87 void StsAsyncCompleteCallbackRequestEnableNotification(ani_env *env, std::shared_ptr<EnableNotificationInfo> info)
88 {
89 ANS_LOGD("enter");
90 if (env == nullptr || info == nullptr) return;
91 ani_status status;
92 int32_t errorCode = info->errorCode ==
93 ERR_OK ? ERR_OK : NotificationSts::GetExternalCode(info->errorCode);
94 if (errorCode == ERR_OK) {
95 ANS_LOGD("Resolve. errorCode %{public}d", errorCode);
96 ani_object ret = OHOS::AppExecFwk::CreateInt(env, errorCode);
97 if (ret == nullptr) {
98 ANS_LOGD("createInt faild");
99 return;
100 }
101 if (ANI_OK != (status = env->PromiseResolver_Resolve(info->resolver, static_cast<ani_ref>(ret)))) {
102 ANS_LOGD("PromiseResolver_Resolve faild. status %{public}d", status);
103 }
104 } else {
105 std::string errMsg = OHOS::NotificationSts::FindAnsErrMsg(errorCode);
106 ANS_LOGD("reject. errorCode %{public}d errMsg %{public}s", errorCode, errMsg.c_str());
107 ani_error rejection =
108 static_cast<ani_error>(OHOS::AbilityRuntime::EtsErrorUtil::CreateError(env, errorCode, errMsg));
109 if (ANI_OK != (status = env->PromiseResolver_Reject(info->resolver, rejection))) {
110 ANS_LOGD("PromiseResolver_Resolve faild. status %{public}d", status);
111 }
112 }
113 }
114
CreateUIExtension(std::shared_ptr<EnableNotificationInfo> & info)115 bool CreateUIExtension(std::shared_ptr<EnableNotificationInfo> &info)
116 {
117 ANS_LOGD("enter");
118 if (info->context == nullptr) {
119 ANS_LOGE("Get context failed");
120 return false;
121 }
122 std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext =
123 OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(info->context);
124 if (abilityContext == nullptr) {
125 ANS_LOGE("abilityContext is null");
126 return false;
127 }
128 auto uiContent = abilityContext->GetUIContent();
129 if (uiContent == nullptr) {
130 ANS_LOGE("uiContent is null");
131 return false;
132 }
133 AAFwk::Want want;
134 std::string targetBundleName = "com.ohos.notificationdialog";
135 std::string targetAbilityName = "EnableNotificationDialog";
136 want.SetElementName(targetBundleName, targetAbilityName);
137 std::string typeKey = "ability.want.params.uiExtensionType";
138 std::string typeValue = "sysDialog/common";
139 want.SetParam(typeKey, typeValue);
140 auto uiExtCallback = std::make_shared<ModalExtensionCallback>();
141 uiExtCallback->SetAbilityContext(abilityContext);
142 uiExtCallback->SetBundleName(info->bundleName);
143 OHOS::Ace::ModalUIExtensionCallbacks uiExtensionCallbacks = {
144 .onRelease = std::bind(&ModalExtensionCallback::OnRelease, uiExtCallback, std::placeholders::_1),
145 .onResult = std::bind(&ModalExtensionCallback::OnResult, uiExtCallback,
146 std::placeholders::_1, std::placeholders::_2),
147 .onReceive = std::bind(&ModalExtensionCallback::OnReceive, uiExtCallback, std::placeholders::_1),
148 .onError = std::bind(&ModalExtensionCallback::OnError, uiExtCallback,
149 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3),
150 .onRemoteReady = std::bind(&ModalExtensionCallback::OnRemoteReady, uiExtCallback, std::placeholders::_1),
151 .onDestroy = std::bind(&ModalExtensionCallback::OnDestroy, uiExtCallback),
152 };
153 OHOS::Ace::ModalUIExtensionConfig config;
154 config.isProhibitBack = true;
155 int32_t sessionId = uiContent->CreateModalUIExtension(want, uiExtensionCallbacks, config);
156 ANS_LOGI("Create end, sessionId: %{public}d", sessionId);
157 if (sessionId == 0) {
158 ANS_LOGE("Create component failed, sessionId is 0");
159 return false;
160 }
161 uiExtCallback->SetSessionId(sessionId);
162 return true;
163 }
164
RequestEnableComplete(ani_env * env,std::shared_ptr<EnableNotificationInfo> & info)165 void RequestEnableComplete(ani_env *env, std::shared_ptr<EnableNotificationInfo> &info)
166 {
167 ANS_LOGD("enter");
168 if (!info->bundleName.empty()) {
169 bool success = CreateUIExtension(info);
170 if (success) {
171 info->errorCode = ERR_ANS_DIALOG_POP_SUCCEEDED;
172 } else {
173 info->errorCode = ERROR_INTERNAL_ERROR;
174 AnsDialogHostClient::Destroy();
175 NotificationHelper::RemoveEnableNotificationDialog();
176 }
177 }
178 if (info->errorCode != ERR_ANS_DIALOG_POP_SUCCEEDED) {
179 ANS_LOGE("error, code is %{public}d.", info->errorCode);
180 AnsDialogHostClient::Destroy();
181 StsAsyncCompleteCallbackRequestEnableNotification(env, info);
182 return;
183 }
184 // Dialog is popped
185 auto StsCallback = std::make_unique<StsAnsDialogCallback>();
186 if (!StsCallback->Init(env, info, StsAsyncCompleteCallbackRequestEnableNotification) ||
187 !AnsDialogHostClient::SetDialogCallbackInterface(std::move(StsCallback))
188 ) {
189 ANS_LOGE("error");
190 AnsDialogHostClient::Destroy();
191 info->errorCode = ERROR_INTERNAL_ERROR;
192 StsAsyncCompleteCallbackRequestEnableNotification(env, info);
193 return;
194 }
195 }
196
AniRequestEnableNotification(ani_env * env,ani_object content)197 ani_object AniRequestEnableNotification(ani_env *env, ani_object content)
198 {
199 ANS_LOGD("enter");
200 std::shared_ptr<EnableNotificationInfo> info = std::make_shared<EnableNotificationInfo>();
201 if (!GetEnableNotificationInfo(env, content, info)) {
202 ANS_LOGD("GetEnableNotificationInfo");
203 return nullptr;
204 }
205 ani_object aniPromise {};
206 ani_resolver aniResolver {};
207 if (ANI_OK != env->Promise_New(&aniResolver, &aniPromise)) {
208 ANS_LOGD("Promise_New faild");
209 return nullptr;
210 }
211 info->resolver = aniResolver;
212 RequestEnableExecute(info);
213 RequestEnableComplete(env, info);
214 ANS_LOGD("RequestEnableNotification done");
215 return aniPromise;
216 }
217 }
218 }