• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "bridge/declarative_frontend/jsview/js_navigation_stack.h"
17 
18 #include "bridge/common/utils/engine_helper.h"
19 #include "bridge/declarative_frontend/engine/js_converter.h"
20 #include "bridge/declarative_frontend/engine/functions/js_function.h"
21 #include "bridge/declarative_frontend/engine/js_execution_scope_defines.h"
22 #include "bridge/declarative_frontend/jsview/js_nav_path_stack.h"
23 #include "bridge/declarative_frontend/jsview/js_navdestination_context.h"
24 #include "core/components_ng/base/ui_node.h"
25 #include "core/components_ng/base/view_stack_processor.h"
26 #include "core/components_ng/pattern/custom/custom_node.h"
27 #include "core/components_ng/pattern/navrouter/navdestination_model.h"
28 #include "core/components_v2/inspector/inspector_constants.h"
29 #include "frameworks/base/json/json_util.h"
30 
31 namespace OHOS::Ace::Framework {
32 namespace {
33 constexpr int32_t ARGC_COUNT_TWO = 2;
34 constexpr int32_t MAX_PARSE_DEPTH = 3;
35 constexpr uint32_t MAX_PARSE_LENGTH = 1024;
36 constexpr uint32_t MAX_PARSE_PROPERTY_SIZE = 15;
37 constexpr int32_t INVALID_DESTINATION_MODE = -1;
38 constexpr char JS_STRINGIFIED_UNDEFINED[] = "undefined";
39 constexpr char JS_NAV_PATH_STACK_GETNATIVESTACK_FUNC[] = "getNativeStack";
40 constexpr char JS_NAV_PATH_STACK_SETPARENT_FUNC[] = "setParent";
41 
GetNapiEnv()42 napi_env GetNapiEnv()
43 {
44     auto engine = EngineHelper::GetCurrentEngine();
45     CHECK_NULL_RETURN(engine, nullptr);
46     NativeEngine* nativeEngine = engine->GetNativeEngine();
47     CHECK_NULL_RETURN(nativeEngine, nullptr);
48     return reinterpret_cast<napi_env>(nativeEngine);
49 }
50 }
51 
GetName()52 std::string JSRouteInfo::GetName()
53 {
54     return name_;
55 }
56 
SetName(const std::string & name)57 void JSRouteInfo::SetName(const std::string& name)
58 {
59     name_ = name;
60 }
61 
SetParam(const JSRef<JSVal> & param)62 void JSRouteInfo::SetParam(const JSRef<JSVal>& param)
63 {
64     param_ = param;
65 }
66 
GetParam() const67 JSRef<JSVal> JSRouteInfo::GetParam() const
68 {
69     return param_;
70 }
71 
RemoveByIndexes(const std::vector<int32_t> & indexes)72 void JSNavigationStack::RemoveByIndexes(const std::vector<int32_t>& indexes)
73 {
74     if (indexes.empty()) {
75         return;
76     }
77     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
78     if (dataSourceObj_->IsEmpty()) {
79         return;
80     }
81     auto remove = dataSourceObj_->GetProperty("removeByIndexes");
82     if (!remove->IsFunction()) {
83         return;
84     }
85     auto removeFunc = JSRef<JSFunc>::Cast(remove);
86     auto indexArr = JSRef<JSArray>::New();
87     if (indexArr->IsEmpty()) {
88         return;
89     }
90     for (int32_t idx = 0; idx < static_cast<int32_t>(indexes.size()); ++idx) {
91         indexArr->SetValueAt(idx, JSRef<JSVal>::Make(ToJSValue(indexes[idx])));
92     }
93     JSRef<JSVal> params[1];
94     params[0] = indexArr;
95     removeFunc->Call(dataSourceObj_, 1, params);
96 }
97 
SetDataSourceObj(const JSRef<JSObject> & dataSourceObj)98 void JSNavigationStack::SetDataSourceObj(const JSRef<JSObject>& dataSourceObj)
99 {
100     // clean callback from old JSNavPathStack
101     UpdateOnStateChangedCallback(dataSourceObj_, nullptr);
102     dataSourceObj_ = dataSourceObj;
103     // add callback to new JSNavPathStack
104     RemoveStack();
105     UpdateOnStateChangedCallback(dataSourceObj_, onStateChangedCallback_);
106 }
107 
GetDataSourceObj()108 const JSRef<JSObject>& JSNavigationStack::GetDataSourceObj()
109 {
110     return dataSourceObj_;
111 }
112 
SetNavDestBuilderFunc(const JSRef<JSFunc> & navDestBuilderFunc)113 void JSNavigationStack::SetNavDestBuilderFunc(const JSRef<JSFunc>& navDestBuilderFunc)
114 {
115     navDestBuilderFunc_ = navDestBuilderFunc;
116 }
117 
IsEmpty()118 bool JSNavigationStack::IsEmpty()
119 {
120     return dataSourceObj_->IsEmpty();
121 }
122 
Pop()123 void JSNavigationStack::Pop()
124 {
125     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
126     if (dataSourceObj_->IsEmpty()) {
127         return;
128     }
129     auto popFunc = dataSourceObj_->GetProperty("pop");
130     if (!popFunc->IsFunction()) {
131         return;
132     }
133     auto func = JSRef<JSFunc>::Cast(popFunc);
134     JSRef<JSVal>::Cast(func->Call(dataSourceObj_));
135 }
136 
Push(const std::string & name,const RefPtr<NG::RouteInfo> & routeInfo)137 void JSNavigationStack::Push(const std::string& name, const RefPtr<NG::RouteInfo>& routeInfo)
138 {
139     // obtain param from NavPathStack
140     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
141     JSRef<JSVal> param;
142     if (routeInfo) {
143         auto jsRouteInfo = AceType::DynamicCast<JSRouteInfo>(routeInfo);
144         param = jsRouteInfo->GetParam();
145     } else {
146         auto getParamByNameFunc = dataSourceObj_->GetProperty("getParamByName");
147         if (getParamByNameFunc->IsFunction()) {
148             auto getFunc = JSRef<JSFunc>::Cast(getParamByNameFunc);
149             JSRef<JSVal> params[1];
150             params[0] = JSRef<JSVal>::Make(ToJSValue(name));
151             auto funcArray = getFunc->Call(dataSourceObj_, 1, params);
152             if (funcArray->IsArray()) {
153                 auto result = JSRef<JSArray>::Cast(funcArray);
154                 param = result->GetValueAt(0);
155             }
156         }
157     }
158     auto pushNameFunc = dataSourceObj_->GetProperty("pushName");
159     if (pushNameFunc->IsFunction()) {
160         auto pushFunc = JSRef<JSFunc>::Cast(pushNameFunc);
161         JSRef<JSVal> params[2];
162         params[0] = JSRef<JSVal>::Make(ToJSValue(name));
163         params[1] = param;
164         pushFunc->Call(dataSourceObj_, 2, params);
165     }
166 }
167 
PushName(const std::string & name,const JSRef<JSVal> & param)168 void JSNavigationStack::PushName(const std::string& name, const JSRef<JSVal>& param)
169 {
170     // obtain param from routeInfo
171     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
172     auto pushNameFunc = dataSourceObj_->GetProperty("pushName");
173     if (pushNameFunc->IsFunction()) {
174         auto pushFunc = JSRef<JSFunc>::Cast(pushNameFunc);
175         JSRef<JSVal> params[2];
176         params[0] = JSRef<JSVal>::Make(ToJSValue(name));
177         params[1] = param;
178         pushFunc->Call(dataSourceObj_, 2, params);
179     }
180 }
181 
Push(const std::string & name,int32_t index)182 void JSNavigationStack::Push(const std::string& name, int32_t index)
183 {
184     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
185     auto getParamByIndexFunc = dataSourceObj_->GetProperty("getParamByIndex");
186     if (!getParamByIndexFunc->IsFunction()) {
187         return ;
188     }
189     auto pushNameFunc = dataSourceObj_->GetProperty("pushName");
190     if (!pushNameFunc->IsFunction()) {
191         return ;
192     }
193     auto getFunc = JSRef<JSFunc>::Cast(getParamByIndexFunc);
194     auto param = JSRef<JSVal>::Cast(getFunc->Call(dataSourceObj_));
195     auto pushFunc = JSRef<JSFunc>::Cast(pushNameFunc);
196     JSRef<JSVal> params[ARGC_COUNT_TWO];
197     params[0] = JSRef<JSVal>::Make(ToJSValue(name));
198     params[1] = param;
199     pushFunc->Call(dataSourceObj_, ARGC_COUNT_TWO, params);
200 }
201 
RemoveName(const std::string & name)202 void JSNavigationStack::RemoveName(const std::string& name)
203 {
204     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
205     if (dataSourceObj_->IsEmpty()) {
206         return;
207     }
208     auto removeByNameFunc = dataSourceObj_->GetProperty("removeByName");
209     if (!removeByNameFunc->IsFunction()) {
210         return;
211     }
212     auto func = JSRef<JSFunc>::Cast(removeByNameFunc);
213     JSRef<JSVal> params[1];
214     params[0] = JSRef<JSVal>::Make(ToJSValue(name));
215     func->Call(dataSourceObj_, 1, params);
216 }
217 
RemoveIndex(int32_t index)218 void JSNavigationStack::RemoveIndex(int32_t index)
219 {
220     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
221     if (dataSourceObj_->IsEmpty()) {
222         return;
223     }
224     auto removeIndexFunc = dataSourceObj_->GetProperty("removeIndex");
225     if (removeIndexFunc->IsFunction()) {
226         auto func = JSRef<JSFunc>::Cast(removeIndexFunc);
227         JSRef<JSVal> params[1];
228         params[0] = JSRef<JSVal>::Make(ToJSValue(index));
229         func->Call(dataSourceObj_, 1, params);
230     }
231 }
232 
Clear()233 void JSNavigationStack::Clear()
234 {
235     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
236     if (dataSourceObj_->IsEmpty()) {
237         return;
238     }
239     auto clearFunc = dataSourceObj_->GetProperty("clear");
240     if (!clearFunc->IsFunction()) {
241         return;
242     }
243     auto func = JSRef<JSFunc>::Cast(clearFunc);
244     func->Call(dataSourceObj_);
245 }
246 
GetAllPathName()247 std::vector<std::string> JSNavigationStack::GetAllPathName()
248 {
249     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, {});
250     if (dataSourceObj_->IsEmpty()) {
251         return {};
252     }
253     auto getAllPathNameFunc = dataSourceObj_->GetProperty("getAllPathName");
254     if (!getAllPathNameFunc->IsFunction()) {
255         return {};
256     }
257     auto func = JSRef<JSFunc>::Cast(getAllPathNameFunc);
258     auto funcArray = func->Call(dataSourceObj_);
259     if (!funcArray->IsArray()) {
260         return {};
261     }
262     auto array = JSRef<JSArray>::Cast(funcArray);
263     if (array->IsEmpty()) {
264         return {};
265     }
266     std::vector<std::string> pathNames;
267     for (size_t i = 0; i < array->Length(); i++) {
268         auto value = array->GetValueAt(i);
269         if (value->IsString()) {
270             pathNames.emplace_back(value->ToString());
271         }
272     }
273 
274     return pathNames;
275 }
276 
GetAllPathIndex()277 std::vector<int32_t> JSNavigationStack::GetAllPathIndex()
278 {
279     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, {});
280     if (dataSourceObj_->IsEmpty()) {
281         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "getAllPathIndex failed, dataSourceObj is empty!");
282         return {};
283     }
284     auto getAllPathIndexFunc = dataSourceObj_->GetProperty("getAllPathIndex");
285     if (!getAllPathIndexFunc->IsFunction()) {
286         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "getAllPathIndex is not a function in dataSourceObj!");
287         return {};
288     }
289     auto func = JSRef<JSFunc>::Cast(getAllPathIndexFunc);
290     auto funcArray = func->Call(dataSourceObj_);
291     if (!funcArray->IsArray()) {
292         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "getAllPathIndexFunc return value is not array!");
293         return {};
294     }
295     auto array = JSRef<JSArray>::Cast(funcArray);
296     if (array->IsEmpty()) {
297         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "getAllPathIndex return value is empyt!");
298         return {};
299     }
300     std::vector<int32_t> pathIndex;
301     for (size_t i = 0; i < array->Length(); i++) {
302         auto value = array->GetValueAt(i);
303         if (value->IsNumber()) {
304             pathIndex.emplace_back(value->ToNumber<int32_t>());
305         }
306     }
307 
308     return pathIndex;
309 }
310 
InitNavPathIndex(const std::vector<std::string> & pathNames)311 void JSNavigationStack::InitNavPathIndex(const std::vector<std::string>& pathNames)
312 {
313     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
314     if (dataSourceObj_->IsEmpty()) {
315         return;
316     }
317 
318     JSRef<JSArray> nameArray = JSRef<JSArray>::New();
319     JSRef<JSVal> params[1];
320     for (size_t i = 0; i < pathNames.size(); i++) {
321         JSRef<JSVal> info = JSRef<JSVal>::Make(ToJSValue(pathNames[i]));
322         nameArray->SetValueAt(i, info);
323     }
324     params[0] = nameArray;
325     auto initNavPathIndexFunc = dataSourceObj_->GetProperty("initNavPathIndex");
326     if (!initNavPathIndexFunc->IsFunction()) {
327         return;
328     }
329     auto func = JSRef<JSFunc>::Cast(initNavPathIndexFunc);
330     func->Call(dataSourceObj_, 1, params);
331 }
332 
SetDestinationIdToJsStack(int32_t index,const std::string & navDestinationId)333 void JSNavigationStack::SetDestinationIdToJsStack(int32_t index, const std::string& navDestinationId)
334 {
335     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
336     auto pathInfo = GetJsPathInfo(index);
337     if (pathInfo->IsEmpty()) {
338         return;
339     }
340     pathInfo->SetProperty<std::string>("navDestinationId", navDestinationId);
341 }
342 
CreateHomeDestination(const WeakPtr<NG::UINode> & customNode,RefPtr<NG::UINode> & node)343 bool JSNavigationStack::CreateHomeDestination(const WeakPtr<NG::UINode>& customNode, RefPtr<NG::UINode>& node)
344 {
345     if (!homePathInfo_.has_value()) {
346         return false;
347     }
348     RefPtr<NG::UINode> targetNode = nullptr;
349     RefPtr<NG::NavDestinationGroupNode> desNode = nullptr;
350     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
351     NG::ScopedViewStackProcessor scopedViewStackProcessor;
352     if (ERROR_CODE_NO_ERROR != LoadDestination(
353         homePathInfo_.value().name, homePathInfo_.value().param, customNode, targetNode, desNode)) {
354         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "failed to create , create empty node");
355         targetNode = AceType::DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
356         GetNavDestinationNodeInUINode(targetNode, desNode);
357     }
358     CHECK_NULL_RETURN(targetNode, false);
359     CHECK_NULL_RETURN(desNode, false);
360     node = targetNode;
361     auto pattern = desNode->GetPattern<NG::NavDestinationPattern>();
362     if (pattern) {
363         pattern->SetName(homePathInfo_.value().name);
364         pattern->SetIndex(-1);
365         auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(homePathInfo_.value().name, homePathInfo_.value().param);
366         pattern->SetNavPathInfo(pathInfo);
367         pattern->SetNavigationStack(WeakClaim(this));
368     }
369     homeDestinationNode_ = WeakPtr(desNode);
370     return true;
371 }
372 
CreateNodeByIndex(int32_t index,const WeakPtr<NG::UINode> & customNode,RefPtr<NG::UINode> & node)373 bool JSNavigationStack::CreateNodeByIndex(int32_t index, const WeakPtr<NG::UINode>& customNode,
374     RefPtr<NG::UINode>& node)
375 {
376     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
377     auto pathInfo = GetJsPathInfo(index);
378     if (pathInfo->IsEmpty()) {
379         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "create node failed, pathInfo is null");
380         return false;
381     }
382     auto name = pathInfo->GetPropertyValue<std::string>("name", "");
383     auto param = pathInfo->GetProperty("param");
384     RefPtr<NG::UINode> targetNode;
385     RefPtr<NG::NavDestinationGroupNode> desNode;
386     NG::ScopedViewStackProcessor scopedViewStackProcessor;
387     int32_t errorCode = LoadDestination(name, param, customNode, targetNode, desNode);
388     if (errorCode == ERROR_CODE_NO_ERROR && desNode) {
389         auto navDestinationPattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
390         if (navDestinationPattern) {
391             SetDestinationIdToJsStack(index, std::to_string(navDestinationPattern->GetNavDestinationId()));
392         }
393     }
394     // isRemove true, set destination info, false, current destination create failed
395     bool isRemove = RemoveDestinationIfNeeded(pathInfo, errorCode, index);
396     if (!isRemove) {
397         return false;
398     }
399     if (errorCode != ERROR_CODE_NO_ERROR) {
400         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "can't find target destination by index, create empty node");
401         node = AceType::DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
402         GetNavDestinationNodeInUINode(node, desNode);
403         CHECK_NULL_RETURN(desNode, true);
404         auto navDestinationPattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
405         CHECK_NULL_RETURN(navDestinationPattern, true);
406         SetDestinationIdToJsStack(index, std::to_string(navDestinationPattern->GetNavDestinationId()));
407         return true;
408     }
409     node = targetNode;
410     auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
411     if (pattern) {
412         pattern->SetName(name);
413         pattern->SetIndex(index);
414         auto onPop = GetOnPopByIndex(index);
415         auto isEntry = GetIsEntryByIndex(index);
416         TAG_LOGD(AceLogTag::ACE_NAVIGATION, "create destination node, isEntry %{public}d", isEntry);
417         auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param, onPop, isEntry);
418         pattern->SetNavPathInfo(pathInfo);
419         pattern->SetNavigationStack(WeakClaim(this));
420     }
421     return true;
422 }
423 
CreateNodeByRouteInfo(const RefPtr<NG::RouteInfo> & routeInfo,const WeakPtr<NG::UINode> & customNode)424 RefPtr<NG::UINode> JSNavigationStack::CreateNodeByRouteInfo(const RefPtr<NG::RouteInfo>& routeInfo,
425     const WeakPtr<NG::UINode>& customNode)
426 {
427     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, nullptr);
428     auto jsRouteInfo = AceType::DynamicCast<JSRouteInfo>(routeInfo);
429     if (!jsRouteInfo) {
430         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "route info is invalid");
431         return DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
432     }
433     auto name = jsRouteInfo->GetName();
434     auto param = jsRouteInfo->GetParam();
435     RefPtr<NG::UINode> node;
436     RefPtr<NG::NavDestinationGroupNode> desNode;
437     int32_t errorCode = LoadDestination(name, param, customNode, node, desNode);
438     if (errorCode == ERROR_CODE_NO_ERROR) {
439         auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
440         if (pattern) {
441             auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param);
442             pattern->SetNavPathInfo(pathInfo);
443             pattern->SetName(name);
444             pattern->SetNavigationStack(WeakClaim(this));
445         }
446         return node;
447     }
448     return DynamicCast<NG::UINode>(NavDestinationModel::GetInstance()->CreateEmpty());
449 }
450 
SetJSExecutionContext(const JSExecutionContext & context)451 void JSNavigationStack::SetJSExecutionContext(const JSExecutionContext& context)
452 {
453     executionContext_ = context;
454 }
455 
GetNameByIndex(int32_t index)456 std::string JSNavigationStack::GetNameByIndex(int32_t index)
457 {
458     auto pathNames = GetAllPathName();
459     if (index < 0 || index >= static_cast<int32_t>(pathNames.size())) {
460         return "";
461     }
462 
463     return pathNames[index];
464 }
465 
GetParamByIndex(int32_t index) const466 JSRef<JSVal> JSNavigationStack::GetParamByIndex(int32_t index) const
467 {
468     if (dataSourceObj_->IsEmpty()) {
469         return JSRef<JSVal>::Make();
470     }
471     auto getParamByIndexFunc = dataSourceObj_->GetProperty("getParamByIndex");
472     if (!getParamByIndexFunc->IsFunction()) {
473         return JSRef<JSVal>::Make();
474     }
475     auto func = JSRef<JSFunc>::Cast(getParamByIndexFunc);
476     JSRef<JSVal> params[1];
477     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
478     return func->Call(dataSourceObj_, 1, params);
479 }
480 
GetOnPopByIndex(int32_t index) const481 JSRef<JSVal> JSNavigationStack::GetOnPopByIndex(int32_t index) const
482 {
483     if (dataSourceObj_->IsEmpty()) {
484         return JSRef<JSVal>::Make();
485     }
486     auto getOnPopByIndexFunc = dataSourceObj_->GetProperty("getOnPopByIndex");
487     if (!getOnPopByIndexFunc->IsFunction()) {
488         return JSRef<JSVal>::Make();
489     }
490     auto func = JSRef<JSFunc>::Cast(getOnPopByIndexFunc);
491     JSRef<JSVal> params[1];
492     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
493     return func->Call(dataSourceObj_, 1, params);
494 }
495 
GetIsEntryByIndex(int32_t index)496 bool JSNavigationStack::GetIsEntryByIndex(int32_t index)
497 {
498     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
499     if (dataSourceObj_->IsEmpty()) {
500         return false;
501     }
502     auto getIsEntryFunc = dataSourceObj_->GetProperty("getIsEntryByIndex");
503     if (!getIsEntryFunc->IsFunction()) {
504         return false;
505     }
506     auto func = JSRef<JSFunc>::Cast(getIsEntryFunc);
507     JSRef<JSVal> params[1];
508     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
509     auto result = func->Call(dataSourceObj_, 1, params);
510     if (!result->IsBoolean()) {
511         return false;
512     }
513     return result->ToBoolean();
514 }
515 
SetIsEntryByIndex(int32_t index,bool isEntry)516 void JSNavigationStack::SetIsEntryByIndex(int32_t index, bool isEntry)
517 {
518     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
519     if (dataSourceObj_->IsEmpty()) {
520         return;
521     }
522     auto setIsEntryFunc = dataSourceObj_->GetProperty("setIsEntryByIndex");
523     if (!setIsEntryFunc->IsFunction()) {
524         return;
525     }
526     auto func = JSRef<JSFunc>::Cast(setIsEntryFunc);
527     JSRef<JSVal> params[ARGC_COUNT_TWO];
528     params[0] = JSRef<JSVal>::Make(ToJSValue(index));
529     params[1] = JSRef<JSVal>::Make(ToJSValue(isEntry));
530     func->Call(dataSourceObj_, ARGC_COUNT_TWO, params);
531 }
532 
GetNavDestinationNodeInUINode(RefPtr<NG::UINode> node,RefPtr<NG::NavDestinationGroupNode> & desNode)533 bool JSNavigationStack::GetNavDestinationNodeInUINode(
534     RefPtr<NG::UINode> node, RefPtr<NG::NavDestinationGroupNode>& desNode)
535 {
536     RefPtr<NG::CustomNode> customNode;
537     while (node) {
538         if (node->GetTag() == V2::JS_VIEW_ETS_TAG) {
539             customNode = AceType::DynamicCast<NG::CustomNode>(node);
540             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "render current custom node: %{public}s",
541                 customNode->GetCustomTag().c_str());
542             // record parent navigationNode before customNode is rendered in case of navDestinationNode
543             auto navigationNode = GetNavigationNode();
544             customNode->SetNavigationNode(navigationNode);
545             // render, and find deep further
546             customNode->Render();
547         } else if (node->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
548             desNode = AceType::DynamicCast<NG::NavDestinationGroupNode>(node);
549             if (desNode) {
550                 desNode->SetNavDestinationCustomNode(AceType::WeakClaim(AceType::RawPtr(customNode)));
551             }
552             return true;
553         }
554         auto children = node->GetChildren();
555         node = children.front();
556     }
557     return false;
558 }
559 
GetReplaceValue() const560 int32_t JSNavigationStack::GetReplaceValue() const
561 {
562     if (dataSourceObj_->IsEmpty()) {
563         return false;
564     }
565     auto replace = dataSourceObj_->GetProperty("isReplace");
566     return replace->ToNumber<int32_t>();
567 }
568 
UpdateReplaceValue(int32_t replaceValue) const569 void JSNavigationStack::UpdateReplaceValue(int32_t replaceValue) const
570 {
571     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
572     if (dataSourceObj_->IsEmpty()) {
573         return;
574     }
575     auto setIsReplaceFunc = dataSourceObj_->GetProperty("setIsReplace");
576     if (!setIsReplaceFunc->IsFunction()) {
577         return;
578     }
579     auto replaceFunc = JSRef<JSFunc>::Cast(setIsReplaceFunc);
580     JSRef<JSVal> params[1];
581     params[0] = JSRef<JSVal>::Make(ToJSValue(replaceValue));
582     replaceFunc->Call(dataSourceObj_, 1, params);
583 }
584 
GetRouteParam() const585 std::string JSNavigationStack::GetRouteParam() const
586 {
587     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, "");
588     auto size = GetSize();
589     if (size > 0) {
590         auto param = GetParamByIndex(size - 1);
591         return ConvertParamToString(param, true);
592     }
593     return "";
594 }
595 
GetSize() const596 int32_t JSNavigationStack::GetSize() const
597 {
598     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, 0);
599     if (dataSourceObj_->IsEmpty()) {
600         return 0;
601     }
602     auto sizeFunc = dataSourceObj_->GetProperty("size");
603     if (!sizeFunc->IsFunction()) {
604         return 0;
605     }
606     auto func = JSRef<JSFunc>::Cast(sizeFunc);
607     auto jsValue = JSRef<JSVal>::Cast(func->Call(dataSourceObj_));
608     if (jsValue->IsNumber()) {
609         return jsValue->ToNumber<int32_t>();
610     }
611     return 0;
612 }
613 
ConvertParamToString(const JSRef<JSVal> & param,bool needLimit) const614 std::string JSNavigationStack::ConvertParamToString(const JSRef<JSVal>& param, bool needLimit) const
615 {
616     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, "");
617     if (param->IsBoolean()) {
618         bool ret = param->ToBoolean();
619         return ret ? "true" : "false";
620     } else if (param->IsNumber()) {
621         double ret = param->ToNumber<double>();
622         std::ostringstream oss;
623         oss << ret;
624         return oss.str();
625     } else if (param->IsString()) {
626         std::string ret = param->ToString();
627         if (needLimit && ret.size() > MAX_PARSE_LENGTH) {
628             return ret.substr(0, MAX_PARSE_LENGTH);
629         }
630         return ret;
631     } else if (param->IsObject()) {
632         JSRef<JSObject> obj = JSRef<JSObject>::Cast(param);
633         auto jsonObj = JsonUtil::Create(true);
634         ParseJsObject(jsonObj, obj, MAX_PARSE_DEPTH, needLimit);
635         return jsonObj->ToString();
636     }
637     return "";
638 }
639 
ParseJsObject(std::unique_ptr<JsonValue> & json,const JSRef<JSObject> & obj,int32_t depthLimit,bool needLimit) const640 void JSNavigationStack::ParseJsObject(
641     std::unique_ptr<JsonValue>& json, const JSRef<JSObject>& obj, int32_t depthLimit, bool needLimit) const
642 {
643     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
644     if (depthLimit == 0) {
645         return;
646     }
647     depthLimit--;
648     auto propertyNames = obj->GetPropertyNames();
649     if (!propertyNames->IsArray()) {
650         return;
651     }
652     size_t size = propertyNames->Length();
653     if (needLimit && size > MAX_PARSE_PROPERTY_SIZE) {
654         size = MAX_PARSE_PROPERTY_SIZE;
655     }
656     for (size_t i = 0; i < size; i++) {
657         JSRef<JSVal> name = propertyNames->GetValueAt(i);
658         if (!name->IsString()) {
659             continue;
660         }
661         auto propertyName = name->ToString();
662         auto key = propertyName.c_str();
663         JSRef<JSVal> value = obj->GetProperty(key);
664         if (value->IsBoolean()) {
665             bool ret = value->ToBoolean();
666             json->Put(key, ret ? "true" : "false");
667         } else if (value->IsNumber()) {
668             double ret = value->ToNumber<double>();
669             std::ostringstream oss;
670             oss << ret;
671             json->Put(key, oss.str().c_str());
672         } else if (value->IsString()) {
673             std::string ret = value->ToString();
674             if (needLimit && ret.size() > MAX_PARSE_LENGTH) {
675                 json->Put(key, ret.substr(0, MAX_PARSE_LENGTH).c_str());
676             } else {
677                 json->Put(key, ret.c_str());
678             }
679         } else if (value->IsObject()) {
680             JSRef<JSObject> childObj = JSRef<JSObject>::Cast(value);
681             auto childJson = JsonUtil::Create(true);
682             ParseJsObject(childJson, childObj, depthLimit, needLimit);
683             json->Put(key, childJson);
684         }
685     }
686 }
687 
GetAnimatedValue() const688 bool JSNavigationStack::GetAnimatedValue() const
689 {
690     if (dataSourceObj_->IsEmpty()) {
691         return true;
692     }
693     auto animated = dataSourceObj_->GetProperty("animated");
694     return animated->ToBoolean();
695 }
696 
UpdateAnimatedValue(bool animated)697 void JSNavigationStack::UpdateAnimatedValue(bool animated)
698 {
699     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
700     if (dataSourceObj_->IsEmpty()) {
701         return;
702     }
703     auto setAnimatedFunc = dataSourceObj_->GetProperty("setAnimated");
704     if (!setAnimatedFunc->IsFunction()) {
705         return;
706     }
707     auto animatedFunc = JSRef<JSFunc>::Cast(setAnimatedFunc);
708     JSRef<JSVal> params[1];
709     params[0] = JSRef<JSVal>::Make(ToJSValue(animated));
710     animatedFunc->Call(dataSourceObj_, 1, params);
711 }
712 
713 
GetDisableAnimation() const714 bool JSNavigationStack::GetDisableAnimation() const
715 {
716     if (dataSourceObj_->IsEmpty()) {
717         return false;
718     }
719     auto disableAllAnimation = dataSourceObj_->GetProperty("disableAllAnimation");
720     return disableAllAnimation->ToBoolean();
721 }
722 
UpdateOnStateChangedCallback(JSRef<JSObject> obj,std::function<void ()> callback)723 void JSNavigationStack::UpdateOnStateChangedCallback(JSRef<JSObject> obj, std::function<void()> callback)
724 {
725     if (obj->IsEmpty()) {
726         return;
727     }
728 
729     auto property = obj->GetProperty(JS_NAV_PATH_STACK_GETNATIVESTACK_FUNC);
730     if (!property->IsFunction()) {
731         return;
732     }
733 
734     auto getNativeStackFunc = JSRef<JSFunc>::Cast(property);
735     auto nativeStack = getNativeStackFunc->Call(obj);
736     if (nativeStack->IsEmpty() || !nativeStack->IsObject()) {
737         return;
738     }
739 
740     auto nativeStackObj = JSRef<JSObject>::Cast(nativeStack);
741     JSNavPathStack* stack = nativeStackObj->Unwrap<JSNavPathStack>();
742     CHECK_NULL_VOID(stack);
743     stack->SetOnStateChangedCallback(callback);
744     // When switching the navigation stack, it is necessary to immediately trigger a refresh
745     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation necessary to immediately trigger a refresh");
746     stack->OnStateChanged();
747     stack->SetOnPopCallback([weakStack = AceType::WeakClaim(this)](const JSRef<JSVal>& param) {
748         auto navigationStack = weakStack.Upgrade();
749         CHECK_NULL_VOID(navigationStack);
750         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(navigationStack->executionContext_);
751         // Firstly, check if there is a NavDestination in the stack that can respond to pop/popToIndex/popToName
752         if (navigationStack->ExecutePopCallbackInStack(param)) {
753             return;
754         }
755         // Otherwise, check if there is a home NavDestination that can respond to pop/popToIndex/popToName
756         navigationStack->ExecutePopCallbackForHomeNavDestination(param);
757     });
758     stack->SetIsHomeNameCallback([weakStack = AceType::WeakClaim(this)](const std::string& name) -> bool {
759         auto navigationStack = weakStack.Upgrade();
760         CHECK_NULL_RETURN(navigationStack, false);
761         if (!navigationStack->homePathInfo_.has_value()) {
762             return false;
763         }
764         return navigationStack->homePathInfo_.value().name == name;
765     });
766 }
767 
ExecutePopCallbackInStack(const JSRef<JSVal> & param)768 bool JSNavigationStack::ExecutePopCallbackInStack(const JSRef<JSVal>& param)
769 {
770     auto size = GetSize();
771     if (size == 0) {
772         return false;
773     }
774     auto pathInfo = GetJsPathInfo(size - 1);
775     if (pathInfo->IsEmpty()) {
776         return false;
777     }
778     auto navDestinationId = pathInfo->GetProperty("navDestinationId");
779     if (!navDestinationId->IsString()) {
780         return false;
781     }
782     auto id = navDestinationId->ToString();
783     auto navPathList = GetAllNavDestinationNodes();
784     for (auto iter : navPathList) {
785         if (ExecutePopCallback(iter.second, std::atoi(id.c_str()), param)) {
786             return true;
787         }
788     }
789     return false;
790 }
791 
ExecutePopCallbackForHomeNavDestination(const JSRef<JSVal> & param)792 void JSNavigationStack::ExecutePopCallbackForHomeNavDestination(const JSRef<JSVal>& param)
793 {
794     auto homeDest = homeDestinationNode_.Upgrade();
795     CHECK_NULL_VOID(homeDest);
796     auto destPattern = homeDest->GetPattern<NG::NavDestinationPattern>();
797     CHECK_NULL_VOID(destPattern);
798     ExecutePopCallback(homeDest, destPattern->GetNavDestinationId(), param);
799 }
800 
OnAttachToParent(RefPtr<NG::NavigationStack> parent)801 void JSNavigationStack::OnAttachToParent(RefPtr<NG::NavigationStack> parent)
802 {
803     auto parentStack = AceType::DynamicCast<JSNavigationStack>(parent);
804     if (!parentStack) {
805         return;
806     }
807 
808     SetJSParentStack(JSRef<JSVal>::Cast(parentStack->GetDataSourceObj()));
809 }
810 
OnDetachFromParent()811 void JSNavigationStack::OnDetachFromParent()
812 {
813     JSRef<JSVal> undefined(JSVal::Undefined());
814     SetJSParentStack(undefined);
815 }
816 
SetJSParentStack(JSRef<JSVal> parent)817 void JSNavigationStack::SetJSParentStack(JSRef<JSVal> parent)
818 {
819     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
820     if (dataSourceObj_->IsEmpty()) {
821         return;
822     }
823 
824     auto property = dataSourceObj_->GetProperty(JS_NAV_PATH_STACK_SETPARENT_FUNC);
825     if (!property->IsFunction()) {
826         return;
827     }
828 
829     auto func = JSRef<JSFunc>::Cast(property);
830     JSRef<JSVal> params[1];
831     params[0] = parent;
832     func->Call(dataSourceObj_, 1, params);
833 }
834 
RemoveInvalidPage(int32_t index)835 void JSNavigationStack::RemoveInvalidPage(int32_t index)
836 {
837     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
838     if (dataSourceObj_->IsEmpty()) {
839         return;
840     }
841     auto removeInvalidPage = dataSourceObj_->GetProperty("removeInvalidPage");
842     if (removeInvalidPage->IsFunction()) {
843         auto func = JSRef<JSFunc>::Cast(removeInvalidPage);
844         JSRef<JSVal> params[1] = { JSRef<JSVal>::Make(ToJSValue(index)) };
845         func->Call(dataSourceObj_, 1, params);
846     }
847 }
848 
DumpStackInfo() const849 std::vector<std::string> JSNavigationStack::DumpStackInfo() const
850 {
851     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, {});
852     std::vector<std::string> dumpInfos;
853     for (size_t i = 0; i < navPathList_.size(); ++i) {
854         const auto& name = navPathList_[i].first;
855         std::string info = "[" + std::to_string(i) + "]{ name: \"" + name + "\"";
856         std::string param = ConvertParamToString(GetParamByIndex(i));
857         if (param.length() > 0) {
858             info += ", param: " + param;
859         }
860         info += " }";
861         dumpInfos.push_back(std::move(info));
862     }
863     return dumpInfos;
864 }
865 
FireNavigationInterception(bool isBefore,const RefPtr<NG::NavDestinationContext> & from,const RefPtr<NG::NavDestinationContext> & to,NG::NavigationOperation operation,bool isAnimated)866 void JSNavigationStack::FireNavigationInterception(bool isBefore, const RefPtr<NG::NavDestinationContext>& from,
867     const RefPtr<NG::NavDestinationContext>& to, NG::NavigationOperation operation, bool isAnimated)
868 {
869     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
870     std::string targetName = isBefore ? "willShow" : "didShow";
871     JSRef<JSFunc> targetFunc;
872     if (!CheckAndGetInterceptionFunc(targetName, targetFunc)) {
873         return;
874     }
875     const uint8_t argsNum = 4;
876     JSRef<JSVal> params[argsNum];
877     auto preDestination = AceType::DynamicCast<NG::NavDestinationContext>(from);
878     if (!preDestination) {
879         params[0] = JSRef<JSVal>::Make(ToJSValue("navBar"));
880     } else if (preDestination->GetIsEmpty()) {
881         params[0] = JSRef<JSObject>::New();
882     } else {
883         JSRef<JSObject> preObj = JSClass<JSNavDestinationContext>::NewInstance();
884         auto preProxy = Referenced::Claim(preObj->Unwrap<JSNavDestinationContext>());
885         preProxy->SetNavDestinationContext(from);
886         params[0] = preObj;
887     }
888 
889     auto topDestination = AceType::DynamicCast<NG::NavDestinationContext>(to);
890     if (!topDestination) {
891         params[1] = JSRef<JSVal>::Make(ToJSValue("navBar"));
892     } else if (topDestination->GetIsEmpty()) {
893         params[1] = JSRef<JSObject>::New();
894     } else {
895         JSRef<JSObject> topObj = JSClass<JSNavDestinationContext>::NewInstance();
896         auto topProxy = Referenced::Claim(topObj->Unwrap<JSNavDestinationContext>());
897         topProxy->SetNavDestinationContext(to);
898         params[1] = topObj;
899     }
900     const uint8_t operationIndex = 2;
901     params[operationIndex] = JSRef<JSVal>::Make(ToJSValue(static_cast<int32_t>(operation)));
902     const uint8_t animatedIndex = 3;
903     params[animatedIndex] = JSRef<JSVal>::Make(ToJSValue(isAnimated));
904     targetFunc->Call(JSRef<JSObject>(), argsNum, params);
905 }
906 
FireNavigationModeChange(NG::NavigationMode mode)907 void JSNavigationStack::FireNavigationModeChange(NG::NavigationMode mode)
908 {
909     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
910     JSRef<JSFunc> modeFunc;
911     if (!CheckAndGetInterceptionFunc("modeChange", modeFunc)) {
912         return;
913     }
914     JSRef<JSVal> params[1];
915     params[0] = JSRef<JSVal>::Make(ToJSValue(static_cast<int32_t>(mode)));
916     modeFunc->Call(JSRef<JSObject>(), 1, params);
917 }
918 
CheckAndGetInterceptionFunc(const std::string & name,JSRef<JSFunc> & func)919 bool JSNavigationStack::CheckAndGetInterceptionFunc(const std::string& name, JSRef<JSFunc>& func)
920 {
921     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
922     if (dataSourceObj_->IsEmpty()) {
923         return false;
924     }
925     JSRef<JSVal> delegateProp = dataSourceObj_->GetProperty("interception");
926     if (!delegateProp->IsObject()) {
927         return false;
928     }
929     JSRef<JSObject> delegate = JSRef<JSObject>::Cast(delegateProp);
930     JSRef<JSVal> funcProp = delegate->GetProperty(name.c_str());
931     if (!funcProp->IsFunction()) {
932         return false;
933     }
934     func = JSRef<JSFunc>::Cast(funcProp);
935     return true;
936 }
937 
LoadDestinationByBuilder(const std::string & name,const JSRef<JSVal> & param,RefPtr<NG::UINode> & node,RefPtr<NG::NavDestinationGroupNode> & desNode)938 bool JSNavigationStack::LoadDestinationByBuilder(const std::string& name, const JSRef<JSVal>& param,
939     RefPtr<NG::UINode>& node, RefPtr<NG::NavDestinationGroupNode>& desNode)
940 {
941     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
942     if (navDestBuilderFunc_->IsEmpty()) {
943         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "Builder function is empty");
944         return false;
945     }
946     auto builderObj = JSRef<JSObject>::Cast(navDestBuilderFunc_);
947     const int32_t number = builderObj->GetProperty("length")->ToNumber<int32_t>();
948     JSRef<JSVal> params[number];
949     if (number >= 1) {
950         params[0] = JSRef<JSVal>::Make(ToJSValue(name));
951     }
952     if (number >= ARGC_COUNT_TWO) {
953         params[1] = param;
954     }
955     navDestBuilderFunc_->Call(JSRef<JSObject>(), number, params);
956     node = NG::ViewStackProcessor::GetInstance()->Finish();
957     return GetNavDestinationNodeInUINode(node, desNode);
958 }
959 
LoadDestination(const std::string & name,const JSRef<JSVal> & param,const WeakPtr<NG::UINode> & customNode,RefPtr<NG::UINode> & node,RefPtr<NG::NavDestinationGroupNode> & desNode)960 int32_t JSNavigationStack::LoadDestination(const std::string& name, const JSRef<JSVal>& param,
961     const WeakPtr<NG::UINode>& customNode, RefPtr<NG::UINode>& node,
962     RefPtr<NG::NavDestinationGroupNode>& desNode)
963 {
964     NG::ScopedViewStackProcessor scopedViewStackProcessor;
965     // execute navdestination attribute builder
966     if (LoadDestinationByBuilder(name, param, node, desNode)) {
967         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "load destination by buildermap");
968         return ERROR_CODE_NO_ERROR;
969     }
970     // deal route config and execute route config builder
971     auto container = Container::Current();
972     CHECK_NULL_RETURN(container, ERROR_CODE_INTERNAL_ERROR);
973     auto navigationRoute = container->GetNavigationRoute();
974     if (!navigationRoute) {
975         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation route is invalid");
976         return ERROR_CODE_INTERNAL_ERROR;
977     }
978     if (!navigationRoute->HasLoaded(name) && navigationRoute->LoadPage(name) != 0) {
979         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "load page failed: %{public}s", name.c_str());
980         return navDestBuilderFunc_->IsEmpty() ? ERROR_CODE_BUILDER_FUNCTION_NOT_REGISTERED
981             : ERROR_CODE_DESTINATION_NOT_FOUND;
982     }
983     int32_t result = ExecuteBuilderByConfig(name, customNode, param);
984     if (result != ERROR_CODE_NO_ERROR) {
985         return result;
986     }
987     node = NG::ViewStackProcessor::GetInstance()->Finish();
988     if (!GetNavDestinationNodeInUINode(node, desNode)) {
989         return ERROR_CODE_DESTINATION_NOT_FOUND;
990     }
991     return ERROR_CODE_NO_ERROR;
992 }
993 
ExecuteBuilderByConfig(const std::string & name,const WeakPtr<NG::UINode> & customNode,const JSRef<JSVal> & param)994 int32_t JSNavigationStack::ExecuteBuilderByConfig(const std::string& name,
995     const WeakPtr<NG::UINode>& customNode, const JSRef<JSVal>& param)
996 {
997     auto parentCustomNode = AceType::DynamicCast<NG::CustomNode>(customNode.Upgrade());
998     CHECK_NULL_RETURN(parentCustomNode, ERROR_CODE_INTERNAL_ERROR);
999     auto thisObjTmp = parentCustomNode->FireThisFunc();
1000     CHECK_NULL_RETURN(thisObjTmp, ERROR_CODE_INTERNAL_ERROR);
1001     JSRef<JSObject> thisObj = *(JSRef<JSObject>*)(thisObjTmp);
1002     auto engine = AceType::DynamicCast<Framework::JsiDeclarativeEngine>(EngineHelper::GetCurrentEngine());
1003     CHECK_NULL_RETURN(engine, ERROR_CODE_INTERNAL_ERROR);
1004     JSRef<JSObject> wrapBuilder = JSRef<JSObject>::Make(engine->GetNavigationBuilder(name).ToLocal());
1005     if (wrapBuilder->IsEmpty()) {
1006         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "wrap builder is empty: %{public}s", name.c_str());
1007         return ERROR_CODE_BUILDER_FUNCTION_NOT_REGISTERED;
1008     }
1009     auto builderProp = wrapBuilder->GetProperty("builder");
1010     if (!builderProp->IsFunction()) {
1011         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "get builder failed: %{public}s", name.c_str());
1012         return ERROR_CODE_BUILDER_FUNCTION_NOT_REGISTERED;
1013     }
1014     auto builderObj = JSRef<JSObject>::Cast(builderProp);
1015     const int32_t number = builderObj->GetProperty("length")->ToNumber<int32_t>();
1016     JSRef<JSVal> params[number];
1017     if (number >= 1) {
1018         params[0] = JSRef<JSVal>::Make(ToJSValue(name));
1019     }
1020     if (number >= ARGC_COUNT_TWO) {
1021         params[1] = param;
1022     }
1023     auto builder = JSRef<JSFunc>::Cast(builderProp);
1024     builder->Call(thisObj, number, params);
1025     return ERROR_CODE_NO_ERROR;
1026 }
1027 
GetJsIndexFromNativeIndex(int32_t index)1028 int32_t JSNavigationStack::GetJsIndexFromNativeIndex(int32_t index)
1029 {
1030     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, -1);
1031     if (dataSourceObj_->IsEmpty()) {
1032         return -1;
1033     }
1034     auto getIndexFunc = dataSourceObj_->GetProperty("getJsIndexFromNativeIndex");
1035     if (!getIndexFunc->IsFunction()) {
1036         return -1;
1037     }
1038     auto func = JSRef<JSFunc>::Cast(getIndexFunc);
1039     JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(index));
1040     auto res = func->Call(dataSourceObj_, 1, &param);
1041     if (res->IsNumber()) {
1042         return res->ToNumber<int32_t>();
1043     }
1044     return -1;
1045 }
1046 
MoveIndexToTop(int32_t index)1047 void JSNavigationStack::MoveIndexToTop(int32_t index)
1048 {
1049     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1050     if (dataSourceObj_->IsEmpty()) {
1051         return;
1052     }
1053     auto moveIndexToTopFunc = dataSourceObj_->GetProperty("moveIndexToTop");
1054     if (!moveIndexToTopFunc->IsFunction()) {
1055         return;
1056     }
1057     auto func = JSRef<JSFunc>::Cast(moveIndexToTopFunc);
1058     JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(index));
1059     func->Call(dataSourceObj_, 1, &param);
1060 }
1061 
UpdatePathInfoIfNeeded(RefPtr<NG::UINode> & uiNode,int32_t index)1062 void JSNavigationStack::UpdatePathInfoIfNeeded(RefPtr<NG::UINode>& uiNode, int32_t index)
1063 {
1064     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1065     bool needUpdate = GetNeedUpdatePathInfo(index);
1066     if (!needUpdate) {
1067         return;
1068     }
1069     SetNeedUpdatePathInfo(index, false);
1070     RefPtr<NG::NavDestinationGroupNode> desNode;
1071     if (!GetNavDestinationNodeInUINode(uiNode, desNode)) {
1072         return;
1073     }
1074     auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(desNode->GetPattern());
1075     if (!pattern) {
1076         return;
1077     }
1078 
1079     auto name = GetNameByIndex(index);
1080     auto param = GetParamByIndex(index);
1081     auto onPop = GetOnPopByIndex(index);
1082     auto isEntry = GetIsEntryByIndex(index);
1083     TAG_LOGD(AceLogTag::ACE_NAVIGATION, "update destination node info, isEntry %{public}d", isEntry);
1084     auto pathInfo = AceType::MakeRefPtr<JSNavPathInfo>(name, param, onPop, isEntry);
1085     pattern->SetNavPathInfo(pathInfo);
1086 }
1087 
GetNeedUpdatePathInfo(int32_t index)1088 bool JSNavigationStack::GetNeedUpdatePathInfo(int32_t index)
1089 {
1090     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1091     auto path = GetJsPathInfo(index);
1092     if (path->IsEmpty()) {
1093         return false;
1094     }
1095     auto needUpdate = path->GetProperty("needUpdate");
1096     if (!needUpdate->IsBoolean()) {
1097         return false;
1098     }
1099     return needUpdate->ToBoolean();
1100 }
1101 
SetNeedUpdatePathInfo(int32_t index,bool need)1102 void JSNavigationStack::SetNeedUpdatePathInfo(int32_t index, bool need)
1103 {
1104     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1105     auto path = GetJsPathInfo(index);
1106     if (path->IsEmpty()) {
1107         return;
1108     }
1109     path->SetProperty<bool>("needUpdate", need);
1110 }
1111 
RecoveryNavigationStack()1112 void JSNavigationStack::RecoveryNavigationStack()
1113 {
1114     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1115     navPathList_ = preNavPathList_;
1116     if (dataSourceObj_->IsEmpty()) {
1117         return;
1118     }
1119     JSRef<JSArray> pathArray = JSRef<JSArray>::New();
1120     for (int32_t index = 0; index < static_cast<int32_t>(navPathList_.size()); index++) {
1121         auto node = navPathList_[index].second;
1122         auto navDestinationGroupNode = AceType::DynamicCast<NG::NavDestinationGroupNode>(
1123             NG::NavigationGroupNode::GetNavDestinationNode(node));
1124         if (!navDestinationGroupNode) {
1125             continue;
1126         }
1127         auto pattern = AceType::DynamicCast<NG::NavDestinationPattern>(navDestinationGroupNode->GetPattern());
1128         if (!pattern) {
1129             continue;
1130         }
1131         auto context = pattern->GetNavDestinationContext();
1132         if (!context) {
1133             continue;
1134         }
1135         JSRef<JSObject> item = CreatePathInfoWithNecessaryProperty(context);
1136         pathArray->SetValueAt(index, item);
1137     }
1138     dataSourceObj_->SetPropertyObject("pathArray", pathArray);
1139 }
1140 
NeedBuildNewInstance(int32_t index)1141 bool JSNavigationStack::NeedBuildNewInstance(int32_t index)
1142 {
1143     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1144     auto pathInfo = GetJsPathInfo(index);
1145     if (pathInfo->IsEmpty()) {
1146         return false;
1147     }
1148     auto needBuildNewInstance = pathInfo->GetProperty("needBuildNewInstance");
1149     if (!needBuildNewInstance->IsBoolean()) {
1150         return false;
1151     }
1152     return needBuildNewInstance->ToBoolean();
1153 }
1154 
SetNeedBuildNewInstance(int32_t index,bool need)1155 void JSNavigationStack::SetNeedBuildNewInstance(int32_t index, bool need)
1156 {
1157     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1158     auto pathInfo = GetJsPathInfo(index);
1159     if (pathInfo->IsEmpty()) {
1160         return;
1161     }
1162     pathInfo->SetProperty<bool>("needBuildNewInstance", need);
1163 }
1164 
GetJsPathArray() const1165 JSRef<JSArray> JSNavigationStack::GetJsPathArray() const
1166 {
1167     if (dataSourceObj_->IsEmpty()) {
1168         return JSRef<JSArray>();
1169     }
1170     auto objArray = dataSourceObj_->GetProperty("pathArray");
1171     if (!objArray->IsArray()) {
1172         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "navPathArray invalid!");
1173         return JSRef<JSArray>();
1174     }
1175     return JSRef<JSArray>::Cast(objArray);
1176 }
1177 
GetJsPathInfo(int32_t index) const1178 JSRef<JSObject> JSNavigationStack::GetJsPathInfo(int32_t index) const
1179 {
1180     auto navPathArray = GetJsPathArray();
1181     int32_t len = static_cast<int32_t>(navPathArray->Length());
1182     if (index < 0 || index >= len) {
1183         return JSRef<JSObject>();
1184     }
1185     auto pathInfo = navPathArray->GetValueAt(index);
1186     if (!pathInfo->IsObject()) {
1187         return JSRef<JSObject>();
1188     }
1189     return JSRef<JSObject>::Cast(pathInfo);
1190 }
1191 
CreatePathInfoWithNecessaryProperty(const RefPtr<NG::NavDestinationContext> & context)1192 JSRef<JSObject> JSNavigationStack::CreatePathInfoWithNecessaryProperty(
1193     const RefPtr<NG::NavDestinationContext>& context)
1194 {
1195     auto pathInfo = JSRef<JSObject>::New();
1196     CHECK_NULL_RETURN(context, pathInfo);
1197     auto jsPathInfo = AceType::DynamicCast<JSNavPathInfo>(context->GetNavPathInfo());
1198     CHECK_NULL_RETURN(jsPathInfo, pathInfo);
1199 
1200     pathInfo->SetProperty<std::string>("name", jsPathInfo->GetName());
1201     pathInfo->SetProperty<int32_t>("index", context->GetIndex());
1202     pathInfo->SetProperty<std::string>("navDestinationId", std::to_string(context->GetNavDestinationId()));
1203     pathInfo->SetProperty<bool>("isEntry", jsPathInfo->GetIsEntry());
1204     pathInfo->SetPropertyObject("param", jsPathInfo->GetParam());
1205     pathInfo->SetPropertyObject("onPop", jsPathInfo->GetOnPop());
1206     return pathInfo;
1207 }
1208 
GetStringifyParamByIndex(int32_t index) const1209 std::string JSNavigationStack::GetStringifyParamByIndex(int32_t index) const
1210 {
1211     auto env = GetNapiEnv();
1212     if (!env) {
1213         return JS_STRINGIFIED_UNDEFINED;
1214     }
1215     napi_handle_scope scope = nullptr;
1216     napi_open_handle_scope(env, &scope);
1217     if (scope == nullptr) {
1218         return JS_STRINGIFIED_UNDEFINED;
1219     }
1220     if (dataSourceObj_->IsEmpty()) {
1221         napi_close_handle_scope(env, scope);
1222         return JS_STRINGIFIED_UNDEFINED;
1223     }
1224     napi_value navPathStack = JsConverter::ConvertJsValToNapiValue(dataSourceObj_);
1225     napi_value getParamByIndex;
1226     napi_get_named_property(env, navPathStack, "getParamByIndex", &getParamByIndex);
1227     napi_value napiIndex;
1228     napi_create_int32(env, index, &napiIndex);
1229     napi_value param;
1230     napi_call_function(env, navPathStack, getParamByIndex, 1, &napiIndex, &param);
1231 
1232     napi_value globalValue;
1233     napi_get_global(env, &globalValue);
1234     napi_value jsonClass;
1235     napi_get_named_property(env, globalValue, "JSON", &jsonClass);
1236     napi_value stringifyFunc;
1237     napi_get_named_property(env, jsonClass, "stringify", &stringifyFunc);
1238     napi_value stringifyParam;
1239     if (napi_call_function(env, jsonClass, stringifyFunc, 1, &param, &stringifyParam) != napi_ok) {
1240         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Can not stringify current param!");
1241         napi_get_and_clear_last_exception(env, &stringifyParam);
1242         napi_close_handle_scope(env, scope);
1243         return JS_STRINGIFIED_UNDEFINED;
1244     }
1245     size_t len = 0;
1246     napi_get_value_string_utf8(env, stringifyParam, nullptr, 0, &len);
1247     std::unique_ptr<char[]> paramChar = std::make_unique<char[]>(len + 1);
1248     napi_get_value_string_utf8(env, stringifyParam, paramChar.get(), len + 1, &len);
1249     napi_close_handle_scope(env, scope);
1250     return paramChar.get();
1251 }
1252 
GetSerializedParamSafely(int32_t index) const1253 std::string JSNavigationStack::GetSerializedParamSafely(int32_t index) const
1254 {
1255     std::string serializedEmpty = "{}";
1256     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, serializedEmpty);
1257     auto getSerializedParamSafelyFunc = dataSourceObj_->GetProperty("getSerializedParamSafely");
1258     if (!getSerializedParamSafelyFunc->IsFunction()) {
1259         return serializedEmpty;
1260     }
1261     JSRef<JSVal> arg[1] = { JSRef<JSVal>::Make(ToJSValue(index)) };
1262     auto serializedParam = JSRef<JSFunc>::Cast(getSerializedParamSafelyFunc)->Call(dataSourceObj_, 1, arg);
1263     if (!serializedParam->IsString() || serializedParam->ToString().empty()) {
1264         TAG_LOGW(AceLogTag::ACE_NAVIGATION,
1265             "current navDestination(index: %{public}d)'s param can't be serialized or is empty!", index);
1266     }
1267     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "serialize navDestination param success! its index: %{public}d", index);
1268     return serializedParam->ToString();
1269 }
1270 
SetPathArray(const std::vector<NG::NavdestinationRecoveryInfo> & navdestinationsInfo)1271 void JSNavigationStack::SetPathArray(const std::vector<NG::NavdestinationRecoveryInfo>& navdestinationsInfo)
1272 {
1273     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1274     JSRef<JSArray> newPathArray = JSRef<JSArray>::New();
1275     for (int32_t index = 0; index < static_cast<int32_t>(navdestinationsInfo.size()); ++index) {
1276         auto infoName = navdestinationsInfo[index].name;
1277         auto infoParam = navdestinationsInfo[index].param;
1278         auto infoMode = navdestinationsInfo[index].mode;
1279 
1280         JSRef<JSObject> navPathInfo = JSRef<JSObject>::New();
1281         navPathInfo->SetProperty<std::string>("name", infoName);
1282         if (!infoParam.empty() && infoParam != JS_STRINGIFIED_UNDEFINED) {
1283             navPathInfo->SetPropertyObject("param", JSRef<JSObject>::New()->ToJsonObject(infoParam.c_str()));
1284         }
1285         navPathInfo->SetProperty<bool>("fromRecovery", true);
1286         navPathInfo->SetProperty<int32_t>("mode", infoMode);
1287         newPathArray->SetValueAt(index, navPathInfo);
1288     }
1289     dataSourceObj_->SetPropertyObject("pathArray", newPathArray);
1290     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Set navPathArray by recovery info success");
1291 }
1292 
CallPushDestinationInner(const NG::NavdestinationRecoveryInfo & navdestinationsInfo)1293 void JSNavigationStack::CallPushDestinationInner(const NG::NavdestinationRecoveryInfo& navdestinationsInfo)
1294 {
1295     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1296     if (dataSourceObj_->IsEmpty()) {
1297         return;
1298     }
1299     auto pushNavDestinationFunc = dataSourceObj_->GetProperty("pushDestination");
1300     if (!pushNavDestinationFunc->IsFunction()) {
1301         return;
1302     }
1303     auto infoName = navdestinationsInfo.name;
1304     auto infoParam = navdestinationsInfo.param;
1305     auto infoMode = navdestinationsInfo.mode;
1306 
1307     JSRef<JSObject> navPathInfo = JSRef<JSObject>::New();
1308     navPathInfo->SetProperty<std::string>("name", infoName);
1309     if (!infoParam.empty() && infoParam != JS_STRINGIFIED_UNDEFINED) {
1310         navPathInfo->SetPropertyObject("param", JSRef<JSObject>::New()->ToJsonObject(infoParam.c_str()));
1311     }
1312     navPathInfo->SetProperty<int32_t>("mode", infoMode);
1313 
1314     auto func = JSRef<JSFunc>::Cast(pushNavDestinationFunc);
1315     JSRef<JSVal> arg[1];
1316     arg[0] = navPathInfo;
1317     func->Call(dataSourceObj_, 1, arg);
1318 }
1319 
IsFromRecovery(int32_t index)1320 bool JSNavigationStack::IsFromRecovery(int32_t index)
1321 {
1322     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1323     auto pathInfo = GetJsPathInfo(index);
1324     if (pathInfo->IsEmpty()) {
1325         return false;
1326     }
1327     auto fromRecovery = pathInfo->GetProperty("fromRecovery");
1328     if (!fromRecovery->IsBoolean()) {
1329         return false;
1330     }
1331     return fromRecovery->ToBoolean();
1332 }
1333 
SetFromRecovery(int32_t index,bool fromRecovery)1334 void JSNavigationStack::SetFromRecovery(int32_t index, bool fromRecovery)
1335 {
1336     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1337     auto pathInfo = GetJsPathInfo(index);
1338     if (pathInfo->IsEmpty()) {
1339         return;
1340     }
1341     pathInfo->SetProperty<bool>("fromRecovery", fromRecovery);
1342 }
1343 
GetRecoveredDestinationMode(int32_t index)1344 int32_t JSNavigationStack::GetRecoveredDestinationMode(int32_t index)
1345 {
1346     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, 0);
1347     auto pathInfo = GetJsPathInfo(index);
1348     if (pathInfo->IsEmpty()) {
1349         return INVALID_DESTINATION_MODE;
1350     }
1351     auto mode = pathInfo->GetProperty("mode");
1352     if (!mode->IsNumber()) {
1353         return INVALID_DESTINATION_MODE;
1354     }
1355     return mode->ToNumber<int32_t>();
1356 }
1357 
ErrorToMessage(int32_t code)1358 std::string JSNavigationStack::ErrorToMessage(int32_t code)
1359 {
1360     switch (code) {
1361         case ERROR_CODE_INTERNAL_ERROR:
1362             return "Internal error. Create NavDestination failed, probably caused by wrong UIContext.";
1363         case ERROR_CODE_DESTINATION_NOT_FOUND:
1364             return "NavDestination not found.";
1365         case ERROR_CODE_BUILDER_FUNCTION_NOT_REGISTERED:
1366             return "Builder function not registered.";
1367         case ERROR_CODE_PARAM_INVALID:
1368             return "Paramter error.";
1369         default:
1370             return "Error code is not supported.";
1371     }
1372 }
1373 
RemoveDestinationIfNeeded(const JSRef<JSObject> & pathInfo,int32_t errorCode,int32_t index)1374 bool JSNavigationStack::RemoveDestinationIfNeeded(const JSRef<JSObject>& pathInfo, int32_t errorCode, int32_t index)
1375 {
1376     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1377     if (!pathInfo->HasProperty("promise")) {
1378         // not use pushDestination, return true
1379         return true;
1380     }
1381     auto promise = pathInfo->GetProperty("promise");
1382     if (!promise->IsFunction()) {
1383         return true;
1384     }
1385     auto promiseFunc = JSRef<JSFunc>::Cast(promise);
1386     if (errorCode == ERROR_CODE_NO_ERROR) {
1387         JSRef<JSVal> params[1];
1388         params[0] = JSRef<JSVal>::Make(ToJSValue(errorCode));
1389         promiseFunc->Call(dataSourceObj_, 1, params);
1390         return true;
1391     }
1392     // push destination failed, remove page in pathStack
1393     RemoveInvalidPage(index);
1394     const int32_t argc = 2;
1395     JSRef<JSVal> params[argc];
1396     JSRef<JSObject> errorInfo = JSRef<JSObject>::New();
1397     params[0] = JSRef<JSVal>::Make(ToJSValue(errorCode));
1398     params[1] = JSRef<JSVal>::Make(ToJSValue(ErrorToMessage(errorCode)));
1399     promiseFunc->Call(dataSourceObj_, argc, params);
1400     return false;
1401 }
1402 
CheckIsReplacedDestination(int32_t index,std::string & replacedName,int32_t & replacedIndex)1403 bool JSNavigationStack::CheckIsReplacedDestination(int32_t index, std::string& replacedName, int32_t& replacedIndex)
1404 {
1405     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1406     auto pathInfo = GetJsPathInfo(index);
1407     if (pathInfo->IsEmpty()) {
1408         return false;
1409     }
1410     auto recoveryFromReplaceDestination = pathInfo->GetProperty("recoveryFromReplaceDestination");
1411     if (!recoveryFromReplaceDestination->IsBoolean() || !recoveryFromReplaceDestination->ToBoolean()) {
1412         return false;
1413     }
1414     auto jsReplacedName = pathInfo->GetProperty("name");
1415     if (!jsReplacedName->IsString()) {
1416         return false;
1417     }
1418     replacedName = jsReplacedName->ToString();
1419     auto jsReplacedIndex = pathInfo->GetProperty("index");
1420     if (!jsReplacedIndex->IsNumber()) {
1421         return false;
1422     }
1423     replacedIndex = jsReplacedIndex->ToNumber<int32_t>();
1424     return true;
1425 }
1426 
SetRecoveryFromReplaceDestination(int32_t index,bool value)1427 void JSNavigationStack::SetRecoveryFromReplaceDestination(int32_t index, bool value)
1428 {
1429     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1430     auto pathInfo = GetJsPathInfo(index);
1431     if (pathInfo->IsEmpty()) {
1432         return;
1433     }
1434     pathInfo->SetProperty<bool>("recoveryFromReplaceDestination", value);
1435 }
1436 
ExecutePopCallback(const RefPtr<NG::UINode> & uiNode,uint64_t navDestinationId,const JSRef<JSVal> & param)1437 bool JSNavigationStack::ExecutePopCallback(const RefPtr<NG::UINode>& uiNode,
1438     uint64_t navDestinationId, const JSRef<JSVal>& param)
1439 {
1440     auto navDestinationNode = AceType::DynamicCast<NG::NavDestinationGroupNode>(
1441         NG::NavigationGroupNode::GetNavDestinationNode(uiNode));
1442     CHECK_NULL_RETURN(navDestinationNode, false);
1443     auto pattern = navDestinationNode->GetPattern<NG::NavDestinationPattern>();
1444     CHECK_NULL_RETURN(pattern, false);
1445     if (pattern->GetNavDestinationId() != navDestinationId) {
1446         return false;
1447     }
1448     auto navPathInfo = AceType::DynamicCast<JSNavPathInfo>(pattern->GetNavPathInfo());
1449     CHECK_NULL_RETURN(navPathInfo, false);
1450     auto callback = navPathInfo->GetNavDestinationPopCallback();
1451     if (callback->IsEmpty()) {
1452         return false;
1453     }
1454     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "fire onPop callback: %{public}s", pattern->GetName().c_str());
1455     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1456     JSRef<JSVal> params[1];
1457     params[0] = param;
1458     callback->Call(JSRef<JSObject>(), 1, params);
1459     return true;
1460 }
1461 
HasSingletonMoved()1462 bool JSNavigationStack::HasSingletonMoved()
1463 {
1464     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1465     if (dataSourceObj_->IsEmpty()) {
1466         return false;
1467     }
1468     auto hasSingletonMoved = dataSourceObj_->GetProperty("hasSingletonMoved");
1469     if (!hasSingletonMoved->IsBoolean()) {
1470         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "hasSingletonMoved invalid!");
1471         return false;
1472     }
1473     return hasSingletonMoved->ToBoolean();
1474 }
1475 
IsTopFromSingletonMoved()1476 bool JSNavigationStack::IsTopFromSingletonMoved()
1477 {
1478     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1479     auto len = GetSize();
1480     if (len == 0) {
1481         return false;
1482     }
1483     auto top = GetJsPathInfo(len - 1);
1484     if (top->IsEmpty()) {
1485         return false;
1486     }
1487     auto isFromSingletonMoved = top->GetProperty("singletonMoved");
1488     if (!isFromSingletonMoved->IsBoolean()) {
1489         return false;
1490     }
1491     return isFromSingletonMoved->ToBoolean();
1492 }
1493 
GetNavDestinationIdInt(int32_t index)1494 uint64_t JSNavigationStack::GetNavDestinationIdInt(int32_t index)
1495 {
1496     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, -1);
1497     auto pathInfo = GetJsPathInfo(index);
1498     if (pathInfo->IsEmpty()) {
1499         return -1;
1500     }
1501     auto id = pathInfo->GetProperty("navDestinationId");
1502     if (!id->IsString()) {
1503         return -1;
1504     }
1505     auto navDestinationIdStr = id->ToString();
1506     auto navDestinationId = std::atol(navDestinationIdStr.c_str());
1507     return navDestinationId;
1508 }
1509 
GetIsForceSet(int32_t index)1510 bool JSNavigationStack::GetIsForceSet(int32_t index)
1511 {
1512     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, false);
1513     auto pathInfo = GetJsPathInfo(index);
1514     if (pathInfo->IsEmpty()) {
1515         return false;
1516     }
1517     auto isForceSet = pathInfo->GetProperty("isForceSet");
1518     if (!isForceSet->IsBoolean()) {
1519         return false;
1520     }
1521     return isForceSet->ToBoolean();
1522 }
1523 
ResetIsForceSetFlag(int32_t index)1524 void JSNavigationStack::ResetIsForceSetFlag(int32_t index)
1525 {
1526     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1527     auto pathInfo = GetJsPathInfo(index);
1528     if (pathInfo->IsEmpty()) {
1529         return;
1530     }
1531     pathInfo->SetPropertyObject("isForceSet", JsiValue::Undefined());
1532 }
1533 
ResetSingletonMoved()1534 void JSNavigationStack::ResetSingletonMoved()
1535 {
1536     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1537     if (dataSourceObj_->IsEmpty()) {
1538         return;
1539     }
1540     auto hasSingletonMoved = dataSourceObj_->GetProperty("hasSingletonMoved");
1541     if (!hasSingletonMoved->IsBoolean() || !hasSingletonMoved->ToBoolean()) {
1542         return;
1543     }
1544     auto len = GetSize();
1545     for (auto index = 0; index < len; index++) {
1546         auto info = GetJsPathInfo(index);
1547         if (info->IsEmpty()) {
1548             continue;
1549         }
1550         info->SetProperty<bool>("singletonMoved", false);
1551     }
1552     dataSourceObj_->SetProperty<bool>("hasSingletonMoved", false);
1553 }
1554 
PushIntentNavDestination(const std::string & name,const std::string & params,bool needTransition)1555 void JSNavigationStack::PushIntentNavDestination(
1556     const std::string& name, const std::string& params, bool needTransition)
1557 {
1558     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
1559     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation push intent navDestination(%{public}s)", name.c_str());
1560     if (dataSourceObj_->IsEmpty()) {
1561         return;
1562     }
1563     auto pushIntentNavDestinationFunc = dataSourceObj_->GetProperty("pushIntentNavDestination");
1564     if (!pushIntentNavDestinationFunc->IsFunction()) {
1565         return;
1566     }
1567     auto func = JSRef<JSFunc>::Cast(pushIntentNavDestinationFunc);
1568     JSRef<JSVal> arg[3];
1569     arg[0] = JSRef<JSVal>::Make(ToJSValue(name));
1570     arg[1] = JSRef<JSVal>::Make(ToJSValue(params));
1571     arg[2] = JSRef<JSVal>::Make(ToJSValue(needTransition));
1572     func->Call(dataSourceObj_, 3, arg);
1573 }
1574 } // namespace OHOS::Ace::Framework
1575