• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #include "ani_open_settings.h"
17 
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 #include "ani_ans_dialog_callback.h"
24 
25 namespace OHOS {
26 namespace NotificationManagerSts {
27 using namespace OHOS::Notification;
28 static std::atomic<bool> isExist = false;
29 const int32_t ERR__INVALID_WANT = 1011;
GetOpenSettingsInfo(ani_env * env,ani_object content,std::shared_ptr<OpenSettingsInfo> & info)30 bool GetOpenSettingsInfo(ani_env *env, ani_object content, std::shared_ptr<OpenSettingsInfo> &info)
31 {
32     ANS_LOGD("enter");
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         ANS_LOGE("sts GetOpenSettingsInfo ERROR_PARAM_INVALID");
42         OHOS::NotificationSts::ThrowError(env, ERROR_PARAM_INVALID, msg);
43         return false;
44     }
45     info->context = OHOS::AbilityRuntime::GetStageModeContext(env, content);
46     return true;
47 }
48 
CreateUiExtCallback(ani_env * env,std::shared_ptr<SettingsModalExtensionCallback> & uiExtCallback,Ace::ModalUIExtensionCallbacks & uiExtensionCallbacks,std::shared_ptr<OpenSettingsInfo> & info,std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> & abilityContext,std::string & bundleName)49 bool CreateUiExtCallback(ani_env *env, std::shared_ptr<SettingsModalExtensionCallback>& uiExtCallback,
50     Ace::ModalUIExtensionCallbacks& uiExtensionCallbacks, std::shared_ptr<OpenSettingsInfo> &info,
51     std::shared_ptr<OHOS::AbilityRuntime::AbilityContext>& abilityContext, std::string &bundleName)
52 {
53     if (!uiExtCallback->Init(env, info, StsAsyncCompleteCallbackOpenSettings)) {
54         ANS_LOGE("error");
55         info->errorCode = OHOS::Notification::ERROR_INTERNAL_ERROR;
56         StsAsyncCompleteCallbackOpenSettings(env, info);
57         return false;
58     }
59     uiExtCallback->SetAbilityContext(abilityContext);
60     uiExtCallback->SetBundleName(bundleName);
61     uiExtensionCallbacks = {
62         .onRelease =
63             std::bind(&SettingsModalExtensionCallback::OnRelease, uiExtCallback, std::placeholders::_1),
64         .onResult = std::bind(&SettingsModalExtensionCallback::OnResult, uiExtCallback,
65             std::placeholders::_1, std::placeholders::_2),
66         .onReceive =
67             std::bind(&SettingsModalExtensionCallback::OnReceive, uiExtCallback, std::placeholders::_1),
68         .onError = std::bind(&SettingsModalExtensionCallback::OnError, uiExtCallback,
69             std::placeholders::_1, std::placeholders::_2, std::placeholders::_3),
70         .onRemoteReady =
71             std::bind(&SettingsModalExtensionCallback::OnRemoteReady, uiExtCallback, std::placeholders::_1),
72         .onDestroy = std::bind(&SettingsModalExtensionCallback::OnDestroy, uiExtCallback),
73     };
74     return true;
75 }
76 
CreateSettingsUIExtension(std::shared_ptr<OHOS::AbilityRuntime::Context> context,std::string & bundleName,ani_env * env,std::shared_ptr<OpenSettingsInfo> & info)77 bool CreateSettingsUIExtension(std::shared_ptr<OHOS::AbilityRuntime::Context> context, std::string &bundleName,
78     ani_env *env, std::shared_ptr<OpenSettingsInfo> &info)
79 {
80     if (context == nullptr) {
81         ANS_LOGE("Get context failed");
82         return false;
83     }
84 
85     std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext =
86         OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
87     if (abilityContext == nullptr) {
88         ANS_LOGE("abilityContext is null");
89         return false;
90     }
91     auto uiContent = abilityContext->GetUIContent();
92     if (uiContent == nullptr) {
93         ANS_LOGE("uiContent is null");
94         return false;
95     }
96 
97     AAFwk::Want want;
98     std::string targetBundleName = "com.ohos.sceneboard";
99     std::string targetAbilityName = "NotificationManangerUIExtensionAbility";
100     want.SetElementName(targetBundleName, targetAbilityName);
101 
102     std::string typeKey = "ability.want.params.uiExtensionType";
103     std::string typeValue = "sys/commonUI";
104     want.SetParam(typeKey, typeValue);
105 
106     auto uiExtCallback = std::make_shared<SettingsModalExtensionCallback>();
107     Ace::ModalUIExtensionCallbacks uiExtensionCallbacks;
108     if (!CreateUiExtCallback(env, uiExtCallback, uiExtensionCallbacks, info, abilityContext,
109         bundleName)) {
110         ANS_LOGE("CreateUiExtCallback fail");
111         return false;
112     }
113 
114     Ace::ModalUIExtensionConfig config;
115     config.isProhibitBack = true;
116 
117     int32_t sessionId = uiContent->CreateModalUIExtension(want, uiExtensionCallbacks, config);
118     ANS_LOGI("Create end, sessionId: %{public}d", sessionId);
119     if (sessionId == 0) {
120         ANS_LOGE("Create component failed, sessionId is 0");
121         return false;
122     }
123     uiExtCallback->SetSessionId(sessionId);
124     return true;
125 }
126 
StsAsyncCompleteCallbackOpenSettings(ani_env * env,std::shared_ptr<OpenSettingsInfo> info)127 void StsAsyncCompleteCallbackOpenSettings(ani_env *env, std::shared_ptr<OpenSettingsInfo> info)
128 {
129     ANS_LOGD("enter");
130     if (env == nullptr) {
131         ANS_LOGD("env is null");
132         return;
133     }
134     ani_status status;
135     int32_t errorCode = ERR_OK;
136     if (info->errorCode == OHOS::Notification::ERROR_SETTING_WINDOW_EXIST) {
137         errorCode = OHOS::Notification::ERROR_SETTING_WINDOW_EXIST;
138     } else if (info->errorCode == ERR__INVALID_WANT) {
139         errorCode = ERR__INVALID_WANT;
140     } else {
141         errorCode = info->errorCode ==
142             ERR_OK ? ERR_OK : NotificationSts::GetExternalCode(info->errorCode);
143     }
144 
145     if (errorCode == ERR_OK) {
146         ANS_LOGD("Resolve. errorCode %{public}d", errorCode);
147         ani_object ret = OHOS::AppExecFwk::CreateInt(env, errorCode);
148         if (ret == nullptr) {
149             ANS_LOGD("createInt faild");
150             NotificationSts::ThrowErrorWithMsg(env, "");
151             return;
152         }
153         if (ANI_OK != (status = env->PromiseResolver_Resolve(info->resolver, static_cast<ani_ref>(ret)))) {
154             ANS_LOGD("PromiseResolver_Resolve faild. status %{public}d", status);
155             NotificationSts::ThrowErrorWithMsg(env, "");
156         }
157     } else {
158         std::string errMsg = OHOS::NotificationSts::FindAnsErrMsg(errorCode);
159         ANS_LOGD("reject. errorCode %{public}d errMsg %{public}s", errorCode, errMsg.c_str());
160         ani_error rejection =
161             static_cast<ani_error>(OHOS::AbilityRuntime::EtsErrorUtil::CreateError(env, errorCode, errMsg));
162         if (ANI_OK != (status = env->PromiseResolver_Reject(info->resolver, rejection))) {
163             ANS_LOGD("PromiseResolver_Resolve faild. status %{public}d", status);
164             NotificationSts::ThrowErrorWithMsg(env, "");
165         }
166     }
167 }
168 
AniOpenNotificationSettings(ani_env * env,ani_object content)169 ani_object AniOpenNotificationSettings(ani_env *env, ani_object content)
170 {
171     ANS_LOGD("sts AniOpenNotificationSettings call");
172     std::shared_ptr<OpenSettingsInfo> info = std::make_shared<OpenSettingsInfo>();
173     if (!GetOpenSettingsInfo(env, content, info)) {
174         ANS_LOGE("sts AniOpenNotificationSettings GetOpenSettingsInfo fail");
175         return nullptr;
176     }
177     if (info->context == nullptr) {
178         ANS_LOGE("sts AniOpenNotificationSettings context is null");
179         NotificationSts::ThrowErrorWithMsg(env, "");
180         return nullptr;
181     }
182     std::string bundleName {""};
183     if (isExist.exchange(true)) {
184         ANS_LOGE("sts AniOpenNotificationSettings ERROR_SETTING_WINDOW_EXIST");
185         OHOS::NotificationSts::ThrowError(env, OHOS::Notification::ERROR_SETTING_WINDOW_EXIST,
186             NotificationSts::FindAnsErrMsg(OHOS::Notification::ERROR_SETTING_WINDOW_EXIST));
187         return nullptr;
188     }
189     ani_object aniPromise {};
190     ani_resolver aniResolver {};
191     if (ANI_OK != env->Promise_New(&aniResolver, &aniPromise)) {
192         ANS_LOGD("Promise_New faild");
193         return nullptr;
194     }
195     info->resolver = aniResolver;
196     bool success = CreateSettingsUIExtension(info->context, bundleName, env, info);
197     if (success) {
198         info->errorCode = OHOS::Notification::ERR_ANS_DIALOG_POP_SUCCEEDED;
199     } else {
200         info->errorCode = OHOS::Notification::ERROR_INTERNAL_ERROR;
201     }
202     if (info->errorCode != ERR_ANS_DIALOG_POP_SUCCEEDED) {
203         ANS_LOGE("error, code is %{public}d.", info->errorCode);
204         StsAsyncCompleteCallbackOpenSettings(env, info);
205         isExist.store(false);
206         return nullptr;
207     }
208     ANS_LOGD("sts AniOpenNotificationSettings end");
209 
210     return aniPromise;
211 }
212 
SettingsModalExtensionCallback()213 SettingsModalExtensionCallback::SettingsModalExtensionCallback()
214 {}
215 
~SettingsModalExtensionCallback()216 SettingsModalExtensionCallback::~SettingsModalExtensionCallback()
217 {}
218 
Init(ani_env * env,std::shared_ptr<OpenSettingsInfo> info,StsSettingsModalExtensionCallbackComplete * complete)219 bool SettingsModalExtensionCallback::Init(ani_env *env, std::shared_ptr<OpenSettingsInfo> info,
220     StsSettingsModalExtensionCallbackComplete *complete)
221 {
222     if (env == nullptr || info == nullptr || complete == nullptr) {
223         ANS_LOGE("invalid data");
224         return false;
225     }
226     ani_status status = ANI_OK;
227     if ((status = env->GetVM(&vm_)) != ANI_OK) {
228         ANS_LOGD("GetVM faild. status %{public}d", status);
229         return false;
230     }
231     info_ = info;
232     complete_ = complete;
233     return true;
234 }
235 
ProcessStatusChanged(int32_t code,bool isAsync)236 void SettingsModalExtensionCallback::ProcessStatusChanged(int32_t code, bool isAsync)
237 {
238     ANS_LOGD("enter");
239     if (vm_ == nullptr || info_ == nullptr || complete_ == nullptr) {
240         ANS_LOGE("invalid data");
241         AnsDialogHostClient::Destroy();
242         return;
243     }
244     info_->errorCode = code;
245 
246     ani_env* env;
247     ani_status aniResult = ANI_ERROR;
248     ani_options aniArgs { 0, nullptr };
249     if (isAsync) {
250         aniResult = vm_->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env);
251     } else {
252         aniResult = vm_->GetEnv(ANI_VERSION_1, &env);
253     }
254     if (aniResult != ANI_OK) {
255         ANS_LOGD("AttachCurrentThread error. result: %{public}d.", aniResult);
256         return;
257     }
258     if (complete_) {
259         complete_(env, info_);
260     }
261     if (isAsync && (aniResult = vm_->DetachCurrentThread()) != ANI_OK) {
262         ANS_LOGD("DetachCurrentThread error. result: %{public}d.", aniResult);
263         return;
264     }
265 }
266 
267 /*
268  * when UIExtensionAbility use terminateSelfWithResult
269  */
OnResult(int32_t resultCode,const AAFwk::Want & result)270 void SettingsModalExtensionCallback::OnResult(int32_t resultCode, const AAFwk::Want& result)
271 {
272     ANS_LOGD("OnResult");
273 }
274 
275 /*
276  * when UIExtensionAbility send message to UIExtensionComponent
277  */
OnReceive(const AAFwk::WantParams & receive)278 void SettingsModalExtensionCallback::OnReceive(const AAFwk::WantParams& receive)
279 {
280     ANS_LOGD("OnReceive");
281 }
282 
283 /*
284  * when UIExtensionAbility disconnect or use terminate or process die
285  * releaseCode is 0 when process normal exit
286  */
OnRelease(int32_t releaseCode)287 void SettingsModalExtensionCallback::OnRelease(int32_t releaseCode)
288 {
289     ANS_LOGD("OnRelease");
290     ReleaseOrErrorHandle(releaseCode);
291 }
292 
293 /*
294  * when UIExtensionComponent init or turn to background or destroy UIExtensionAbility occur error
295  */
OnError(int32_t code,const std::string & name,const std::string & message)296 void SettingsModalExtensionCallback::OnError(int32_t code, const std::string& name, const std::string& message)
297 {
298     ANS_LOGE("OnError, code = %{public}d,name = %{public}s, message = %{public}s", code, name.c_str(), message.c_str());
299     ReleaseOrErrorHandle(code);
300     ProcessStatusChanged(code, false);
301 }
302 
303 /*
304  * when UIExtensionComponent connect to UIExtensionAbility, ModalUIExtensionProxy will init,
305  * UIExtensionComponent can send message to UIExtensionAbility by ModalUIExtensionProxy
306  */
OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy> & uiProxy)307 void SettingsModalExtensionCallback::OnRemoteReady(const std::shared_ptr<Ace::ModalUIExtensionProxy>& uiProxy)
308 {
309     ANS_LOGI("OnRemoteReady");
310     ProcessStatusChanged(0, true);
311 }
312 
313 /*
314  * when UIExtensionComponent destructed
315  */
OnDestroy()316 void SettingsModalExtensionCallback::OnDestroy()
317 {
318     ANS_LOGI("OnDestroy");
319     isExist.store(false);
320 }
321 
322 
SetSessionId(int32_t sessionId)323 void SettingsModalExtensionCallback::SetSessionId(int32_t sessionId)
324 {
325     this->sessionId_ = sessionId;
326 }
327 
SetBundleName(std::string bundleName)328 void SettingsModalExtensionCallback::SetBundleName(std::string bundleName)
329 {
330     this->bundleName_ = bundleName;
331 }
332 
SetAbilityContext(std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext)333 void SettingsModalExtensionCallback::SetAbilityContext(
334     std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext)
335 {
336     this->abilityContext_ = abilityContext;
337 }
338 
ReleaseOrErrorHandle(int32_t code)339 void SettingsModalExtensionCallback::ReleaseOrErrorHandle(int32_t code)
340 {
341     ANS_LOGD("ReleaseOrErrorHandle start");
342     Ace::UIContent* uiContent = this->abilityContext_->GetUIContent();
343     if (uiContent == nullptr) {
344         ANS_LOGE("uiContent is null");
345         return;
346     }
347     uiContent->CloseModalUIExtension(this->sessionId_);
348     ANS_LOGD("ReleaseOrErrorHandle end");
349     return;
350 }
351 }
352 }