1 /*
2 * Copyright (c) 2021 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 "acelite_config.h"
17 #if (FEATURE_MODULE_DIALOG == 1)
18 #include "ace_log.h"
19 #include "js_async_work.h"
20 #include "js_dialog.h"
21
22 namespace OHOS {
23 namespace ACELite {
JSDialog()24 JSDialog::JSDialog()
25 : dialog_(nullptr),
26 dialogListener_(nullptr),
27 dismissListener_(nullptr),
28 title_(nullptr),
29 message_(nullptr) {}
30
~JSDialog()31 JSDialog::~JSDialog()
32 {
33 ReleaseResource();
34 }
35
ReleaseResource()36 void JSDialog::ReleaseResource()
37 {
38 ACE_FREE(title_);
39 ACE_FREE(message_);
40 ACE_DELETE(dialog_);
41 ACE_DELETE(dismissListener_);
42 ACE_DELETE(dialogListener_);
43 }
44
SetTitle(char * title)45 void JSDialog::SetTitle(char *title)
46 {
47 title_ = title;
48 }
49
SetMessage(char * message)50 void JSDialog::SetMessage(char *message)
51 {
52 message_ = message;
53 }
54
55 /**
56 * This the async callback used to release the JSDialog instance.
57 */
DialogRecycleExecutor(void * jsDialog)58 static void DialogRecycleExecutor(void *jsDialog)
59 {
60 if (jsDialog == nullptr) {
61 return;
62 }
63 // release resource
64 delete reinterpret_cast<JSDialog *>(jsDialog);
65 }
66
ShowDialog(JSIValue thisVal,JSIValue buttons,JSIValue successFunc,JSIValue cancelFunc,JSIValue completeFunc)67 bool JSDialog::ShowDialog(JSIValue thisVal,
68 JSIValue buttons,
69 JSIValue successFunc,
70 JSIValue cancelFunc,
71 JSIValue completeFunc)
72 {
73 ACE_DELETE(dialog_);
74 dialog_ = new UIDialog();
75 if (dialog_ == nullptr) {
76 HILOG_ERROR(HILOG_MODULE_ACE, "create ui dialog failed, return ");
77 return false;
78 }
79
80 dialog_->SetTitle(title_);
81 dialog_->SetText(message_);
82
83 // set dialog dismiss listener
84 dismissListener_ = new DismissListener(this, cancelFunc, completeFunc, thisVal);
85 if (dismissListener_ == nullptr) {
86 HILOG_ERROR(HILOG_MODULE_ACE, "create dialog dismissListener_ is nullptr, return nullptr.");
87 return false;
88 }
89 dialog_->SetOnCancelListener(dismissListener_);
90
91 // parser dialog button and set button listenr
92 if (!ParseButton(this, buttons, successFunc, completeFunc, thisVal)) {
93 HILOG_ERROR(HILOG_MODULE_ACE, "parse dialog button error");
94 return false;
95 }
96
97 dialog_->EnableAutoCancel(true);
98 // show dialog
99 dialog_->Show();
100 return true;
101 }
102
103
ParseButton(JSDialog * jsDialog,JSIValue buttonArrayObject,JSIValue successFuncObject,JSIValue completeFuncObject,JSIValue context)104 bool JSDialog::ParseButton(JSDialog *jsDialog,
105 JSIValue buttonArrayObject,
106 JSIValue successFuncObject,
107 JSIValue completeFuncObject,
108 JSIValue context)
109 {
110 if (jsDialog == nullptr) {
111 return false;
112 }
113 UIDialog *dialog = const_cast<UIDialog *>(jsDialog->GetUIDialog());
114 if (dialog == nullptr) {
115 return false;
116 }
117 /* parse dialog buttons */
118 uint32_t len = JSI::GetArrayLength(buttonArrayObject);
119 const uint8_t maxButtonNum = 3;
120 const char * const buttonTextKey = "text";
121 const char * const buttonColorKey = "color";
122 // support up to 3 buttons
123 for (uint32_t index = 0; index < len; index++) {
124 if (index >= maxButtonNum) {
125 HILOG_WARN(HILOG_MODULE_ACE, "dialog support up to 3 buttons, please check dialog button num");
126 break;
127 }
128 // parse button text
129 JSIValue buttonObject = JSI::GetPropertyByIndex(buttonArrayObject, index);
130 char *buttonText = JSI::GetStringProperty(buttonObject, buttonTextKey);
131
132 // parse button text color
133 char *buttonColorText = JSI::GetStringProperty(buttonObject, buttonColorKey);
134 ColorType color = ParseButtonColor(buttonColorText);
135 dialog->SetButtonColor(static_cast<UIDialog::DialogButtonType>(index), color);
136 // set button click listener
137 dialogListener_ = new DialogListener(jsDialog, index, successFuncObject, completeFuncObject, context);
138 if (dialogListener_ == nullptr) {
139 JSI::ReleaseString(buttonText);
140 JSI::ReleaseString(buttonColorText);
141 JSI::ReleaseValue(buttonObject);
142 return false;
143 }
144 dialog->SetButton(static_cast<UIDialog::DialogButtonType>(index), buttonText, dialogListener_);
145 // release button JSI value
146 JSI::ReleaseString(buttonText);
147 JSI::ReleaseString(buttonColorText);
148 JSI::ReleaseValue(buttonObject);
149 }
150 return true;
151 }
152
ParseButtonColor(const char * const buttonColorText)153 ColorType JSDialog::ParseButtonColor(const char * const buttonColorText)
154 {
155 uint32_t color = 0; // default color
156 uint8_t alpha = 0;
157 if (!ParseColor(buttonColorText, color, alpha)) {
158 HILOG_ERROR(HILOG_MODULE_ACE, "input dialog button color error, please check. default color instead");
159 return Color::GetColorFromRGB(0, 0, 0);
160 }
161 HILOG_INFO(HILOG_MODULE_ACE, "dialog buttonColorText = %{public}s, colorVal = %{public}d", buttonColorText, color);
162 uint8_t red8 = uint8_t((color & TEXT_RED_COLOR_MASK) >> RED_COLOR_START_BIT);
163 uint8_t green8 = uint8_t((color & TEXT_GREEN_COLOR_MASK) >> GREEN_COLOR_START_BIT);
164 uint8_t blue8 = uint8_t((color & TEXT_BLUE_COLOR_MASK));
165 return Color::GetColorFromRGB(red8, green8, blue8);
166 }
167
168 /**
169 * Call this function if the dialog is dismissed in any scenario.
170 */
DispatchReleaseRequest(const JSDialog * jsDialog)171 void JSDialog::DispatchReleaseRequest(const JSDialog *jsDialog)
172 {
173 if (!JsAsyncWork::DispatchAsyncWork(DialogRecycleExecutor, const_cast<JSDialog *>(jsDialog))) {
174 // dispatch the release request failed, JSDialog resource leaked
175 HILOG_ERROR(HILOG_MODULE_ACE, "dispatch the release request failed, resource leaked [%{private}p]", jsDialog);
176 }
177 }
178
DialogListener(JSDialog * jsDialog,uint8_t index,JSIValue successFunc,JSIValue completeFunc,JSIValue context)179 DialogListener::DialogListener(JSDialog *jsDialog,
180 uint8_t index,
181 JSIValue successFunc,
182 JSIValue completeFunc,
183 JSIValue context)
184 : jsDialog_(jsDialog),
185 buttonIndex_(index),
186 jsSuccessFunc_(JSI::AcquireValue(successFunc)),
187 jsCompleteFunc_(JSI::AcquireValue(completeFunc)),
188 jsContext_(JSI::AcquireValue(context)) {}
189
~DialogListener()190 DialogListener::~DialogListener() {}
191
OnClick(UIView & view,const ClickEvent & event)192 bool DialogListener::OnClick(UIView &view, const ClickEvent &event)
193 {
194 HILOG_INFO(HILOG_MODULE_ACE, "dialog button on click");
195 JSIValue args[1];
196 args[0] = JSI::CreateObject();
197 const char * const indexStr = "index";
198
199 JSI::SetNumberProperty(args[0], indexStr, buttonIndex_);
200 if (JSI::ValueIsFunction(jsSuccessFunc_)) {
201 JSI::CallFunction(jsSuccessFunc_, jsContext_, args, 1);
202 }
203 if (JSI::ValueIsFunction(jsCompleteFunc_)) {
204 JSI::CallFunction(jsCompleteFunc_, jsContext_, nullptr, 0);
205 }
206 JSI::ReleaseValueList(args[0], jsSuccessFunc_, jsCompleteFunc_, jsContext_);
207 // the dialog is going to be dismissed, request to do the recycling
208 JSDialog::DispatchReleaseRequest(jsDialog_);
209 return true;
210 }
211
DismissListener(JSDialog * jsDialog,JSIValue cancelFunc,JSIValue completeFunc,JSIValue context)212 DismissListener::DismissListener(JSDialog *jsDialog, JSIValue cancelFunc, JSIValue completeFunc, JSIValue context)
213 : jsDialog_(jsDialog),
214 jsCancelFunc_(JSI::AcquireValue(cancelFunc)),
215 jsCompleteFunc_(JSI::AcquireValue(completeFunc)),
216 jsContext_(JSI::AcquireValue(context)) {}
217
~DismissListener()218 DismissListener::~DismissListener() {}
OnClick(UIView & view,const ClickEvent & event)219 bool DismissListener::OnClick(UIView &view, const ClickEvent &event)
220 {
221 HILOG_INFO(HILOG_MODULE_ACE, "dialog dismiss button on click");
222 if (JSI::ValueIsFunction(jsCancelFunc_)) {
223 JSI::CallFunction(jsCancelFunc_, jsContext_, nullptr, 0);
224 }
225 if (JSI::ValueIsFunction(jsCompleteFunc_)) {
226 JSI::CallFunction(jsCompleteFunc_, jsContext_, nullptr, 0);
227 }
228 JSI::ReleaseValueList(jsCancelFunc_, jsCompleteFunc_, jsContext_);
229 // the dialog is going to be dismissed, request to do the recycling
230 JSDialog::DispatchReleaseRequest(jsDialog_);
231 return true;
232 }
233 } // namespace ACELite
234 } // namespace OHOS
235 #endif // FEATURE_MODULE_DIALOG
236