• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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