1 /*
2  * Copyright (c) 2023-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 
16 #include "application_state_change_callback.h"
17 
18 #include "hilog_tag_wrapper.h"
19 #include "js_data_struct_converter.h"
20 #include "js_runtime_utils.h"
21 
22 namespace OHOS {
23 namespace AbilityRuntime {
JsApplicationStateChangeCallback(napi_env env)24 JsApplicationStateChangeCallback::JsApplicationStateChangeCallback(napi_env env)
25     : env_(env)
26 {
27 }
28 
CallJsMethodInnerCommon(const std::string & methodName,const std::set<std::shared_ptr<NativeReference>> callbacks)29 void JsApplicationStateChangeCallback::CallJsMethodInnerCommon(
30     const std::string &methodName, const std::set<std::shared_ptr<NativeReference>> callbacks)
31 {
32     for (auto &callback : callbacks) {
33         if (!callback) {
34             TAG_LOGE(AAFwkTag::APPKIT, "Invalid jsCallback");
35             continue;
36         }
37 
38         auto obj = callback->GetNapiValue();
39         if (!CheckTypeForNapiValue(env_, obj, napi_object)) {
40             TAG_LOGE(AAFwkTag::APPKIT, "Failed to get object");
41             continue;
42         }
43 
44         napi_value method = nullptr;
45         napi_get_named_property(env_, obj, methodName.data(), &method);
46         if (method == nullptr) {
47             TAG_LOGE(AAFwkTag::APPKIT, "Failed to get %{public}s from object", methodName.data());
48             continue;
49         }
50         napi_call_function(env_, obj, method, 0, nullptr, nullptr);
51     }
52 }
53 
CallJsMethod(const std::string & methodName)54 void JsApplicationStateChangeCallback::CallJsMethod(const std::string &methodName)
55 {
56     TAG_LOGD(AAFwkTag::APPKIT, "MethodName = %{public}s", methodName.c_str());
57     std::weak_ptr<JsApplicationStateChangeCallback> thisWeakPtr(shared_from_this());
58     std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>(
59         [thisWeakPtr, methodName, callbacks = callbacks_]
60         (napi_env env, NapiAsyncTask &task, int32_t status) {
61             std::shared_ptr<JsApplicationStateChangeCallback> jsCallback = thisWeakPtr.lock();
62             if (jsCallback) {
63                 jsCallback->CallJsMethodInnerCommon(methodName, callbacks);
64             }
65         }
66     );
67     napi_ref callback = nullptr;
68     std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
69     NapiAsyncTask::Schedule("JsApplicationStateChangeCallback::CallJsMethod:" + methodName,
70         env_, std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
71 }
72 
NotifyApplicationForeground()73 void JsApplicationStateChangeCallback::NotifyApplicationForeground()
74 {
75     CallJsMethod("onApplicationForeground");
76 }
77 
NotifyApplicationBackground()78 void JsApplicationStateChangeCallback::NotifyApplicationBackground()
79 {
80     CallJsMethod("onApplicationBackground");
81 }
82 
Register(napi_value jsCallback)83 void JsApplicationStateChangeCallback::Register(napi_value jsCallback)
84 {
85     if (env_ == nullptr || jsCallback == nullptr) {
86         TAG_LOGE(AAFwkTag::APPKIT, "env or jsCallback is nullptr");
87         return;
88     }
89     napi_ref ref = nullptr;
90     napi_create_reference(env_, jsCallback, 1, &ref);
91     callbacks_.emplace(std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref)));
92 }
93 
UnRegister(napi_value jsCallback)94 bool JsApplicationStateChangeCallback::UnRegister(napi_value jsCallback)
95 {
96     if (jsCallback == nullptr) {
97         TAG_LOGI(AAFwkTag::APPKIT, "jsCallback is nullptr, delete all callback");
98         callbacks_.clear();
99         return true;
100     }
101 
102     for (auto &callback : callbacks_) {
103         if (!callback) {
104             TAG_LOGE(AAFwkTag::APPKIT, "Invalid jsCallback");
105             continue;
106         }
107 
108         napi_value value = callback->GetNapiValue();
109         if (value == nullptr) {
110             TAG_LOGE(AAFwkTag::APPKIT, "Failed to get object");
111             continue;
112         }
113 
114         bool isEqual = false;
115         napi_strict_equals(env_, value, jsCallback, &isEqual);
116         if (isEqual) {
117             return callbacks_.erase(callback) == 1;
118         }
119     }
120     return false;
121 }
122 
IsEmpty() const123 bool JsApplicationStateChangeCallback::IsEmpty() const
124 {
125     return callbacks_.empty();
126 }
127 } // namespace AbilityRuntime
128 } // namespace OHOS