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