diff --git a/adapter/ohos/entrance/ace_container.cpp b/adapter/ohos/entrance/ace_container.cpp index 9affcb38b12174602965c9324cd3aa07488a3895..28a1097c4a6fb640f4d3c7b8b756325a681698d9 100644 --- a/adapter/ohos/entrance/ace_container.cpp +++ b/adapter/ohos/entrance/ace_container.cpp @@ -4381,8 +4381,8 @@ bool AceContainer::SetSystemBarEnabled(SystemBarType type, bool enable, bool ani property.enable_ = enable; property.enableAnimation_ = animation; property.settingFlag_ = static_cast( - static_cast(property.settingFlag_) | - static_cast(Rosen::SystemBarSettingFlag::ENABLE_SETTING)); + static_cast(property.settingFlag_) | + static_cast(Rosen::SystemBarSettingFlag::ENABLE_SETTING)); TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Set SystemBar: type:%{public}d, enable:%{public}d, animation:%{public}d", static_cast(type), enable, animation); if (Rosen::WMError::WM_OK != uiWindow_->SetSpecificBarProperty(winType, property)) { diff --git a/adapter/ohos/osal/page_viewport_config_ohos.cpp b/adapter/ohos/osal/page_viewport_config_ohos.cpp index 6c82dc29fb231c2868b0dfd663adb8b89421676a..bd4198d8f75b36a55e020acec9395426ae4678f1 100644 --- a/adapter/ohos/osal/page_viewport_config_ohos.cpp +++ b/adapter/ohos/osal/page_viewport_config_ohos.cpp @@ -68,8 +68,8 @@ void PageViewportConfigOhos::ApplySafeArea() auto mgr = pipeline->GetSafeAreaManager(); CHECK_NULL_VOID(mgr); BackupInfo backupInfo; - backupInfo.rootWidth = static_cast(pipeline->GetRootWidth()); - backupInfo.rootHeight = static_cast(pipeline->GetRootHeight()); + backupInfo.rootWidth = static_cast(pipeline->GetRootWidth()); + backupInfo.rootHeight = static_cast(pipeline->GetRootHeight()); TAG_LOGI(AceLogTag::ACE_NAVIGATION, "backup rootSize, width:%{public}u, height:%{public}u", backupInfo.rootWidth, backupInfo.rootHeight); for (auto& avoidArea : avoidAreas_) { diff --git a/build/libace.map b/build/libace.map index e68894968aeba02483749eb27f0dbbd65d2e4362..d333c240a8efba5201b38364d0cc3be77d011554 100644 --- a/build/libace.map +++ b/build/libace.map @@ -541,6 +541,7 @@ OHOS::Ace::NG::NGGestureRecognizer::IsInResponseLinkRecognizers*; OHOS::Ace::TouchEventTarget::GetAttachedNode*; OHOS::Ace::PipelineBase::GetImageCache*; + OHOS::Ace::NG::PanRecognizer::GetDistance*; }; local: *; diff --git a/frameworks/bridge/arkts_frontend/arkts_frontend.cpp b/frameworks/bridge/arkts_frontend/arkts_frontend.cpp index 216722300ea0736ac6a5ec94c27b0ed101382983..b85cf659e58cfd724de3f3e956aa6775bef58df8 100644 --- a/frameworks/bridge/arkts_frontend/arkts_frontend.cpp +++ b/frameworks/bridge/arkts_frontend/arkts_frontend.cpp @@ -22,6 +22,7 @@ #include "bridge/arkts_frontend/arkts_ani_utils.h" #include "bridge/arkts_frontend/ani_context_module.h" #include "bridge/arkts_frontend/entry/arkts_entry_loader.h" +#include "core/components_ng/pattern/stage/page_pattern.h" #include "core/pipeline_ng/pipeline_context.h" namespace OHOS::Ace { @@ -211,6 +212,8 @@ UIContentErrorCode ArktsFrontend::RunPage(const std::string& url, const std::str ani_class appClass; EntryLoader entryLoader(url, env_); + pageRouterManager_ = NG::PageRouterManagerFactory::CreateManager(); + if (env_->FindClass(KOALA_APP_INFO.className, &appClass) != ANI_OK) { LOGE("Cannot load main class %{public}s", KOALA_APP_INFO.className); return UIContentErrorCode::INVALID_URL; @@ -224,12 +227,10 @@ UIContentErrorCode ArktsFrontend::RunPage(const std::string& url, const std::str return UIContentErrorCode::INVALID_URL; } - std::string appUrl = "ComExampleTrivialApplication"; // TODO: use passed in url and params - std::string appParams = "ArkTSLoaderParam"; ani_string aniUrl; - env_->String_NewUTF8(appUrl.c_str(), appUrl.size(), &aniUrl); + env_->String_NewUTF8(url.c_str(), url.size(), &aniUrl); ani_string aniParams; - env_->String_NewUTF8(appParams.c_str(), appParams.size(), &aniParams); + env_->String_NewUTF8(params.c_str(), params.size(), &aniParams); ani_ref appLocal; ani_ref optionalEntry; @@ -280,6 +281,39 @@ void ArktsFrontend::AttachPipelineContext(const RefPtr& context) } } +bool ArktsFrontend::OnBackPressed() +{ + CHECK_NULL_RETURN(pageRouterManager_, false); + auto pageNode = pageRouterManager_->GetCurrentPageNode(); + CHECK_NULL_RETURN(pageNode, false); + auto pagePattern = pageNode->GetPattern(); + CHECK_NULL_RETURN(pagePattern, false); + if (pagePattern->OnBackPressed()) { + return true; + } + return pageRouterManager_->Pop(); +} + +void ArktsFrontend::OnShow() +{ + CHECK_NULL_VOID(pageRouterManager_); + auto pageNode = pageRouterManager_->GetCurrentPageNode(); + CHECK_NULL_VOID(pageNode); + auto pagePattern = pageNode->GetPattern(); + CHECK_NULL_VOID(pagePattern); + pagePattern->OnShow(); +} + +void ArktsFrontend::OnHide() +{ + CHECK_NULL_VOID(pageRouterManager_); + auto pageNode = pageRouterManager_->GetCurrentPageNode(); + CHECK_NULL_VOID(pageNode); + auto pagePattern = pageNode->GetPattern(); + CHECK_NULL_VOID(pagePattern); + pagePattern->OnHide(); +} + void* ArktsFrontend::GetShared(int32_t id) { int32_t currentInstance = id; diff --git a/frameworks/bridge/arkts_frontend/arkts_frontend.h b/frameworks/bridge/arkts_frontend/arkts_frontend.h index 6d365c127bd20a8ee21b59ec1063553523bf7a53..d40cdc00749d42d02de906f55bea7abb8865dbcc 100644 --- a/frameworks/bridge/arkts_frontend/arkts_frontend.h +++ b/frameworks/bridge/arkts_frontend/arkts_frontend.h @@ -27,6 +27,8 @@ #include "core/common/frontend.h" #include "core/pipeline_ng/pipeline_context.h" #include "frameworks/bridge/common/accessibility/accessibility_node_manager.h" +#include "frameworks/bridge/declarative_frontend/ng/page_router_manager.h" +#include "frameworks/bridge/declarative_frontend/ng/page_router_manager_factory.h" typedef struct __EtsEnv ets_env; // only include ets_napi.h in .cpp files typedef struct __ani_env ani_env; @@ -126,12 +128,9 @@ public: void UpdateState(Frontend::State state) override {} - bool OnBackPressed() override - { - return false; - } - void OnShow() override {} - void OnHide() override {} + bool OnBackPressed() override; + void OnShow() override; + void OnHide() override; void OnConfigurationUpdated(const std::string& data) override {} void OnSaveAbilityState(std::string& data) override {} void OnRestoreAbilityState(const std::string& data) override {} @@ -275,12 +274,18 @@ public: void SetAniContext(int32_t instanceId, ani_ref* context); + RefPtr GetPageRouterManager() + { + return pageRouterManager_; + } + private: RefPtr taskExecutor_; RefPtr pipeline_; ani_env* env_; // ani_env ani_ref app_; bool foregroundFrontend_ = false; + RefPtr pageRouterManager_ = nullptr; std::unordered_map storageMap_; RefPtr accessibilityManager_ diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/@ohos.arkui.UIContext.ts b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/@ohos.arkui.UIContext.ts index 7d6bcce88e56a73b2dbdd4e4dcdfbed4a0ed0122..a49c904e162567e38a5edf2a799ba942b035ce2b 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/@ohos.arkui.UIContext.ts +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/@ohos.arkui.UIContext.ts @@ -45,6 +45,9 @@ import inspector from "@ohos/arkui/inspector" import router from '@ohos/router' import promptAction from '@ohos/promptAction'; import { ContextMenu } from 'arkui/component/contextMenu'; +import { Router as RouterExt } from 'arkui/handwritten'; +import { ComputableState } from '@koalaui/runtime' +import { PeerNode } from 'arkui/PeerNode' export class UIInspector { instanceId_: int32 = -1; @@ -103,18 +106,116 @@ export class MeasureUtils { } export class Router { + instanceId_: int32 = 100000; + router_: RouterExt | undefined = undefined; + constructor(instanceId: int32) { + this.instanceId_ = instanceId; + } + public setRouter(router: RouterExt) { + this.router_ = router; + } + public getRouter(): RouterExt { + return this.router_!; + } public pushUrl(options: router.RouterOptions): Promise { - return new Promise((resolve, reject) => { - router.pushUrl(options) - }) + if (this.router_ === undefined) { + throw Error("router set in uiContext is empty"); + } + ArkUIAniModule._Common_Sync_InstanceId(this.instanceId_); + let result = new Promise((resolve, reject) => { + this.router_!.push(options); + }); + ArkUIAniModule._Common_Restore_InstanceId(); + return result; + } + + public replaceUrl(options: router.RouterOptions): Promise { + if (this.router_ === undefined) { + throw Error("router set in uiContext is empty"); + } + ArkUIAniModule._Common_Sync_InstanceId(this.instanceId_); + let result = new Promise((resolve, reject) => { + this.router_!.replace(options); + }); + ArkUIAniModule._Common_Restore_InstanceId(); + return result; } public back(options?:router.RouterOptions): void { - router.back(options) + if (this.router_ === undefined) { + throw Error("router set in uiContext is empty"); + } + ArkUIAniModule._Common_Sync_InstanceId(this.instanceId_); + this.router_!.back(options); + ArkUIAniModule._Common_Restore_InstanceId(); } public clear(): void { - router.clear() + if (this.router_ === undefined) { + throw Error("router set in uiContext is empty"); + } + ArkUIAniModule._Common_Sync_InstanceId(this.instanceId_); + this.router_!.clear(); + ArkUIAniModule._Common_Restore_InstanceId(); + } + public getLength(): string { + if (this.router_ === undefined) { + throw Error("router set in uiContext is empty"); + } + ArkUIAniModule._Common_Sync_InstanceId(this.instanceId_); + let result = this.router_!.getLength(); + ArkUIAniModule._Common_Restore_InstanceId(); + return result; + } + + public getParams(): Object { + if (this.router_ === undefined) { + throw Error("router set in uiContext is empty"); + } + ArkUIAniModule._Common_Sync_InstanceId(this.instanceId_); + let result = this.router_!.getParams(); + ArkUIAniModule._Common_Restore_InstanceId(); + return result; + } + + public getState(): router.RouterState { + if (this.router_ === undefined) { + throw Error("router set in uiContext is empty"); + } + ArkUIAniModule._Common_Sync_InstanceId(this.instanceId_); + let result = this.router_!.getState(); + ArkUIAniModule._Common_Restore_InstanceId(); + return result; + } + + public getStateByIndex(index: number): router.RouterState | undefined { + if (this.router_ === undefined) { + throw Error("router set in uiContext is empty"); + } + ArkUIAniModule._Common_Sync_InstanceId(this.instanceId_); + let result = this.router_!.getStateByIndex(index); + ArkUIAniModule._Common_Restore_InstanceId(); + return result; + } + + public getStateByUrl(url: string): Array { + if (this.router_ === undefined) { + throw Error("router set in uiContext is empty"); + } + ArkUIAniModule._Common_Sync_InstanceId(this.instanceId_); + let result = this.router_!.getStateByUrl(url); + ArkUIAniModule._Common_Restore_InstanceId(); + return result; + } + + public getStateRoot(): Array> { + if (this.router_ === undefined) { + throw Error("router set in uiContext is empty"); + } + ArkUIAniModule._Common_Sync_InstanceId(this.instanceId_); + let result = this.router_!.getEntryRootValue(); + ArkUIAniModule._Common_Restore_InstanceId(); + return result; } } @@ -214,7 +315,7 @@ export class PromptAction { export class UIContext { instanceId_: int32 = 100000; observer_ :UIObserver |null = null; - router_: Router = new Router() + router_: Router; focusController_: FocusController; componentUtils_: ComponentUtils; atomicServiceBar_: AtomicServiceBarInternal; @@ -228,6 +329,7 @@ export class UIContext { this.componentUtils_ = new ComponentUtils(instanceId); this.atomicServiceBar_ = new AtomicServiceBarInternal(instanceId); this.contextMenuController_ = new ContextMenuController(instanceId); + this.router_ = new Router(instanceId); } public getFont() : Font { let font : Font = new Font(this.instanceId_); @@ -323,9 +425,13 @@ export class UIContext { public getRouter(): Router { if (this.router_ === undefined) { - this.router_ = new Router() + this.router_ = new Router(this.instanceId_); } - return this.router_ + return this.router_; + } + + public setRouter(router: RouterExt): void { + this.router_.setRouter(router); } public animateTo(param: AnimateParam, event: (() => void)): void { diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/@ohos.router.ts b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/@ohos.router.ts index bc7f70ef9d1504a25414cd7a40661b8a9062ca10..161b41666568e7c9596e795a8ed5764e63ca291c 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/@ohos.router.ts +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/@ohos.router.ts @@ -1,6 +1,8 @@ import { InteropNativeModule } from "@koalaui/interop/InteropNativeModule" import { Router } from "arkui/handwritten" import { PeerNode } from "arkui/PeerNode" +import { UserViewBuilder } from "arkui/UserView" +import { ComputableState } from "@koalaui/runtime" namespace router { export interface RouterOptions { @@ -13,8 +15,11 @@ namespace router { Single } - export function registerPage(page: string, className: string): void { - pageEntries.set(page, className) + export interface RouterState { + index: number; + name: string; + path: string; + params: Object; } export function error(prefix: string, e: Object|null|undefined): string { @@ -29,42 +34,65 @@ namespace router { let globalRouterImp: Router | undefined export function setRouter(routerImp: Router): void { - pageEntries = new Map(); - InteropNativeModule._NativeLog("AceRouter:enter set router") globalRouterImp = routerImp - routerImp.provideClassNameResolver((page:string) => pageEntries?.get(page)) } - export function getParams(): Object | undefined { - return globalRouterImp!.getParam("arkuiOptions") + export function getParams(): Object { + return globalRouterImp!.getParams() } export function clear(): void { - InteropNativeModule._NativeLog("AceRouter:enter ohos clear") globalRouterImp!.clear() } + export function getLength(): string { + return globalRouterImp!.getLength(); + } + + export function getState(): RouterState { + return globalRouterImp!.getState(); + } + + export function getStateByIndex(index: number): RouterState | undefined { + return globalRouterImp!.getStateByIndex(index); + } + + export function getStateByUrl(url: string): Array { + return globalRouterImp!.getStateByUrl(url); + } + export function pushUrl(options: RouterOptions): void { InteropNativeModule._NativeLog("AceRouter:enter ohos pushUrl " + options.url) - globalRouterImp!.push(options.url) + globalRouterImp!.push(options) + } + + export function replaceUrl(options: RouterOptions): void { + InteropNativeModule._NativeLog("AceRouter:enter ohos replaceUrl " + options.url) + globalRouterImp!.replace(options) } export function push(options: RouterOptions): void { InteropNativeModule._NativeLog("AceRouter:enter ohos push " + options.url) - globalRouterImp!.push(options.url) - .catch((e: Object|null|undefined) => InteropNativeModule._NativeLog(error(`AceRouter:Push URL ${options.url} in router failed`, e))) + globalRouterImp!.push(options) } export function back(options?: RouterOptions): void { InteropNativeModule._NativeLog("AceRouter:enter ohos back") - globalRouterImp!.back(options?.url) - .catch((e: Object|null|undefined) => InteropNativeModule._NativeLog(error(`AceRouter:Cannot go back in router`, e))) + globalRouterImp!.back(options) } export function UpdateVisiblePagePeerNode(node: PeerNode, index: number = -1): void { InteropNativeModule._NativeLog("AceRouter:enter ohos UpdateVisiblePagePeerNode") globalRouterImp!.UpdateVisiblePagePeerNode(node, index); } + + export function getStateRoot(): Array> { + return globalRouterImp!.getEntryRootValue(); + } + + export function runPage(options: RouterOptions, builder: UserViewBuilder): void { + globalRouterImp!.runPage(options, builder) + } } export default router \ No newline at end of file diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/ArkComponentRoot.ts b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/ArkComponentRoot.ts index 693a70dd29ecc3ed68c2a987f7e70feac1ff9a47..293703ed87302a61f8473929ef6256f2f56f64ed 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/ArkComponentRoot.ts +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/ArkComponentRoot.ts @@ -21,8 +21,6 @@ import { int32 } from "@koalaui/common" import { InteropNativeModule } from "@koalaui/interop" import router from "@ohos/router" -import { CurrentRouterTransitionState, VisibilityHiding, VisibilityShowing, WithRouterTransitionState } from "./handwritten/Router"; - let _isNeedCreate: boolean = false export function setNeedCreate(isNeedCreate: boolean): boolean @@ -58,20 +56,6 @@ export function ArkComponentRoot( InteropNativeModule._NativeLog(`ArkTS ArkComponentRoot NodeAttach after content`) return } - let state = CurrentRouterTransitionState() - if (state) { - RunEffect(state.visibility, (visibility: int32) => { - switch (visibility) { - case VisibilityShowing: - component.onPageShow() - break - case VisibilityHiding: - component.onPageHide() - break - default: break - } - }) - } let shown = rememberDisposable(() => { let state = mutableState(false) scheduleCallback(() => { @@ -93,8 +77,8 @@ export function ArkComponentRoot( if (shown.value) { InteropNativeModule._NativeLog(`ArkTS ArkComponentRoot NodeAttach before WithRouterTransitionState`) InteropNativeModule._NativeLog("AceRouter:ArkComponentRoot NodeAttach, UpdateRouter page visibility state") + content(); router.UpdateVisiblePagePeerNode(node); - WithRouterTransitionState(undefined, content) // skip first frame and hide router state InteropNativeModule._NativeLog(`ArkTS ArkComponentRoot NodeAttach after WithRouterTransitionState`) } } diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/ArkUIEntry.ts b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/ArkUIEntry.ts index 79b583fab536bd11e39607356d04ebd905aa2f70..a5da39eca367c95e59340c5a6b29a41df04ae0f9 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/ArkUIEntry.ts +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/ArkUIEntry.ts @@ -31,6 +31,7 @@ import { Deserializer } from "./component/peers/Deserializer" import { StateUpdateLoop } from "./stateManagement" import { Routed } from "./handwritten/Router" import { updateLazyItems } from "./handwritten/LazyForEachImpl" +import router from "@ohos/router" setCustomEventsChecker(checkArkoalaCallbacks) @@ -145,7 +146,6 @@ function registerSyncCallbackProcessor() { export class Application { private manager: StateManager | undefined = undefined - private rootState: ComputableState | undefined = undefined private timer: MutableState | undefined = undefined private currentCrash: Object | undefined = undefined private enableDumpTree = false @@ -153,13 +153,17 @@ export class Application { private userView?: UserView private entryPoint?: EntryPoint private moduleName: string + private initUrl: string + private initParam: string private withLog = false private useNativeLog = true - constructor(useNativeLog: boolean, moduleName: string, userView?: UserView, entryPoint?: EntryPoint) { + constructor(useNativeLog: boolean, moduleName: string, initUrl: string, initParam: string, userView?: UserView, entryPoint?: EntryPoint) { this.useNativeLog = useNativeLog this.moduleName = moduleName + this.initUrl = initUrl + this.initParam = initParam this.userView = userView this.entryPoint = entryPoint } @@ -167,25 +171,22 @@ export class Application { static createMemoRootState(manager: StateManager, /** @memo */ builder: UserViewBuilder, - moduleName: string - ): ComputableState { + moduleName: string, + initUrl: string + ): void { const peer = PeerNode.generateRootPeer() - return manager.updatableNode(peer, (context: StateContext) => { - const frozen = manager.frozen - manager.frozen = true - memoEntry(context, 0, () => { - InteropNativeModule._NativeLog("AceRouter:createMemoRootState set Routed") - Routed(builder, moduleName) - }) - manager.frozen = frozen - }) + Routed(builder, moduleName, peer, initUrl) + let routerOption: router.RouterOptions = {url: initUrl} + router.runPage(routerOption, builder) } private computeRoot(): PeerNode { // let handle = ArkUINativeModule._SystemAPI_StartFrame() let result: PeerNode + let rootArray: Array> try { - result = this.rootState!.value + rootArray = router.getStateRoot() + result = rootArray[rootArray.length - 1].value } finally { // ArkUINativeModule._SystemAPI_EndFrame(handle) } @@ -207,7 +208,7 @@ export class Application { } else { throw new Error("Invalid EntryPoint") } - this.rootState = Application.createMemoRootState(this.manager!, builder, this.moduleName) + Application.createMemoRootState(this.manager!, builder, this.moduleName, this.initUrl) InteropNativeModule._NativeLog(`ArkTS Application.start before computeRoot`) root = this.computeRoot() InteropNativeModule._NativeLog(`ArkTS Application.start after computeRoot`) @@ -242,16 +243,19 @@ export class Application { private updateState() { // NativeModule._NativeLog("ARKTS: updateState") - this.updateStates(this.manager!, this.rootState!) + let rootArray = router.getStateRoot(); + let rootState = rootArray[rootArray.length - 1] + this.updateStates(this.manager!, rootState!) while (StateUpdateLoop.len) { StateUpdateLoop.consume(); - this.updateStates(this.manager!, this.rootState!) + this.updateStates(this.manager!, rootState!) } // Here we request to draw a frame and call custom components callbacks. - let root = this.rootState!.value - ArkUINativeModule._MeasureLayoutAndDraw(root.peer.ptr) - // Call callbacks and sync - callScheduledCallbacks() + rootArray.forEach((element, index) => { + let root = element.value + ArkUINativeModule._MeasureLayoutAndDraw(root.peer.ptr) + callScheduledCallbacks() + }); } updateStates(manager: StateManager, root: ComputableState) { @@ -308,7 +312,12 @@ export class Application { try { this.timer!.value = Date.now() as int64 this.loopIteration(arg0, arg1) - if (this.enableDumpTree) dumpTree(this.rootState!.value) + if (this.enableDumpTree) { + let rootArray = router.getStateRoot(); + if (rootArray.length > 0) { + dumpTree(rootArray[0]!.value) + } + } } catch (error) { if (error instanceof Error) { InteropNativeModule._NativeLog(`ArkTS Application.enter error name: ${error.name} message: ${error.message}`); @@ -385,7 +394,7 @@ export class Application { registerNativeModuleLibraryName("ArkUIGeneratedNativeModule", "ArkoalaNative_ark.z") registerNativeModuleLibraryName("TestNativeModule", "ArkoalaNative_ark.z") registerSyncCallbackProcessor() - return new Application(useNativeLog, moduleName, userView, entryPoint) + return new Application(useNativeLog, moduleName, appUrl, params, userView, entryPoint) } } diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/component/arkts/ArkUIGeneratedNativeModule.ts b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/component/arkts/ArkUIGeneratedNativeModule.ts index 4de989e3666166a762c5f8ede862c307a39a20c7..29f980a0dd923a7bfa0d65e0475bea8fe25500c8 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/component/arkts/ArkUIGeneratedNativeModule.ts +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/component/arkts/ArkUIGeneratedNativeModule.ts @@ -6948,4 +6948,16 @@ export class ArkUIGeneratedNativeModule { native static _GlobalScope_cursorControl_restoreDefault(): void @ani.unsafe.Quick native static _GlobalScope_focusControl_requestFocus(value: KStringPtr): boolean + @ani.unsafe.Quick + native static _RouterExtender_RouterPush1attribute(url: KStringPtr): KPointer + @ani.unsafe.Direct + native static _RouterExtender_RouterReplace1attribute(thisArray: KSerializerBuffer, thisLength: int32): KPointer + @ani.unsafe.Direct + native static _RouterExtender_MoveCommonUnderPageNode(commonNode: KPointer, pageNode: KPointer): void + @ani.unsafe.Direct + native static _RouterExtender_RouterBack0attribute(): void + @ani.unsafe.Quick + native static _RouterExtender_RouterRunPage(url: KStringPtr): KPointer + @ani.unsafe.Direct + native static _RouterExtender_RouterClear(): void } diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/handwritten/ArkPageTransition.ts b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/handwritten/ArkPageTransition.ts index ca0854b51ea582abbadf4ff10ff5f9c3c65344c9..2936413a90cfaaf017f32c2052e72af0d9a54793 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/handwritten/ArkPageTransition.ts +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/handwritten/ArkPageTransition.ts @@ -16,10 +16,6 @@ import { int32 } from "@koalaui/common" import { contextNode, remember, scheduleCallback } from "@koalaui/runtime" import { PeerNode, PeerNodeType } from "../PeerNode" -import { - CurrentRouter, - CurrentRouterTransitionState -} from "./Router" import { ArkPageTransitionData, ArkPageTransitionEnterComponent, @@ -39,7 +35,6 @@ enum RouterTransitionVisibility { function NotifyPageTransition(pageId: int32, style: ArkPageTransitionData, state: RouterTransitionVisibility) { const node = contextNode(PeerNodeType) // console.log("NotifyPageTransition: shall notify", "page", pageId, "state is", RouterTransitionVisibility[state]) - const router = CurrentRouter() scheduleCallback(() => { // TODO: make it driven by actual animation. /* @@ -65,10 +60,6 @@ export function ArkPageTransitionEnter( ) { const receiver = remember(() => new ArkPageTransitionEnterComponent(params)) style?.(receiver) - const state = CurrentRouterTransitionState() - if (state !== undefined && state.visibility == RouterTransitionVisibility.Showing) { - NotifyPageTransition(state.pageId, receiver, RouterTransitionVisibility.Showing) - } } /** @memo */ @@ -80,8 +71,4 @@ export function ArkPageTransitionExit( ) { const receiver = remember(() => new ArkPageTransitionExitComponent(params)) style?.(receiver) - const state = CurrentRouterTransitionState() - if (state !== undefined && state.visibility == RouterTransitionVisibility.Hiding) { - NotifyPageTransition(state.pageId, receiver, RouterTransitionVisibility.Hiding) - } } diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/handwritten/ArkRouterExtenderMaterialized.ts b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/handwritten/ArkRouterExtenderMaterialized.ts new file mode 100644 index 0000000000000000000000000000000000000000..d1e37bbb2d41d9b5363d7ed8664f4b2841d143bc --- /dev/null +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/handwritten/ArkRouterExtenderMaterialized.ts @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import router from "@ohos/router"; +import { ArkUIGeneratedNativeModule } from "#components" +import { InteropNativeModule } from "@koalaui/interop/InteropNativeModule"; +import { KPointer } from "@koalaui/interop/InteropTypes"; +import { runtimeType, RuntimeType } from "@koalaui/interop"; +import { int32, int8 } from "@koalaui/common"; +import { Serializer } from "../component/peers/Serializer"; + +export class RouterExtender { + public static routerPush(options: router.RouterOptions): KPointer { + const url = options.url as (string) + const retVal = ArkUIGeneratedNativeModule._RouterExtender_RouterPush1attribute(url) + return retVal + } + + public static routerReplace(options: router.RouterOptions, finishCallback: () => void): KPointer { + const thisSerializer : Serializer = Serializer.hold() + const url = options.url as (string) + thisSerializer.writeString(url) + let value_type : int32 = RuntimeType.UNDEFINED + value_type = runtimeType(finishCallback) + thisSerializer.writeInt8(value_type as int32) + if ((RuntimeType.UNDEFINED) != (value_type)) { + const value_value = finishCallback! as (() => void) + thisSerializer.holdAndWriteCallback(value_value) + } + const retVal = ArkUIGeneratedNativeModule._RouterExtender_RouterReplace1attribute(thisSerializer.asBuffer(), thisSerializer.length()) + thisSerializer.release() + return retVal + } + + public static routerPushUrl(options: router.RouterOptions): Promise { + return new Promise(() => {}) + } + + public static routerBack(options?: router.RouterOptions): void { + if (options) { + const url = options.url as (string) + } else { + ArkUIGeneratedNativeModule._RouterExtender_RouterBack0attribute() + } + } + + public static routerClear(): void { + ArkUIGeneratedNativeModule._RouterExtender_RouterClear() + } + + public static routerRunPage(options: router.RouterOptions): KPointer { + const url = options.url as (string) + const retVal = ArkUIGeneratedNativeModule._RouterExtender_RouterRunPage(url) + return retVal + } + + public static moveCommonUnderPageNode(commonNode: KPointer, pageNode: KPointer): void { + ArkUIGeneratedNativeModule._RouterExtender_MoveCommonUnderPageNode(commonNode, pageNode) + } +} \ No newline at end of file diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/handwritten/Router.ts b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/handwritten/Router.ts index 492bdc3251e78c84dbc8659e96675ac85d79f181..413e52fa0a17d05daf01c597fde1df6682c5b845 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/handwritten/Router.ts +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/arkui-ohos/src/handwritten/Router.ts @@ -27,9 +27,13 @@ import { RunEffect, __context, __id, + memoEntry, + GlobalStateManager, + StateContext, + ComputableState, } from "@koalaui/runtime" import { ArkUINativeModule } from "#components" -import { runtimeType, RuntimeType } from "@koalaui/interop" +import { KPointer, runtimeType, RuntimeType } from "@koalaui/interop" import router from "@ohos/router" import { EntryPoint, UserView, UserViewBuilder } from "../UserView" import { InteropNativeModule, nullptr } from "@koalaui/interop" @@ -37,7 +41,7 @@ import { PeerNode } from "../PeerNode" import { ArkUIGeneratedNativeModule, TypeChecker } from "#components" import { Visibility } from "../component" import { Serializer } from "../component/peers/Serializer" -//import { RouteType} from "../generated/ArkPageTransitionInterfaces" +import { RouterExtender } from "./ArkRouterExtenderMaterialized" // ---------------------------------------------------------- // TODO: Remove these constants when enums are fixed in Panda @@ -70,202 +74,79 @@ export interface RouterTransitionState { class VisiblePage { /** @memo */ page: UserViewBuilder - version: int32 - private transitionState: MutableState + url: string + path: string + params: Object | undefined peerNode: PeerNode | undefined - constructor( - page: UserViewBuilder, - version: int32, - visibility: int32, // TODO: Use RouterTransitionVisibility enum when enums are fixed in Panda - route?: int32 // TODO: Use RouteType enum when enums are fixed in Panda - ) { - this.page = page - this.version = version - this.transitionState = mutableState({ pageId: version, visibility, route } as RouterTransitionState) - this.peerNode = undefined - } - - setTransitionState(visibility: int32, route?: int32) { - this.transitionState.value = { pageId: this.version, visibility, route } as RouterTransitionState - } - - get transition(): RouterTransitionState { - return this.transitionState.value - } - - updatePeerNode(node: PeerNode): void { - this.peerNode = node - } -} - -class RouterState { - readonly visiblePages = arrayState() - currentActivePage = mutableState(0) constructor( page: UserViewBuilder, url: string, - params?: Map, - resolve?: (dummy: undefined) => void + path: string, + params?: Object ) { this.page = page this.url = url + this.path = path this.params = params - this.resolve = resolve - this.visiblePages.push(new VisiblePage(page, this.version.value, VisibilityVisible)) - } - /** @memo */ - page: UserViewBuilder - url: string - params?: Map - resolve?: (dummy: undefined) => void - version = mutableState(0) - - updateVisiblePagePeerNode(node: PeerNode, index: number): void { - InteropNativeModule._NativeLog("AceRouter:enter RouterState UpdateVisiblePagePeerNode") - this.visiblePages.value[index].updatePeerNode(node) - } -} - -class RouterStackEntry { - public url: string - public page: UserViewBuilder - public params?: Map - - constructor( - url: string, - page: UserViewBuilder, - params?: Map, - ) { - this.url = url - this.page = page - this.params = params - } -} - -class RouterRegistryEntry { - public url: string - public page: UserViewBuilder - - constructor( - url: string, - page: UserViewBuilder - ) { - this.url = url - this.page = page + this.peerNode = undefined } -} -export class PageInfo { - public depth: number - public page: string - constructor(depth: number, page: string) { - this.depth = depth - this.page = page + updatePeerNode(node: PeerNode): void { + this.peerNode = node } } -export type PageTransition = () => void -export type PageClassNameResolver = (page:string) => string | undefined - export interface Router { - provideClassNameResolver(resolver: PageClassNameResolver): void + push(options: router.RouterOptions): void - push(url: string, params?: Map): Promise + replace(options: router.RouterOptions): void - replace(url: string, params?: Map): Promise + pushUrl(options: router.RouterOptions): Promise - back(url?: string, params?: Map): Promise + back(options?: router.RouterOptions): void clear(): void - getParam(key: string): Object | undefined + getLength(): string + + getParams(): Object - depth: number + getState(): router.RouterState - pageInfo: PageInfo + getStateByIndex(index: number): router.RouterState | undefined - onPageTransitionEnd(pageId: int32): void + getStateByUrl(url: string): Array UpdateVisiblePagePeerNode(node: PeerNode, index?: number): void -} -const CURRENT_ROUTER = "ohos.arkoala.router" -const CURRENT_ROUTER_TRANSITION = "ohos.arkoala.router.transition" + getEntryRootValue(): Array> + + runPage(options: router.RouterOptions, builder: UserViewBuilder): void +} -class RouterImpl implements Router { - stack = new Array() - currentLocals?: Map - resolver?: PageClassNameResolver - private readonly state: RouterState +class ArkRouter implements Router { private readonly moduleName: string + private peerNodeList = new Array + public readonly visiblePages = arrayState() + private showingPageIndex : number = 0 + private rootState: Array> = new Array>() - constructor(state: RouterState, moduleName: string) { - this.state = state + constructor(moduleName: string) { this.moduleName = moduleName } - provideClassNameResolver(resolver: PageClassNameResolver): void { - this.resolver = resolver - } - - get depth(): number { - this.state.version.value - return this.stack.length - } - - set depth(depth: number) { - /* - TODO SHOPPING: readonly properties don't work - */ - } - - get pageInfo(): PageInfo { - return new PageInfo(this.stack.length, this.state.url) - } - - set pageInfo(pageInfo: PageInfo) { - /* - TODO SHOPPING: readonly properties don't work - */ - } - - resolve(route: string): Promise { - return new Promise( - (resolvePromise: (value: UserView | EntryPoint) => void, rejectPromise: (e: Error) => void) => { - let className: string | undefined = ""; - className = this.resolver?.(route) - if (className) { - InteropNativeModule._NativeLog("AceRouter:resolve className: " + route + " " + className) - // TODO: parameters. - let view = ArkUINativeModule._LoadUserView(className, "") - if (view) { - resolvePromise(view as UserView) - } else { - rejectPromise(new Error(`Cannot load class ${className}`)) - } - } else { - InteropNativeModule._NativeLog("AceRouter:resolve url: " + route); - let className: string = this.getClassName(route) - InteropNativeModule._NativeLog("AceRouter:resolve generated className: " + className); - /** @memo */ - let entry = this.RunPage(className) - if (entry) { - resolvePromise(entry) - } else { - rejectPromise(new Error(`Cannot load class ${className}`)) - } - rejectPromise(new Error(`Unknown URL ${route}`)) - } - }) - } - private getClassName(url: string): string { let className: string = this.moduleName + "/src/main/ets/" + url + "/__EntryWrapper"; return className; } - private RunPage(url: string): EntryPoint { + private getPathInfo(url: string): string { + let pathInfo = this.moduleName + "/src/main/ets/" + url + ".js" + return pathInfo + } + + private RunPage(url: string): EntryPoint | undefined { try { //@ts-ignore let runtimeLinker = getNearestNonBootRuntimeLinker(); @@ -278,279 +159,210 @@ class RouterImpl implements Router { return entryPoint } } - //@ts-ignore + //@ts-ignore catch (e: Error) { InteropNativeModule._NativeLog("AceRouter: catch RunPage error: " + e) } - return new EntryPoint() + return undefined } - pushOrReplace(url: string, push: boolean, params?: Map): Promise { - return new Promise(( - resolve: (value: undefined) => void, - reject: (reason: string | undefined) => void - ): Promise => { - return this.resolve(url) - .then((view: UserView | EntryPoint) => { - if (view instanceof UserView) { - InteropNativeModule._NativeLog("AceRouter: load page as UserView") - let page: UserViewBuilder = view.getBuilder() - if (push) { - this.stack.push(new RouterStackEntry(this.state.url, this.state.page, this.state.params)) - } - this.activate(new RouterRegistryEntry(url, page), push ? RouteType_Push : RouteType_None, params, resolve) - } else if (view instanceof EntryPoint) { - InteropNativeModule._NativeLog("AceRouter: load page as EntryPoint") - let page = view.entry - if (push) { - this.stack.push(new RouterStackEntry(this.state.url, this.state.page, this.state.params)) - } - this.activate(new RouterRegistryEntry(url, page), push ? RouteType_Push : RouteType_None, params, resolve) - } - }) - .catch((error: string | undefined): void => reject(error)) - }) + UpdateVisiblePagePeerNode(node: PeerNode, index: number = -1): void { + InteropNativeModule._NativeLog("AceRouter: router UpdateVisiblePagePeerNode, index: " + index) + if (index == -1) { + index = this.visiblePages.length - 1 + } + if (index < 0 || index > this.showingPageIndex) { + InteropNativeModule._NativeLog("AceRouter: router page size is incorrect") + return; + } + if (this.visiblePages.length > index && this.peerNodeList.length > index) { + this.visiblePages.value[index].updatePeerNode(node) + RouterExtender.moveCommonUnderPageNode(node.peer.ptr, this.peerNodeList[index]) + } } - showingPage: number = -1 - hidingPage: number = -1 - - // TODO: Use RouteType enum as route parameter when enums are fixed in Panda - private activate(entry: RouterRegistryEntry, route: int32, params: Map | undefined, resolve: (dummy: undefined) => void) { - const state = this.state - state.version.value++ - // console.log("activating", RouteType[route], entry.url, "version", state.version.value) - // let previousVisiblePageIndex = this.findIndexByVersion(state.currentActivePage.value) - let previousVisiblePageIndex = state.visiblePages.length - 1 - let previousVisiblePage = state.visiblePages.value[previousVisiblePageIndex] - InteropNativeModule._NativeLog("AceRouter: previousVisiblePage index " + previousVisiblePageIndex); - if (previousVisiblePage) { - // previousVisiblePage.setTransitionState(VisibilityHiding, route) - previousVisiblePage.transition.visibility = VisibilityHidden - previousVisiblePage.transition.route = RouteType_Pop - InteropNativeModule._NativeLog("AceRouter: previousVisiblePage visibility " + previousVisiblePage.transition.visibility); - } - state.page = entry.page - state.url = entry.url - state.params = params - state.resolve = resolve - let newVisiblePage: VisiblePage - - switch (route) { - case RouteType_Push: { - newVisiblePage = new VisiblePage(entry.page, state.version.value, VisibilityShowing, route) - state.visiblePages.splice(previousVisiblePageIndex + 1, 0, newVisiblePage) - let peerNode = state.visiblePages.value[previousVisiblePageIndex].peerNode - if (peerNode) { - InteropNativeModule._NativeLog("AceRouter: push and previous page peerNode set invisible"); - let visibleValue: Visibility = Visibility.HIDDEN - const thisSerializer : Serializer = Serializer.hold() - let value_type : int32 = RuntimeType.UNDEFINED - value_type = runtimeType(visibleValue) - thisSerializer.writeInt8(value_type as int32) - if ((RuntimeType.UNDEFINED) != (value_type)) { - const value_value = (visibleValue as Visibility) - thisSerializer.writeInt32(TypeChecker.Visibility_ToNumeric(value_value)) - } - ArkUIGeneratedNativeModule._CommonMethod_visibility(peerNode.peer.ptr, thisSerializer.asBuffer(), thisSerializer.length()) - thisSerializer.release() - } - break + push(options: router.RouterOptions): void { + let className = this.getClassName(options.url) + let entryObject = this.RunPage(className) + if (entryObject) { + let manager = GlobalStateManager.instance + let peerNode = PeerNode.generateRootPeer() + let stateNode = manager.updatableNode(peerNode, (context: StateContext) => { + const frozen = manager.frozen + manager.frozen = true + memoEntry(context, 0, () => { + entryObject!.entry() + }) + manager.frozen = frozen + }) + this.rootState.push(stateNode) + let pageNode = RouterExtender.routerPush(options) + if (pageNode === nullptr) { + InteropNativeModule._NativeLog("AceRouter:push page failed") + this.rootState.pop() + return } - case RouteType_Pop: { - const index = this.stack.length // TODO: store uid in registry to find a page - newVisiblePage = state.visiblePages.value[index] - newVisiblePage.setTransitionState(VisibilityShowing, route) - let peerNode = newVisiblePage.peerNode - if (peerNode) { - InteropNativeModule._NativeLog("AceRouter: pop and previous page peerNode set visible"); - let visibleValue: Visibility = Visibility.VISIBLE - const thisSerializer : Serializer = Serializer.hold() - let value_type : int32 = RuntimeType.UNDEFINED - value_type = runtimeType(visibleValue) - thisSerializer.writeInt8(value_type as int32) - if ((RuntimeType.UNDEFINED) != (value_type)) { - const value_value = (visibleValue as Visibility) - thisSerializer.writeInt32(TypeChecker.Visibility_ToNumeric(value_value)) - } - ArkUIGeneratedNativeModule._CommonMethod_visibility(peerNode.peer.ptr, thisSerializer.asBuffer(), thisSerializer.length()) - thisSerializer.release() - } - // remove all hidden pages removed from the stack - for (let i = state.visiblePages.length - 1; i > index; i--) { - const visibility = state.visiblePages.value[i].transition.visibility - if (visibility == VisibilityHidden) { - InteropNativeModule._NativeLog("AceRouter: dispose page, index: " + i) - // state.visiblePages.value[i].peerNode?.dispose() - state.visiblePages.splice(i, undefined) - } + this.peerNodeList.splice(this.peerNodeList.length, 0, pageNode) + + let newPage = new VisiblePage(entryObject.entry, options.url, this.getPathInfo(options.url), options.params) + this.visiblePages.splice(this.showingPageIndex + 1, 0, newPage) + this.showingPageIndex += 1 + } + } + + replace(options: router.RouterOptions): void { + let className = this.getClassName(options.url) + let entryObject = this.RunPage(className) + if (entryObject) { + let manager = GlobalStateManager.instance + let peerNode = PeerNode.generateRootPeer() + let stateNode = manager.updatableNode(peerNode, (context: StateContext) => { + const frozen = manager.frozen + manager.frozen = true + memoEntry(context, 0, () => { + entryObject!.entry() + }) + manager.frozen = frozen + }) + + this.rootState.push(stateNode) + let pageTransiTionFinishCallback = () => { + this.peerNodeList.splice(this.showingPageIndex - 1, 1) + this.visiblePages.splice(this.showingPageIndex - 1, 1) + let preNodeList = this.rootState.splice(this.showingPageIndex - 1, 1) + if (preNodeList.length > 0 && preNodeList[0]) { + preNodeList[0].dispose(); } - break + this.showingPageIndex -= 1 } - case RouteType_None: { - // TODO: can/shall we animate replace? - newVisiblePage = new VisiblePage(entry.page, state.version.value, VisibilityShowing, route) - state.visiblePages.set(previousVisiblePageIndex, newVisiblePage) - break + let pageNode = RouterExtender.routerReplace(options, pageTransiTionFinishCallback) + if (pageNode === nullptr) { + InteropNativeModule._NativeLog("AceRouter:replace page failed") + this.rootState.pop() + return } - default: - throw new Error("Illegal RouteType: " + route) + this.peerNodeList.push(pageNode) + + let newPage = new VisiblePage(entryObject.entry, options.url, this.getPathInfo(options.url), options.params) + this.visiblePages.push(newPage) + this.showingPageIndex += 1 } - this.hidingPage = previousVisiblePage?.version ?? -1 - this.showingPage = newVisiblePage.version - state.currentActivePage.value = newVisiblePage.version } - findIndexByVersion(version: int32): int32 { - const array = this.state.visiblePages - const length = array.length - for (let i = 0; i < length; i++) { - if (array.value[i].version == version) return i - } - return -1 + pushUrl(options: router.RouterOptions): Promise { + return new Promise(() => {}) } - onPageTransitionEnd(pageId: int32): void { - const index = this.findIndexByVersion(pageId) - if (index < 0) return - const page = this.state.visiblePages.value[index] - if (page.transition.visibility == VisibilityShowing) { - if (pageId == this.state.currentActivePage.value) { - console.log("PAGE VISIBLE:", page.transition.pageId) - page.setTransitionState(VisibilityVisible) - } else { - page.setTransitionState(VisibilityHidden) - } - } else if (page.transition.visibility == VisibilityHiding) { - if (index < this.stack.length) { - console.log("PAGE HIDDEN:", page.transition.pageId) - page.setTransitionState(VisibilityHidden) - } else { - console.log("PAGE REMOVED:", page.transition.pageId) - this.state.visiblePages.splice(index, 1) - } + back(options?: router.RouterOptions): void { + if (this.peerNodeList.length <= 1) { + return; + } + this.showingPageIndex = this.showingPageIndex - 1 + this.peerNodeList.pop() + RouterExtender.routerBack(options) + this.visiblePages.pop() + let preNode = this.rootState.pop() + if (preNode) { + preNode?.dispose(); } - // else { - // // console.log("ERROR: no page transition:", RouterTransitionVisibility[page.transition.visibility], page.transition.route ? RouteType[page.transition.route] : "unknown") - // } } - UpdateVisiblePagePeerNode(node: PeerNode, index: number = -1): void { - InteropNativeModule._NativeLog("AceRouter: router UpdateVisiblePagePeerNode, index: " + index) - if (index == -1) { - index = this.state.visiblePages.length - 1 - } - if (index < 0) { - InteropNativeModule._NativeLog("AceRouter: router page size is zero") + clear(): void { + InteropNativeModule._NativeLog("AceRouter: router clear") + if (this.peerNodeList.length <= 1) { return; } - this.state.updateVisiblePagePeerNode(node, index) + this.peerNodeList.splice(0, this.showingPageIndex) + this.visiblePages.splice(0, this.showingPageIndex) + this.rootState.splice(0, this.showingPageIndex) + RouterExtender.routerClear(); + this.showingPageIndex = 0 } - push(url: string, params?: Map): Promise { - InteropNativeModule._NativeLog("AceRouter: router push") - return this.pushOrReplace(url, true, params) + getParams(): Object { + let curPage = this.visiblePages.at(this.showingPageIndex) + return curPage.params !== undefined ? curPage.params! : new Object() } - replace(url: string, params?: Map): Promise { - return this.pushOrReplace(url, false, params) + getLength(): string { + return String(this.visiblePages.length) } - back(url?: string, params?: Map): Promise { - InteropNativeModule._NativeLog("AceRouter: router back") - return new Promise(( - resolve: (dummy: undefined) => void, - reject: (reason: string | undefined) => void - ): void => { - let entry: RouterStackEntry | undefined = undefined - if (url) { - for (let i = this.stack.length - 1; i >= 0; i--) { - let element = this.stack[i] - if (element.url == url) { - entry = element - this.stack.splice(i) - break - } - } - } else { - entry = this.stack.length > 0 ? this.stack.pop() : undefined - } - if (entry) { - this.activate( - new RouterRegistryEntry(entry.url, entry.page), - RouteType_Pop, - params ?? entry.params, - resolve - ) - } else { - reject(`history is empty`) + getState(): router.RouterState { + let curPage = this.visiblePages.at(this.showingPageIndex) + let state: router.RouterState = { + index: this.showingPageIndex, + name: curPage.url, + path: curPage.path, + params: curPage.params !== undefined ? curPage.params! : new Object() + } as router.RouterState + return state + } + + getStateByIndex(index: number): router.RouterState | undefined { + if (index > this.showingPageIndex) { + return undefined + } + let page = this.visiblePages.at(index) + let state: router.RouterState = { + index: index, + name: page.url, + path: page.path, + params: page.params !== undefined ? page.params! : new Object() + } as router.RouterState + return state + } + + getStateByUrl(url: string): Array { + let retVal: Array = new Array() + this.visiblePages.value.forEach((element, index) => { + if (element.url === url) { + let state: router.RouterState = { + index: index, + name: element.url, + path: element.path, + params: element.params !== undefined ? element.params! : new Object() + } as router.RouterState + retVal.push(state) } }) + return retVal } - clear(): void { - InteropNativeModule._NativeLog("AceRouter: router clear") - for (let i = 0; i < this.state.visiblePages.length - 1; i++) { - this.state.visiblePages.value[i].peerNode?.dispose(); - } - if (this.state.visiblePages.length > 1) { - this.state.visiblePages.splice(0, this.state.visiblePages.length - 1) - } - if (this.stack.length > 1) { - this.stack.splice(0, this.stack.length -1) - } + getEntryRootValue(): Array> { + return this.rootState } - getParam(key: string): Object | undefined { - return this.state.params?.get(key) + runPage(options: router.RouterOptions, builder: UserViewBuilder): void { + let manager = GlobalStateManager.instance + let peerNode = PeerNode.generateRootPeer() + let stateNode = manager.updatableNode(peerNode, (context: StateContext) => { + const frozen = manager.frozen + manager.frozen = true + memoEntry(context, 0, builder) + manager.frozen = frozen + }) + + let pageNode = RouterExtender.routerRunPage(options) + let node: PeerNode = stateNode.value + this.rootState.push(stateNode) + this.peerNodeList.splice(this.peerNodeList.length, 0, pageNode) + + let newPage = new VisiblePage(builder, options.url, this.getPathInfo(options.url), options.params) + this.visiblePages.splice(0, 0, newPage) + this.visiblePages.value[this.showingPageIndex].updatePeerNode(node) + RouterExtender.moveCommonUnderPageNode(node.peer.ptr, this.peerNodeList[this.showingPageIndex]) } } -/** @memo */ export function Routed( /** @memo */ initial: () => void, moduleName: string, + rootPeer: PeerNode, initialUrl?: string, ): void { - const routerState = remember(() => new RouterState(initial, initialUrl ?? "_initial_")) - const routerImp = remember(() => { - let routerImp = new RouterImpl(routerState, moduleName) - // Install default global router. - router.setRouter(routerImp) - return routerImp - }) - RunEffect<((dummy: undefined) => void) | undefined>(routerState.resolve, (resolve?: (dummy: undefined) => void): void => { resolve?.(undefined) }) - contextLocalScope(CURRENT_ROUTER, routerImp, () => { - RepeatByArray( - __context(), - __id(), - routerState.visiblePages.value, - (page: VisiblePage, index: int32): int32 => { return page.version }, - (__memo_context: __memo_context_type, __memo_id: __memo_id_type,page: VisiblePage, index: int32): void => { - WithRouterTransitionState(page.transition, () => { - page.page() - }) - } - ) - }) -} - -/** @memo */ -export function CurrentRouter(): Router | undefined { - return contextLocal(CURRENT_ROUTER)?.value -} - -/** @memo */ -export function CurrentRouterTransitionState(): RouterTransitionState | undefined { - return contextLocal(CURRENT_ROUTER_TRANSITION)?.value -} - -/** @memo */ -export function WithRouterTransitionState( - transition: RouterTransitionState | undefined, - /** @memo */ - content: () => void -) { - contextLocalScope(CURRENT_ROUTER_TRANSITION, transition, content) + let routerImp = new ArkRouter(moduleName) + // Install default global router. + router.setRouter(routerImp) } diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/components.gni b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/components.gni index 432863c55dfa2f6205df0a0ee9bf0335e2d325d6..c28b2ba2ac3a596768f434b77f59106c667b975b 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/components.gni +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala-arkts/components.gni @@ -252,6 +252,7 @@ arkui_files = [ "arkui-preprocessed/arkui/handwritten/ArkNavPathStack.ets", "arkui-preprocessed/arkui/handwritten/ArkPageTransition.ets", "arkui-preprocessed/arkui/handwritten/ArkPageTransitionData.ets", + "arkui-preprocessed/arkui/handwritten/ArkRouterExtenderMaterialized.ets", "arkui-preprocessed/arkui/handwritten/ArkStateStyle.ets", "arkui-preprocessed/arkui/handwritten/ForeignFunctions.ets", "arkui-preprocessed/arkui/handwritten/GridItemOpsHandWritten.ets", diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/arkoala_api_generated.h b/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/arkoala_api_generated.h index 110ada6f7218050181e1418c908cb5034c12ab52..ba83b2df398046bd1b78bf461609db3d47739cee 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/arkoala_api_generated.h +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/arkoala_api_generated.h @@ -26821,6 +26821,15 @@ typedef struct GENERATED_ArkUIPromptActionAccessor { void (*showToast)(const Ark_ShowToastOptions* value); } GENERATED_ArkUIPromptActionAccessor; +typedef struct GENERATED_ArkUIRouterExtenderAccessor { + Ark_NativePointer (*push)(const Ark_String* url); + Ark_NativePointer (*replace)(const Ark_String* url, const Opt_Callback_Void* finishCallback); + void (*moveCommonUnderPageNode)(Ark_NativePointer commonNode, Ark_NativePointer pageNode); + void (*back)(); + Ark_NativePointer (*runPage)(const Ark_String* url); + void (*clear)(); +} GENERATED_ArkUIRouterExtenderAccessor; + /** * An API to control an implementation. When making changes modifying binary * layout, i.e. adding new events - increase ARKUI_API_VERSION above for binary @@ -27157,6 +27166,7 @@ typedef struct GENERATED_ArkUIAccessors { const GENERATED_ArkUILinearIndicatorControllerAccessor* (*getLinearIndicatorControllerAccessor)(); const GENERATED_ArkUIGlobalScopeAccessor* (*getGlobalScopeAccessor)(); const GENERATED_ArkUIPromptActionAccessor* (*getPromptActionAccessor)(); + const GENERATED_ArkUIRouterExtenderAccessor* (*getRouterExtenderAccessor)(); } GENERATED_ArkUIAccessors; typedef struct GENERATED_ArkUIGraphicsAPI { diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/bridge_generated.cc b/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/bridge_generated.cc index 85801275728c794bcd533c059b4ba7cf59aa043e..22269c3177fab1b6aaac0f60e319292c0435f879 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/bridge_generated.cc +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/bridge_generated.cc @@ -44566,6 +44566,40 @@ Ark_Boolean impl_GlobalScope_focusControl_requestFocus(const KStringPtr& value) return GetAccessors()->getGlobalScopeAccessor()->focusControl_requestFocus((const Ark_String*) (&value)); } KOALA_INTEROP_1(GlobalScope_focusControl_requestFocus, Ark_Boolean, KStringPtr) +Ark_NativePointer impl_RouterExtender_RouterPush1attribute(const KStringPtr& value) { + return GetAccessors()->getRouterExtenderAccessor()->push((const Ark_String*)(&value)); +} +KOALA_INTEROP_1(RouterExtender_RouterPush1attribute, Ark_NativePointer, KStringPtr) +Ark_NativePointer impl_RouterExtender_RouterReplace1attribute(KSerializerBuffer thisArray, int32_t thisLength) { + Deserializer thisDeserializer(thisArray, thisLength); + const auto url = static_cast(thisDeserializer.readString()); + const auto value_value_buf_runtimeType = static_cast(thisDeserializer.readInt8()); + Opt_Callback_Void value_value_buf = {}; + value_value_buf.tag = value_value_buf_runtimeType == INTEROP_RUNTIME_UNDEFINED ? INTEROP_TAG_UNDEFINED : INTEROP_TAG_OBJECT; + if ((INTEROP_RUNTIME_UNDEFINED) != (value_value_buf_runtimeType)) + { + value_value_buf.value = {thisDeserializer.readCallbackResource(), reinterpret_cast(thisDeserializer.readPointerOrDefault(reinterpret_cast(getManagedCallbackCaller(Kind_Callback_Void)))), reinterpret_cast(thisDeserializer.readPointerOrDefault(reinterpret_cast(getManagedCallbackCallerSync(Kind_Callback_Void))))}; + } + Opt_Callback_Void value_value = value_value_buf; + return GetAccessors()->getRouterExtenderAccessor()->replace((const Ark_String*)(&url) ,(const Opt_Callback_Void*)&value_value); +} +KOALA_INTEROP_DIRECT_2(RouterExtender_RouterReplace1attribute, Ark_NativePointer, KSerializerBuffer, int32_t) +void impl_RouterExtender_MoveCommonUnderPageNode(Ark_NativePointer commonNode, Ark_NativePointer pageNode) { + return GetAccessors()->getRouterExtenderAccessor()->moveCommonUnderPageNode(commonNode, pageNode); +} +KOALA_INTEROP_DIRECT_V2(RouterExtender_MoveCommonUnderPageNode, Ark_NativePointer, Ark_NativePointer) +void impl_RouterExtender_RouterBack0attribute() { + return GetAccessors()->getRouterExtenderAccessor()->back(); +} +KOALA_INTEROP_DIRECT_V0(RouterExtender_RouterBack0attribute) +Ark_NativePointer impl_RouterExtender_RouterRunPage(const KStringPtr& value) { + return GetAccessors()->getRouterExtenderAccessor()->runPage((const Ark_String*)(&value)); +} +KOALA_INTEROP_1(RouterExtender_RouterRunPage, Ark_NativePointer, KStringPtr) +void impl_RouterExtender_RouterClear() { + GetAccessors()->getRouterExtenderAccessor()->clear(); +} +KOALA_INTEROP_DIRECT_V0(RouterExtender_RouterClear) Ark_Int64 impl_UIStateGet(Ark_NativePointer thisPtr) { return GetNodeModifiers()->getUIStateModifier()->getUIState(thisPtr); } diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/callback_managed_caller.cc b/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/callback_managed_caller.cc index 369014466b73b9364a30fe6daead360d6061e4bb..a61b8346ae0f1cf082fd09ffa495b0f5d9fa3bdb 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/callback_managed_caller.cc +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/callback_managed_caller.cc @@ -6041,7 +6041,8 @@ void callManagedOnTextPickerChangeCallback(Ark_Int32 resourceId, Ark_Union_Strin argsSerializer.writeInt8(1); const auto selectItem_1 = selectItem.value1; argsSerializer.writeInt32(selectItem_1.length); - for (size_t i = 0; i < static_cast(selectItem_1.length); i++) { + const int maxLen = std::min(selectItem_1.length, INT_MAX); + for (int i = 0; i < maxLen; i++) { const Ark_String selectItem_1_element = selectItem_1.array[i]; argsSerializer.writeString(selectItem_1_element); } @@ -6081,7 +6082,8 @@ void callManagedOnTextPickerChangeCallbackSync(Ark_VMContext vmContext, Ark_Int3 argsSerializer.writeInt8(1); const auto selectItem_1 = selectItem.value1; argsSerializer.writeInt32(selectItem_1.length); - for (size_t i = 0; i < static_cast(selectItem_1.length); i++) { + const int maxLen = std::min(selectItem_1.length, INT_MAX); + for (int i = 0; i < maxLen; i++) { const Ark_String selectItem_1_element = selectItem_1.array[i]; argsSerializer.writeString(selectItem_1_element); } @@ -6929,7 +6931,8 @@ void callManagedTextPickerScrollStopCallback(Ark_Int32 resourceId, Ark_Union_Str argsSerializer.writeInt8(1); const auto value_1 = value.value1; argsSerializer.writeInt32(value_1.length); - for (size_t i = 0; i < static_cast(value_1.length); i++) { + const int maxLen = std::min(value_1.length, INT_MAX); + for (int i = 0; i < maxLen; i++) { const Ark_String value_1_element = value_1.array[i]; argsSerializer.writeString(value_1_element); } diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/dummy_impl.cc b/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/dummy_impl.cc index 6176fd5525b6b55a23f0212dc0dddeda265106b9..01d882c1caf27b34bce46baa2095a43d1af95fd0 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/dummy_impl.cc +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/dummy_impl.cc @@ -43146,6 +43146,50 @@ namespace OHOS::Ace::NG::GeneratedModifier { return 0; } } // GlobalScopeAccessor + namespace RouterExtenderAccessor { + Ark_NativePointer PushImpl(const Ark_String* url) + { + if (!needGroupedLog(1)) + return; + string out("push("); + WriteToString(&out, url); + out.append(") \n"); + out.append("[return fnPtr(dummyClassFinalizer)] \n"); + appendGroupedLog(1, out); + } + + void MoveCommonUnderPageNode(Ark_NativePointer commonNode, Ark_NativePointer pageNode) + { + if (!needGroupedLog(1)) + return; + string out("moveCommonUnderPageNode("); + WriteToString(&out, commonNode); + out.append(", "); + WriteToString(&out, pageNode); + out.append(") \n"); + appendGroupedLog(1, out); + } + + void BackImpl() + { + if (!needGroupedLog(1)) + return; + string out("back("); + out.append(") \n"); + appendGroupedLog(1, out); + } + + Ark_NativePointer RunPageImpl(const Ark_String* url) + { + if (!needGroupedLog(1)) + return; + string out("runPage("); + WriteToString(&out, url); + out.append(") \n"); + out.append("[return fnPtr(dummyClassFinalizer)] \n"); + appendGroupedLog(1, out); + } + } // RouterExtenderAccessor const GENERATED_ArkUIAnimationExtenderAccessor* GetAnimationExtenderAccessor() { static const GENERATED_ArkUIAnimationExtenderAccessor AnimationExtenderAccessorImpl { @@ -46945,6 +46989,17 @@ namespace OHOS::Ace::NG::GeneratedModifier { struct GlobalScopePeer { virtual ~GlobalScopePeer() = default; }; + const GENERATED_ArkUIRouterExtenderAccessor* GetRouterExtenderAccessor() + { + static const GENERATED_ArkUIRouterExtenderAccessor RouterExtenderAccessorImpl { + RouterExtenderAccessor::PushImpl, + RouterExtenderAccessor::MoveCommonUnderPageNode, + RouterExtenderAccessor::BackImpl, + RouterExtenderAccessor::RunPageImpl + }; + return &RouterExtenderAccessorImpl; + } + const GENERATED_ArkUIAccessors* GENERATED_GetArkUIAccessors() { static const GENERATED_ArkUIAccessors accessorsImpl = { @@ -47154,6 +47209,7 @@ namespace OHOS::Ace::NG::GeneratedModifier { GetLinearIndicatorControllerAccessor, GetGlobalScopeAccessor, GetPromptActionAccessor, + GetRouterExtenderAccessor, }; return &accessorsImpl; } diff --git a/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/real_impl.cc b/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/real_impl.cc index 46b13579feb528e29f0b8c66919a96f9fa6a1ce2..6ecd34c1d92896d1ebf053fdcfa02dac2b8ad3a1 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/real_impl.cc +++ b/frameworks/bridge/arkts_frontend/koala_projects/arkoala/framework/native/src/generated/real_impl.cc @@ -20711,6 +20711,20 @@ namespace OHOS::Ace::NG::GeneratedModifier { return {}; } } // GlobalScopeAccessor + namespace RouterExtenderAccessor { + Ark_NativePointer PushImpl(const Ark_String* url) + { + } + void MoveCommonUnderPageNode(Ark_NativePointer commonNode, Ark_NativePointer pageNode) + { + } + void BackImpl() + { + } + Ark_NativePointer RunPageImpl(const Ark_String* url) + { + } + } // RouterExtenderAccessor const GENERATED_ArkUIAnimationExtenderAccessor* GetAnimationExtenderAccessor() { static const GENERATED_ArkUIAnimationExtenderAccessor AnimationExtenderAccessorImpl { @@ -24523,6 +24537,16 @@ namespace OHOS::Ace::NG::GeneratedModifier { struct GlobalScopePeer { virtual ~GlobalScopePeer() = default; }; + const GENERATED_ArkUIRouterExtenderAccessor* GetRouterExtenderAccessor() + { + static const GENERATED_ArkUIRouterExtenderAccessor RouterExtenderAccessorImpl { + RouterExtenderAccessor::PushImpl, + RouterExtenderAccessor::MoveCommonUnderPageNode, + RouterExtenderAccessor::BackImpl, + RouterExtenderAccessor::RunPageImpl + }; + return &RouterExtenderAccessorImpl; + } const GENERATED_ArkUIAccessors* GENERATED_GetArkUIAccessors() { static const GENERATED_ArkUIAccessors accessorsImpl = { @@ -24734,6 +24758,7 @@ namespace OHOS::Ace::NG::GeneratedModifier { GetLinearIndicatorControllerAccessor, GetGlobalScopeAccessor, GetPromptActionAccessor, + GetRouterExtenderAccessor, }; return &accessorsImpl; } diff --git a/frameworks/bridge/arkts_frontend/koala_projects/interop/src/cpp/DeserializerBase.h b/frameworks/bridge/arkts_frontend/koala_projects/interop/src/cpp/DeserializerBase.h index dca0cac10ae379e245ccad22904ac2227d79d178..1699bc4977be432fc05f22dc72b9491bcf818f97 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/interop/src/cpp/DeserializerBase.h +++ b/frameworks/bridge/arkts_frontend/koala_projects/interop/src/cpp/DeserializerBase.h @@ -347,8 +347,9 @@ public: toClean.push_back(keys); } values = malloc(length * sizeof(V)); - memset(values, 0, length * sizeof(V)); - toClean.push_back(values); + if (values && memset_s(values, length * sizeof(V), 0, length * sizeof(V)) == 0) { + toClean.push_back(values); + } } map->size = length; map->keys = reinterpret_cast(keys); diff --git a/frameworks/bridge/arkts_frontend/koala_projects/interop/src/cpp/SerializerBase.h b/frameworks/bridge/arkts_frontend/koala_projects/interop/src/cpp/SerializerBase.h index 745c3ec24e6103c9970cab9d84e06d9ea67420c3..46981ac502f9f3857aaa66bb0cd2ed08b20fb46a 100644 --- a/frameworks/bridge/arkts_frontend/koala_projects/interop/src/cpp/SerializerBase.h +++ b/frameworks/bridge/arkts_frontend/koala_projects/interop/src/cpp/SerializerBase.h @@ -90,7 +90,12 @@ public: SerializerBase(CallbackResourceHolder* resourceHolder = nullptr): position(0), ownData(true), resourceHolder(resourceHolder) { this->dataLength = 256; - this->data = reinterpret_cast(malloc(this->dataLength)); + auto newData = malloc(this->dataLength); + if (newData) { + this->data = reinterpret_cast(newData); + } else { + this->data = nullptr; + } } SerializerBase(uint8_t* data, uint32_t dataLength, CallbackResourceHolder* resourceHolder = nullptr): diff --git a/frameworks/bridge/declarative_frontend/jsview/js_navdestination.cpp b/frameworks/bridge/declarative_frontend/jsview/js_navdestination.cpp index 7eedce1b30f4686ec1d7f5702849d3b311ea3f25..8d8e5d4ef621d4cb2f37f68a9354bb38a9f0f4b9 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_navdestination.cpp +++ b/frameworks/bridge/declarative_frontend/jsview/js_navdestination.cpp @@ -454,7 +454,7 @@ void JSNavDestination::SetMenus(const JSCallbackInfo& info) } NG::NavigationMenuOptions options; - if (info.Length() > 1) { + if (info.Length() > 1 && info[1]->IsObject()) { auto optObj = JSRef::Cast(info[1]); auto moreButtonProperty = optObj->GetProperty(MORE_BUTTON_OPTIONS_PROPERTY); JSNavigationUtils::ParseMenuOptions(moreButtonProperty, options); @@ -618,7 +618,7 @@ void JSNavDestination::SetToolBarConfiguration(const JSCallbackInfo& info) targetNode, info, JSRef::Cast(info[0]), toolBarItems); } NG::MoreButtonOptions toolbarMoreButtonOptions; - if (info.Length() > 1) { + if (info.Length() > 1 && info[1]->IsObject()) { auto optObj = JSRef::Cast(info[1]); auto moreButtonProperty = optObj->GetProperty(MORE_BUTTON_OPTIONS_PROPERTY); JSNavigationUtils::ParseToolBarMoreButtonOptions(moreButtonProperty, toolbarMoreButtonOptions); diff --git a/frameworks/bridge/declarative_frontend/jsview/js_navigation.cpp b/frameworks/bridge/declarative_frontend/jsview/js_navigation.cpp index 1ebbc8ea9b8d5896b22b0b517c426c4b7b76da80..918c5792595b39c7a87d6a44aec7878bcacbe927 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_navigation.cpp +++ b/frameworks/bridge/declarative_frontend/jsview/js_navigation.cpp @@ -512,7 +512,7 @@ void JSNavigation::SetToolbarConfiguration(const JSCallbackInfo& info) targetNode, info, JSRef::Cast(info[0]), toolbarItems); } NG::MoreButtonOptions toolbarMoreButtonOptions; - if (info.Length() > 1) { + if (info.Length() > 1 && info[1]->IsObject()) { auto optObj = JSRef::Cast(info[1]); auto moreButtonProperty = optObj->GetProperty(MORE_BUTTON_OPTIONS_PROPERTY); JSNavigationUtils::ParseToolBarMoreButtonOptions(moreButtonProperty, toolbarMoreButtonOptions); @@ -547,7 +547,7 @@ void JSNavigation::SetMenus(const JSCallbackInfo& info) } NG::NavigationMenuOptions options; - if (info.Length() > 1) { + if (info.Length() > 1 && info[1]->IsObject()) { auto optObj = JSRef::Cast(info[1]); auto moreButtonProperty = optObj->GetProperty(MORE_BUTTON_OPTIONS_PROPERTY); JSNavigationUtils::ParseMenuOptions(moreButtonProperty, options); diff --git a/frameworks/bridge/declarative_frontend/jsview/js_xcomponent.cpp b/frameworks/bridge/declarative_frontend/jsview/js_xcomponent.cpp index 2c3a3a783b9c70750dc05c0ebbf36003450fe63f..57ba4a42c5b36cf81f8d795c98e72ca7a400bb60 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_xcomponent.cpp +++ b/frameworks/bridge/declarative_frontend/jsview/js_xcomponent.cpp @@ -243,6 +243,9 @@ void JSXComponent::Create(const JSCallbackInfo& info) void JSXComponent::ExtractInfoToXComponentOptions( XComponentOptions& options, JSRef& controllerObj, const JSCallbackInfo& info) { + if (!info[0]->IsObject()) { + return; + } auto paramObject = JSRef::Cast(info[0]); auto id = paramObject->GetProperty("id"); auto type = paramObject->GetProperty("type"); diff --git a/frameworks/bridge/declarative_frontend/ng/page_router_manager.cpp b/frameworks/bridge/declarative_frontend/ng/page_router_manager.cpp index 5cd18422781896f8674db808c903320d9c2797c0..4df4ee53ba0dd30f2e269851fe0a68d4423df524 100644 --- a/frameworks/bridge/declarative_frontend/ng/page_router_manager.cpp +++ b/frameworks/bridge/declarative_frontend/ng/page_router_manager.cpp @@ -209,6 +209,224 @@ void PageRouterManager::Push(const RouterPageInfo& target) StartPush(target); } +RefPtr PageRouterManager::PushExtender(const RouterPageInfo& target) +{ + CHECK_RUN_ON(JS); + if (inRouterOpt_) { + auto context = PipelineContext::GetCurrentContext(); + CHECK_NULL_RETURN(context, nullptr); + context->PostAsyncEvent( + [weak = WeakClaim(this), target]() { + auto router = weak.Upgrade(); + CHECK_NULL_VOID(router); + router->Push(target); + }, + "ArkUIPageRouterPush", TaskExecutor::TaskType::JS); + return nullptr; + } + RouterOptScope scope(this); + if (target.url.empty()) { + TAG_LOGE(AceLogTag::ACE_ROUTER, "push url is empty"); + return nullptr; + } + auto context = PipelineContext::GetCurrentContext(); + CHECK_NULL_RETURN(context, nullptr); + if (GetStackSize() >= MAX_ROUTER_STACK_SIZE && !context->GetForceSplitEnable()) { + TAG_LOGW(AceLogTag::ACE_ROUTER, "StartPush exceeds maxStackSize."); + if (target.errorCallback != nullptr) { + target.errorCallback("The pages are pushed too much.", ERROR_CODE_PAGE_STACK_FULL); + } + return nullptr; + } + RouterPageInfo info = target; + info.path = info.url + ".js"; + if (info.path.empty()) { + TAG_LOGW(AceLogTag::ACE_ROUTER, "empty path found in StartPush with url: %{public}s", info.url.c_str()); + if (info.errorCallback != nullptr) { + info.errorCallback("The uri of router is not exist.", ERROR_CODE_URI_ERROR); + } + return nullptr; + } + + CleanPageOverlay(); + UpdateSrcPage(); + + if (info.routerMode == RouterMode::SINGLE) { + auto pageInfo = FindPageInStack(info.url); + if (pageInfo.second) { + // find page in stack, move postion and update params. + auto pagePattern = pageInfo.second->GetPattern(); + if (pagePattern) { + pagePattern->FireOnNewParam(info.params); + } + MovePageToFront(pageInfo.first, pageInfo.second, info, true); + return pagePattern->GetHost(); + } + auto index = FindPageInRestoreStack(info.url); + if (index != INVALID_PAGE_INDEX) { + // find page in restore page, create page, move position and update params. + RestorePageWithTarget(index, false, info, RestorePageDestination::TOP); + return pageInfo.second; + } + } + auto loadPageSuccess = LoadPageExtender(GenerateNextPageId(), info, true, true, true); + if (!loadPageSuccess) { + return nullptr; + } + auto pageNode = pageRouterStack_.back().Upgrade(); + return pageNode; +} + +RefPtr PageRouterManager::ReplaceExtender( + const RouterPageInfo& target, std::function&& finishCallback) +{ + CHECK_RUN_ON(JS); + if (inRouterOpt_) { + auto context = PipelineContext::GetCurrentContext(); + CHECK_NULL_RETURN(context, nullptr); + context->PostAsyncEvent( + [weak = WeakClaim(this), target]() { + auto router = weak.Upgrade(); + CHECK_NULL_VOID(router); + router->Replace(target); + }, + "ArkUIPageRouterReplace", TaskExecutor::TaskType::JS); + return nullptr; + } + RouterOptScope scope(this); + CleanPageOverlay(); + if (target.url.empty()) { + return nullptr; + } + + RouterPageInfo info = target; + info.path = info.url + ".js"; + if (info.path.empty()) { + TAG_LOGW(AceLogTag::ACE_ROUTER, "empty path found in StartReplace with url: %{public}s", info.url.c_str()); + if (info.errorCallback != nullptr) { + info.errorCallback("The uri of router is not exist.", ERROR_CODE_URI_ERROR_LITE); + } + return nullptr; + } + UpdateSrcPage(); + + auto pipelineContext = PipelineContext::GetCurrentContext(); + CHECK_NULL_RETURN(pipelineContext, nullptr); +#if defined(ENABLE_SPLIT_MODE) + auto stageManager = pipelineContext->GetStageManager(); + CHECK_NULL_RETURN(stageManager, nullptr); +#endif + TAG_LOGI(AceLogTag::ACE_ROUTER, + "router replace in new lifecycle(API version > 11), replace mode: %{public}d, url: %{public}s", + static_cast(info.routerMode), info.url.c_str()); + auto popNode = GetCurrentPageNode(); + int32_t popIndex = static_cast(pageRouterStack_.size()) - 1; + bool findPage = false; + if (info.routerMode == RouterMode::SINGLE) { + auto pageInfo = FindPageInStack(info.url); + // haven't find page by named route's name. Try again with its page path. + if (pageInfo.second == nullptr && info.isNamedRouterMode) { + std::string pagePath = Framework::JsiDeclarativeEngine::GetPagePath(info.url); + pageInfo = FindPageInStack(pagePath); + } + auto replacePageNode = pageInfo.second; + if (pageInfo.first == popIndex) { + // replace top self in SINGLE mode, do nothing. + CHECK_NULL_RETURN(replacePageNode, nullptr); + auto pagePattern = pageInfo.second->GetPattern(); + if (pagePattern) { + pagePattern->FireOnNewParam(info.params); + } + return replacePageNode; + } + if (replacePageNode) { + // find page in stack, move position and update params. +#if defined(ENABLE_SPLIT_MODE) + stageManager->SetIsNewPageReplacing(true); +#endif + MovePageToFront(pageInfo.first, replacePageNode, info, false, true, false); +#if defined(ENABLE_SPLIT_MODE) + stageManager->SetIsNewPageReplacing(false); +#endif + popIndex = popIndex - 1; + findPage = true; + auto pagePattern = replacePageNode->GetPattern(); + if (pagePattern) { + pagePattern->FireOnNewParam(info.params); + } + } else { + auto index = FindPageInRestoreStack(info.url); + if (index != INVALID_PAGE_INDEX) { + // find page in restore page, create page, move position and update params. + RestorePageWithTarget(index, false, info, RestorePageDestination::BELLOW_TOP, false); + return replacePageNode; + } + } + } + RefPtr pageNode = nullptr; + if (!findPage) { + isNewPageReplacing_ = true; +#if defined(ENABLE_SPLIT_MODE) + stageManager->SetIsNewPageReplacing(true); +#endif + bool loadPageSuccess = LoadPageExtender(GenerateNextPageId(), info, false, false); + if (loadPageSuccess) { + pageNode = pageRouterStack_.back().Upgrade(); + } +#if defined(ENABLE_SPLIT_MODE) + stageManager->SetIsNewPageReplacing(false); +#endif + isNewPageReplacing_ = false; + } + if (popIndex < 0 || popNode == GetCurrentPageNode()) { + return pageNode; + } + CHECK_NULL_RETURN(popNode, nullptr); + auto pagePattern = popNode->GetPattern(); + CHECK_NULL_RETURN(pagePattern, nullptr); + pagePattern->SetOnNodeDisposeCallback(std::move(finishCallback)); + auto iter = pageRouterStack_.begin(); + std::advance(iter, popIndex); + auto lastIter = pageRouterStack_.erase(iter); + pageRouterStack_.emplace_back(WeakPtr(AceType::DynamicCast(popNode))); + popNode->MovePosition(GetLastPageIndex()); + for (auto iter = lastIter; iter != pageRouterStack_.end(); ++iter, ++popIndex) { + auto page = iter->Upgrade(); + if (!page) { + continue; + } + if (page == popNode) { + // do not change index of page that will be replaced. + continue; + } + auto pagePattern = page->GetPattern(); + pagePattern->GetPageInfo()->SetPageIndex(popIndex + 1); + } +#if defined(ENABLE_SPLIT_MODE) + stageManager->SetIsNewPageReplacing(true); +#endif + PopPage("", false, false); +#if defined(ENABLE_SPLIT_MODE) + stageManager->SetIsNewPageReplacing(false); +#endif + return pageNode; +} + +RefPtr PageRouterManager::RunPageExtender(const RouterPageInfo& target) +{ + PerfMonitor::GetPerfMonitor()->SetAppStartStatus(); + ACE_SCOPED_TRACE("PageRouterManager::RunPage"); + CHECK_RUN_ON(JS); + RouterPageInfo info = target; + info.path = info.url + ".js"; + auto loadPageSuccess = LoadPageExtender(GenerateNextPageId(), info); + if (!loadPageSuccess) { + return nullptr; + } + auto pageNode = pageRouterStack_.back().Upgrade(); + return pageNode; +} + bool PageRouterManager::TryPreloadNamedRouter(const std::string& name, std::function&& finishCallback) { /** @@ -1577,6 +1795,113 @@ RefPtr PageRouterManager::CreatePage(int32_t pageId, const RouterPage return pageNode; } +bool PageRouterManager::LoadPageExtender( + int32_t pageId, const RouterPageInfo& target, bool needHideLast, bool needTransition, bool /*isPush*/) +{ + ACE_SCOPED_TRACE_COMMERCIAL("load page: %s(id:%d)", target.url.c_str(), pageId); + CHECK_RUN_ON(JS); + auto pageNode = CreatePageExtender(pageId, target); + + TaskDependencyManager::GetInstance()->Sync(); + + if (!pageNode) { + TAG_LOGE(AceLogTag::ACE_ROUTER, "failed to create page in LoadPage"); + return false; + } + + pageRouterStack_.emplace_back(pageNode); + if (!OnPageReady(pageNode, needHideLast, needTransition)) { + pageRouterStack_.pop_back(); + TAG_LOGW(AceLogTag::ACE_ROUTER, "LoadPage OnPageReady Failed"); + return false; + } + AccessibilityEventType type = AccessibilityEventType::CHANGE; + pageNode->OnAccessibilityEvent(type); + TAG_LOGI(AceLogTag::ACE_ROUTER, "LoadPage Success"); + return true; +} + +RefPtr PageRouterManager::CreatePageExtender(int32_t pageId, const RouterPageInfo& target) +{ + ACE_SCOPED_TRACE("PageRouterManager::CreatePage"); + CHECK_RUN_ON(JS); + TAG_LOGI(AceLogTag::ACE_ROUTER, "Page router manager is creating page[%{public}d]: url: %{public}s path: " + "%{public}s, recoverable: %{public}s, namedRouter: %{public}s", pageId, target.url.c_str(), + target.path.c_str(), (target.recoverable ? "yes" : "no"), (target.isNamedRouterMode ? "yes" : "no")); + auto entryPageInfo = AceType::MakeRefPtr( + pageId, target.url, target.path, target.params, target.recoverable, target.isNamedRouterMode); + auto pagePattern = ViewAdvancedRegister::GetInstance()->CreatePagePattern(entryPageInfo); + std::unordered_map reportData { { "pageUrl", target.url } }; + ResSchedReportScope reportScope("push_page", reportData); + auto pageNode = PageNode::CreatePageNode(ElementRegister::GetInstance()->MakeUniqueId(), pagePattern); + pageNode->SetHostPageId(pageId); + // !!! must push_back first for UpdateRootComponent + pageRouterStack_.emplace_back(pageNode); + + // record full path info of every pageNode + auto pageInfo = pagePattern->GetPageInfo(); + if (!pageInfo) { + pageRouterStack_.pop_back(); + return nullptr; + } + auto keyInfo = target.url; + if (keyInfo.empty() && manifestParser_) { + auto router = manifestParser_->GetRouter(); + if (router) { + keyInfo = router->GetEntry(""); + } + } +#if !defined(PREVIEW) + if (keyInfo.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) { + // deal with @bundle url + // @bundle format: @bundle:bundleName/moduleName/pagePath/fileName(without file extension) + // @bundle example: @bundle:com.example.applicationHsp/hsp/ets/mylib/pages/Index + // only moduleName and pagePath/fileName is needed: hspmylib/pages/Index + size_t bundleEndPos = keyInfo.find('/'); + size_t moduleStartPos = bundleEndPos + 1; + size_t moduleEndPos = keyInfo.find('/', moduleStartPos); + std::string moduleName = keyInfo.substr(moduleStartPos, moduleEndPos - moduleStartPos); + size_t pageInfoStartPos = keyInfo.find('/', moduleEndPos + 1); + keyInfo = keyInfo.substr(pageInfoStartPos + 1); + keyInfo = moduleName + keyInfo; + } +#endif + SetPageInfoRouteName(entryPageInfo); + auto pagePath = Framework::JsiDeclarativeEngine::GetFullPathInfo(keyInfo); + if (pagePath.empty()) { + auto container = Container::Current(); + if (!container) { + pageRouterStack_.pop_back(); + return nullptr; + } + auto moduleName = container->GetModuleName(); + keyInfo = moduleName + keyInfo; + pagePath = Framework::JsiDeclarativeEngine::GetFullPathInfo(keyInfo); + } + pageInfo->SetFullPath(pagePath); + +#if defined(PREVIEW) + if (!isComponentPreview_()) { +#endif + if (target.isNamedRouterMode) { + if (manifestParser_) { + manifestParser_->SetPagePath(target.url); + } else { + TAG_LOGE(AceLogTag::ACE_ROUTER, "set routeName in manifest failed, manifestParser is null!"); + } + } + + if (target.errorCallback != nullptr) { + target.errorCallback("", ERROR_CODE_NO_ERROR); + } +#if defined(PREVIEW) + } +#endif + + pageRouterStack_.pop_back(); + return pageNode; +} + UIContentErrorCode PageRouterManager::LoadCard(int32_t pageId, const RouterPageInfo& target, const std::string& params, int64_t cardId, bool /* isRestore */, bool needHideLast, const std::string& entryPoint) { diff --git a/frameworks/bridge/declarative_frontend/ng/page_router_manager.h b/frameworks/bridge/declarative_frontend/ng/page_router_manager.h index bc7b60b2a3053f210460e6eb7cc690d1300f394c..6167b584978dedcd8c344db5f2bc039d45951496 100644 --- a/frameworks/bridge/declarative_frontend/ng/page_router_manager.h +++ b/frameworks/bridge/declarative_frontend/ng/page_router_manager.h @@ -151,6 +151,9 @@ public: // router operation void Push(const RouterPageInfo& target); + RefPtr PushExtender(const RouterPageInfo& target); + RefPtr ReplaceExtender(const RouterPageInfo& target, std::function&& finishCallback); + RefPtr RunPageExtender(const RouterPageInfo& target); void PushNamedRoute(const RouterPageInfo& target); bool Pop(); void Replace(const RouterPageInfo& target); @@ -283,6 +286,11 @@ protected: static bool OnPopPageToIndex(int32_t index, bool needShowNext, bool needTransition); static bool OnCleanPageStack(); + // For ArkTS1.2 + virtual bool LoadPageExtender(int32_t pageId, const RouterPageInfo& target, + bool needHideLast = true, bool needTransition = true, bool isPush = false); + RefPtr CreatePageExtender(int32_t pageId, const RouterPageInfo& target); + UIContentErrorCode LoadCard(int32_t pageId, const RouterPageInfo& target, const std::string& params, int64_t cardId, bool isRestore = false, bool needHideLast = true, const std::string& entryPoint = ""); diff --git a/frameworks/core/components/shape/rosen_render_shape_container.cpp b/frameworks/core/components/shape/rosen_render_shape_container.cpp index 14b6fdbbe9e0d6043ea88bc94c199a8f53a3f21f..30d187bac4107c61d6ce2236bf1bcea149f00f5f 100644 --- a/frameworks/core/components/shape/rosen_render_shape_container.cpp +++ b/frameworks/core/components/shape/rosen_render_shape_container.cpp @@ -309,6 +309,7 @@ void RosenRenderShapeContainer::DrawBitmapMesh( const SkScalar dx = width / column; SkPoint* texsPit = texsPoint; + CHECK_NULL_VOID(texsPit); SkScalar y = 0; for (int i = 0; i <= row; i++) { if (i == row) { diff --git a/frameworks/core/components_ng/base/ui_node.cpp b/frameworks/core/components_ng/base/ui_node.cpp index 8c72f31d869606eb3c8cf1d0d9628761bcce98fe..2d8f3aec5c2278cb112744d9f3cd946fdba8ed71 100644 --- a/frameworks/core/components_ng/base/ui_node.cpp +++ b/frameworks/core/components_ng/base/ui_node.cpp @@ -291,6 +291,17 @@ std::list>::iterator UINode::RemoveChild(const RefPtr& ch return result; } +bool UINode::RemoveChildSilently(const RefPtr& child) +{ + CHECK_NULL_RETURN(child, false); + auto iter = std::find(children_.begin(), children_.end(), child); + if (IsDestroyingState() || iter == children_.end()) { + return false; + } + children_.erase(iter); + return true; +} + int32_t UINode::RemoveChildAndReturnIndex(const RefPtr& child) { auto result = RemoveChild(child); diff --git a/frameworks/core/components_ng/base/ui_node.h b/frameworks/core/components_ng/base/ui_node.h index 51f13a1122273aa5a057584a03416426e0d41296..5bf0b803a0531f529e7d28b35f13bce80d0e004f 100644 --- a/frameworks/core/components_ng/base/ui_node.h +++ b/frameworks/core/components_ng/base/ui_node.h @@ -91,6 +91,7 @@ public: void AddChildBefore(const RefPtr& child, const RefPtr& siblingNode); std::list>::iterator RemoveChild(const RefPtr& child, bool allowTransition = false); + bool RemoveChildSilently(const RefPtr& child); int32_t RemoveChildAndReturnIndex(const RefPtr& child); void ReplaceChild(const RefPtr& oldNode, const RefPtr& newNode); void MovePosition(int32_t slot); diff --git a/frameworks/core/components_ng/base/view_abstract_model_static.cpp b/frameworks/core/components_ng/base/view_abstract_model_static.cpp index 6d191b91a7a09bf363a2b6cc0c054ce9ea075009..e1581d15dd389ba2ff1cbe31b0f6d8078dd90bd5 100644 --- a/frameworks/core/components_ng/base/view_abstract_model_static.cpp +++ b/frameworks/core/components_ng/base/view_abstract_model_static.cpp @@ -1085,11 +1085,16 @@ void ViewAbstractModelStatic::SetRotate(FrameNode* frameNode, const std::vector int32_t indZ = 2; int32_t indA = 3; int32_t indP = 4; - rotateVec.x = (value.size() > indX && value[indX].has_value()) ? value[indX].value() : DEFAULT_ROTATE_VEC.x; - rotateVec.y = (value.size() > indY && value[indY].has_value()) ? value[indY].value() : DEFAULT_ROTATE_VEC.y; - rotateVec.z = (value.size() > indZ && value[indZ].has_value()) ? value[indZ].value() : DEFAULT_ROTATE_VEC.z; - rotateVec.w = (value.size() > indA && value[indA].has_value()) ? value[indA].value() : DEFAULT_ROTATE_VEC.w; - rotateVec.v = (value.size() > indP && value[indP].has_value()) ? value[indP].value() : DEFAULT_ROTATE_VEC.v; + rotateVec.x = (value.size() > static_cast(indX) && value[indX].has_value()) ? value[indX].value() + : DEFAULT_ROTATE_VEC.x; + rotateVec.y = (value.size() > static_cast(indY) && value[indY].has_value()) ? value[indY].value() + : DEFAULT_ROTATE_VEC.y; + rotateVec.z = (value.size() > static_cast(indZ) && value[indZ].has_value()) ? value[indZ].value() + : DEFAULT_ROTATE_VEC.z; + rotateVec.w = (value.size() > static_cast(indA) && value[indA].has_value()) ? value[indA].value() + : DEFAULT_ROTATE_VEC.w; + rotateVec.v = (value.size() > static_cast(indP) && value[indP].has_value()) ? value[indP].value() + : DEFAULT_ROTATE_VEC.v; ACE_UPDATE_NODE_RENDER_CONTEXT(TransformRotate, rotateVec, frameNode); } diff --git a/frameworks/core/components_ng/gestures/recognizers/pan_recognizer.h b/frameworks/core/components_ng/gestures/recognizers/pan_recognizer.h index f73c2bee62350151b93f2b9e33d477e5c7852e59..a506ab35c4ba82008a45331e42b4ca39a5fd25c4 100644 --- a/frameworks/core/components_ng/gestures/recognizers/pan_recognizer.h +++ b/frameworks/core/components_ng/gestures/recognizers/pan_recognizer.h @@ -25,7 +25,7 @@ namespace OHOS::Ace::NG { enum class PanGestureState : int32_t; -class PanRecognizer : public MultiFingersRecognizer { +class ACE_FORCE_EXPORT PanRecognizer : public MultiFingersRecognizer { DECLARE_ACE_TYPE(PanRecognizer, MultiFingersRecognizer); public: diff --git a/frameworks/core/components_ng/pattern/stage/page_pattern.cpp b/frameworks/core/components_ng/pattern/stage/page_pattern.cpp index 784746fdd730070596eb576edfe6df650a2984d0..4b77fd48c8c71f2798df0ece8e301fe5bf37cf5c 100644 --- a/frameworks/core/components_ng/pattern/stage/page_pattern.cpp +++ b/frameworks/core/components_ng/pattern/stage/page_pattern.cpp @@ -218,6 +218,7 @@ void PagePattern::OnAttachToMainTree() void PagePattern::OnDetachFromMainTree() { + FireOnNodeDisposeCallback(); #if defined(ENABLE_SPLIT_MODE) if (!needFireObserver_) { return; diff --git a/frameworks/core/components_ng/pattern/stage/page_pattern.h b/frameworks/core/components_ng/pattern/stage/page_pattern.h index e243767f1c300f4cbc84d925fb238d18b0c9cd3e..0a955ee8049601b300ae341aa2e8a8523e1e9af0 100644 --- a/frameworks/core/components_ng/pattern/stage/page_pattern.h +++ b/frameworks/core/components_ng/pattern/stage/page_pattern.h @@ -64,6 +64,17 @@ public: return true; } + void SetOnNodeDisposeCallback(std::function&& disposeCallback) + { + disposeCallback_ = std::move(disposeCallback); + } + + void FireOnNodeDisposeCallback() + { + CHECK_NULL_VOID(disposeCallback_); + disposeCallback_(); + } + bool IsAtomicNode() const override { return false; @@ -366,6 +377,7 @@ protected: RefPtr overlayManager_; OnNewParamCallback onNewParam_; + std::function disposeCallback_; std::function onPageShow_; std::function onPageHide_; std::function onBackPressed_; diff --git a/frameworks/core/components_ng/pattern/stepper/stepper_model_static.cpp b/frameworks/core/components_ng/pattern/stepper/stepper_model_static.cpp index 6049bde4d455d3948e31d82025b852d4ba43c0e5..4d30fbfb7c53511614618758c6c505bb7206c713 100644 --- a/frameworks/core/components_ng/pattern/stepper/stepper_model_static.cpp +++ b/frameworks/core/components_ng/pattern/stepper/stepper_model_static.cpp @@ -35,7 +35,7 @@ void StepperModelStatic::SetIndex(FrameNode* frameNode, const std::optionalHasSwiperNode(); auto swiperId = stepperNode->GetSwiperId(); RefPtr swiperNode; - uint32_t value = index.value_or(0); + uint32_t value = static_cast(index.value_or(0)); if (!hasSwiperNode) { swiperNode = CreateSwiperChild(swiperId, value); swiperNode->MountToParent(Referenced::Claim(stepperNode)); diff --git a/frameworks/core/components_ng/pattern/xcomponent/xcomponent_surface_holder.h b/frameworks/core/components_ng/pattern/xcomponent/xcomponent_surface_holder.h index 4af2937b5d8be21fe1e89bca6a4bcb489d1cbbbc..2191b7b4bb1e4dece944921f63ebaba6755eadcf 100644 --- a/frameworks/core/components_ng/pattern/xcomponent/xcomponent_surface_holder.h +++ b/frameworks/core/components_ng/pattern/xcomponent/xcomponent_surface_holder.h @@ -54,6 +54,6 @@ struct OH_ArkUI_SurfaceHolder { void* userData_ = nullptr; OHNativeWindow* nativeWindow_ = nullptr; std::list surfaceCallbackList_; - ArkUI_NodeHandle node_; + ArkUI_NodeHandle node_ = nullptr; }; #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_XCOMPONENT_XCOMPONENT_SURFACE_HOLDER_H diff --git a/frameworks/core/components_ng/render/paint_property.cpp b/frameworks/core/components_ng/render/paint_property.cpp index 363e4e065799e52665df49cf691814887ef2fc7d..522a773b688a90f814cf1827ddbbae19a4b28a15 100644 --- a/frameworks/core/components_ng/render/paint_property.cpp +++ b/frameworks/core/components_ng/render/paint_property.cpp @@ -31,6 +31,7 @@ RefPtr PaintProperty::GetHost() const void PaintProperty::UpdatePaintPropertyHost(const PaintProperty* renderProperty) { + CHECK_NULL_VOID(renderProperty); host_ = renderProperty->host_; } diff --git a/frameworks/core/interfaces/native/common/view_model.cpp b/frameworks/core/interfaces/native/common/view_model.cpp index 28e1d8f0a5cf7759173fa8a43f9947867b21449c..a02929e2fd7b1f26feda8972d04a2b000eac5897 100644 --- a/frameworks/core/interfaces/native/common/view_model.cpp +++ b/frameworks/core/interfaces/native/common/view_model.cpp @@ -319,7 +319,6 @@ void* createRootNode(ArkUI_Int32 nodeId) auto stageManager = context->GetStageManager(); CHECK_NULL_RETURN(stageManager, nullptr); auto stageNode = stageManager->GetStageNode(); - TAG_LOGD(AceLogTag::ACE_NATIVE_NODE, "createRootNode: stageNode %{public}p", AceType::RawPtr(stageNode)); return AceType::RawPtr(stageNode); } diff --git a/frameworks/core/interfaces/native/generated/interface/arkoala_api_generated.h b/frameworks/core/interfaces/native/generated/interface/arkoala_api_generated.h index 166c0bde7aebf5bf8067468da00dbe7ea8334788..8b8af36594637371f8a5493a1a79eb65277ae17a 100644 --- a/frameworks/core/interfaces/native/generated/interface/arkoala_api_generated.h +++ b/frameworks/core/interfaces/native/generated/interface/arkoala_api_generated.h @@ -26823,6 +26823,15 @@ typedef struct GENERATED_ArkUIPromptActionAccessor { void (*showToast)(const Ark_ShowToastOptions* value); } GENERATED_ArkUIPromptActionAccessor; +typedef struct GENERATED_ArkUIRouterExtenderAccessor { + Ark_NativePointer (*push)(const Ark_String* url); + Ark_NativePointer (*replace)(const Ark_String* url, const Opt_Callback_Void* finishCallback); + void (*moveCommonUnderPageNode)(Ark_NativePointer commonNode, Ark_NativePointer pageNode); + void (*back)(); + Ark_NativePointer (*runPage)(const Ark_String* url); + void (*clear)(); +} GENERATED_ArkUIRouterExtenderAccessor; + /** * An API to control an implementation. When making changes modifying binary * layout, i.e. adding new events - increase ARKUI_API_VERSION above for binary @@ -27160,6 +27169,7 @@ typedef struct GENERATED_ArkUIAccessors { const GENERATED_ArkUILinearIndicatorControllerAccessor* (*getLinearIndicatorControllerAccessor)(); const GENERATED_ArkUIGlobalScopeAccessor* (*getGlobalScopeAccessor)(); const GENERATED_ArkUIPromptActionAccessor* (*getPromptActionAccessor)(); + const GENERATED_ArkUIRouterExtenderAccessor* (*getRouterExtenderAccessor)(); } GENERATED_ArkUIAccessors; typedef struct GENERATED_ArkUIGraphicsAPI { diff --git a/frameworks/core/interfaces/native/generated/interface/node_interface.gni b/frameworks/core/interfaces/native/generated/interface/node_interface.gni index 68b6c1472cd5b4b0bf815cc2288f6ce090992683..23c2a20bcd8cea166dfbf7c96c4244f2588bafe8 100644 --- a/frameworks/core/interfaces/native/generated/interface/node_interface.gni +++ b/frameworks/core/interfaces/native/generated/interface/node_interface.gni @@ -242,6 +242,7 @@ generated_sources = [ "implementation/rotation_gesture_event_accessor.cpp", "implementation/rotation_gesture_interface_accessor.cpp", "implementation/rotation_recognizer_accessor.cpp", + "implementation/router_extender_accessor.cpp", "implementation/row_modifier.cpp", "implementation/row_split_modifier.cpp", "implementation/save_button_modifier.cpp", diff --git a/frameworks/core/interfaces/native/implementation/all_modifiers.cpp b/frameworks/core/interfaces/native/implementation/all_modifiers.cpp index f102bbe2601f24df93eb0110d1c81e0fe06c7dc9..aebb8aad156e5b4ce7f06ef8abf551c17d090149 100644 --- a/frameworks/core/interfaces/native/implementation/all_modifiers.cpp +++ b/frameworks/core/interfaces/native/implementation/all_modifiers.cpp @@ -412,6 +412,7 @@ const GENERATED_ArkUICustomSpanAccessor* GetCustomSpanAccessor(); const GENERATED_ArkUILinearIndicatorControllerAccessor* GetLinearIndicatorControllerAccessor(); const GENERATED_ArkUIGlobalScopeAccessor* GetGlobalScopeAccessor(); const GENERATED_ArkUIPromptActionAccessor* GetPromptActionAccessor(); +const GENERATED_ArkUIRouterExtenderAccessor* GetRouterExtenderAccessor(); const GENERATED_ArkUIStateModifier* GetUIStateModifier(); const GENERATED_ArkUINodeModifiers* GENERATED_GetArkUINodeModifiers() { @@ -749,6 +750,7 @@ const GENERATED_ArkUIAccessors* GENERATED_GetArkUIAccessors() GetLinearIndicatorControllerAccessor, GetGlobalScopeAccessor, GetPromptActionAccessor, + GetRouterExtenderAccessor, }; return &accessorsImpl; } diff --git a/frameworks/core/interfaces/native/implementation/common_method_modifier.cpp b/frameworks/core/interfaces/native/implementation/common_method_modifier.cpp index b3e9f207b56fc047416be8038310a2e1c472785f..57ecd9db4bac0e75f58a9b5338dda5f633f53955 100644 --- a/frameworks/core/interfaces/native/implementation/common_method_modifier.cpp +++ b/frameworks/core/interfaces/native/implementation/common_method_modifier.cpp @@ -3344,7 +3344,7 @@ void Rotate0Impl(Ark_NativePointer node, [&convValue](const Ark_String& str) { std::string degreeStr = Converter::Convert(str); float angle = static_cast(StringUtils::StringToDegree(degreeStr)); - int32_t indA = 3; + uint32_t indA = 3; if (convValue->vec5f.size() > indA) { convValue->vec5f[indA] = angle; } diff --git a/frameworks/core/interfaces/native/implementation/rect_modifier.cpp b/frameworks/core/interfaces/native/implementation/rect_modifier.cpp index bcdd901bc1614e79df210bc2b068484045787f8e..4793728c8c8aba79bb4a8a54eca17accb6558f21 100644 --- a/frameworks/core/interfaces/native/implementation/rect_modifier.cpp +++ b/frameworks/core/interfaces/native/implementation/rect_modifier.cpp @@ -152,7 +152,7 @@ void SetRectOptionsImpl(Ark_NativePointer node, if (!opt->radiusWidth || !opt->radiusHeight) { size_t length = std::min(opt->cornerRadius.size(), static_cast(MAX_RADIUS_ITEM_COUNT)); - for (int32_t i = 0; i < length; ++i) { + for (size_t i = 0; i < length; ++i) { const RectRadius radiusItem = opt->cornerRadius[i]; const Dimension rx = radiusItem.radiusWidth.value(); const Dimension ry = radiusItem.radiusHeight.value(); diff --git a/frameworks/core/interfaces/native/implementation/rich_editor_modifier.cpp b/frameworks/core/interfaces/native/implementation/rich_editor_modifier.cpp index 91690a0022588b83639e32bcfa7fc6e00d309739..48c40ab6db76f354b6ef37f9d296b5cfb2bd0d59 100644 --- a/frameworks/core/interfaces/native/implementation/rich_editor_modifier.cpp +++ b/frameworks/core/interfaces/native/implementation/rich_editor_modifier.cpp @@ -125,7 +125,7 @@ void AssignArkValue(Ark_RichEditorSelection& dst, const BaseEventInfo& src, Conv dst.spans.array = nullptr; return; } - dst.spans.length = resultObjects.size(); + dst.spans.length = Converter::ArkValue(static_cast(resultObjects.size())); dst.spans.array = new Union_Span_Result[resultObjects.size()]; size_t idx = 0; for (auto& resultObject : resultObjects) { diff --git a/frameworks/core/interfaces/native/implementation/root_modifier.cpp b/frameworks/core/interfaces/native/implementation/root_modifier.cpp index 025c00b56521fef15c12f781451609fc624f080e..e565fb12e3bd87b1984509407505710fa5988514 100644 --- a/frameworks/core/interfaces/native/implementation/root_modifier.cpp +++ b/frameworks/core/interfaces/native/implementation/root_modifier.cpp @@ -48,20 +48,6 @@ Ark_NativePointer ConstructImpl(Ark_Int32 id, auto stageManager = context->GetStageManager(); CHECK_NULL_RETURN(stageManager, nullptr); auto stageNode = stageManager->GetStageNode(); - TAG_LOGD(AceLogTag::ACE_NATIVE_NODE, "createRootNode: stageNode %{public}p", AceType::RawPtr(stageNode)); - - // create page node as CAPI root node to support existing - // PageNode functionality like status bar offset supporting for example - auto pageInfo = AceType::MakeRefPtr(id, "", ""); - CHECK_NULL_RETURN(pageInfo, AceType::RawPtr(stageNode)); - auto pagePattern = AceType::MakeRefPtr(pageInfo); - CHECK_NULL_RETURN(pagePattern, AceType::RawPtr(stageNode)); - auto pageNode = FrameNode::CreateFrameNode(V2::PAGE_ETS_TAG, id, pagePattern); - CHECK_NULL_RETURN(pageNode, AceType::RawPtr(stageNode)); - pageNode->SetHostPageId(id); - if (stageManager->PushPage(pageNode, true, false)) { - return AceType::RawPtr(pageNode); - } return AceType::RawPtr(stageNode); } diff --git a/frameworks/core/interfaces/native/implementation/router_extender_accessor.cpp b/frameworks/core/interfaces/native/implementation/router_extender_accessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f9981af29da687f812a932146d722cbb4c723d0 --- /dev/null +++ b/frameworks/core/interfaces/native/implementation/router_extender_accessor.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "arkoala_api_generated.h" +#include "base/memory/ace_type.h" +#include "bridge/arkts_frontend/arkts_frontend.h" +#include "core/common/container.h" +#include "core/components_ng/base/frame_node.h" +#include "core/components_ng/base/ui_node.h" +#include "core/interfaces/native/utility/converter.h" +#include "core/interfaces/native/utility/reverse_converter.h" +#include "frameworks/bridge/declarative_frontend/ng/page_router_manager.h" +#include "frameworks/core/interfaces/native/utility/callback_helper.h" + +#include + +namespace OHOS::Ace::NG::GeneratedModifier { +namespace RouterExtenderAccessor { +Ark_NativePointer PushImpl(const Ark_String* url) +{ + CHECK_NULL_RETURN(url, nullptr); + std::string pushUrl = Converter::Convert(*url); + if (pushUrl.empty()) { + return nullptr; + } + NG::RouterPageInfo routerPageInfo; + routerPageInfo.url = pushUrl; + routerPageInfo.params = ""; + routerPageInfo.recoverable = true; + auto container = Container::Current(); + CHECK_NULL_RETURN(container, nullptr); + auto delegate = AceType::DynamicCast(container->GetFrontend()); + CHECK_NULL_RETURN(delegate, nullptr); + auto pageRouterManager = delegate->GetPageRouterManager(); + if (!pageRouterManager) { + return nullptr; + } + auto pageNode = pageRouterManager->PushExtender(routerPageInfo); + return pageNode.GetRawPtr(); +} + +Ark_NativePointer ReplaceImpl(const Ark_String* url, const Opt_Callback_Void* finishCallback) +{ + CHECK_NULL_RETURN(url, nullptr); + CHECK_NULL_RETURN(finishCallback, nullptr); + std::string pushUrl = Converter::Convert(*url); + if (pushUrl.empty()) { + return nullptr; + } + NG::RouterPageInfo routerPageInfo; + routerPageInfo.url = pushUrl; + routerPageInfo.params = ""; + routerPageInfo.recoverable = true; + auto container = Container::Current(); + CHECK_NULL_RETURN(container, nullptr); + auto delegate = AceType::DynamicCast(container->GetFrontend()); + CHECK_NULL_RETURN(delegate, nullptr); + auto pageRouterManager = delegate->GetPageRouterManager(); + if (!pageRouterManager) { + return nullptr; + } + std::function callback; + if (finishCallback->tag != InteropTag::INTEROP_TAG_UNDEFINED) { + callback = [finish = CallbackHelper(finishCallback->value)]() { + finish.Invoke(); + }; + } + auto pageNode = pageRouterManager->ReplaceExtender(routerPageInfo, std::move(callback)); + return pageNode.GetRawPtr(); +} + +void MoveCommonUnderPageNode(Ark_NativePointer commonNode, Ark_NativePointer pageNode) +{ + auto common = reinterpret_cast(commonNode); + CHECK_NULL_VOID(common); + auto stageNode = common->GetParent(); + CHECK_NULL_VOID(stageNode); + if (stageNode->GetTag() != V2::STAGE_ETS_TAG) { + return; + } + stageNode->RemoveChildSilently(AceType::Claim(common)); + + auto page = reinterpret_cast(pageNode); + CHECK_NULL_VOID(page); + auto pageFrameNode = AceType::Claim(page); + common->MountToParent(pageFrameNode); + + pageFrameNode->MarkModifyDone(); + pageFrameNode->MarkDirtyNode(); + common->MarkModifyDone(); + common->MarkDirtyNode(); +} + +void BackImpl() +{ + auto container = Container::Current(); + CHECK_NULL_VOID(container); + auto delegate = AceType::DynamicCast(container->GetFrontend()); + CHECK_NULL_VOID(delegate); + auto pageRouterManager = delegate->GetPageRouterManager(); + if (!pageRouterManager) { + return; + } + NG::RouterPageInfo routerPageInfo; + routerPageInfo.url = ""; + routerPageInfo.params = ""; + pageRouterManager->BackWithTarget(routerPageInfo); +} + +Ark_NativePointer RunPageImpl(const Ark_String* url) +{ + CHECK_NULL_RETURN(url, nullptr); + std::string pushUrl = Converter::Convert(*url); + if (pushUrl.empty()) { + return nullptr; + } + NG::RouterPageInfo routerPageInfo; + routerPageInfo.url = pushUrl; + routerPageInfo.params = ""; + auto container = Container::Current(); + CHECK_NULL_RETURN(container, nullptr); + auto delegate = AceType::DynamicCast(container->GetFrontend()); + CHECK_NULL_RETURN(delegate, nullptr); + auto pageRouterManager = delegate->GetPageRouterManager(); + if (!pageRouterManager) { + return nullptr; + } + auto pageNode = pageRouterManager->RunPageExtender(routerPageInfo); + return pageNode.GetRawPtr(); +} + +void ClearImpl() +{ + auto container = Container::Current(); + CHECK_NULL_VOID(container); + auto delegate = AceType::DynamicCast(container->GetFrontend()); + CHECK_NULL_VOID(delegate); + auto pageRouterManager = delegate->GetPageRouterManager(); + if (!pageRouterManager) { + return; + } + NG::RouterPageInfo routerPageInfo; + routerPageInfo.url = ""; + routerPageInfo.params = ""; + pageRouterManager->Clear(); +} +} + +const GENERATED_ArkUIRouterExtenderAccessor* GetRouterExtenderAccessor() +{ + static const GENERATED_ArkUIRouterExtenderAccessor RouterExtenderAccessorImpl { + RouterExtenderAccessor::PushImpl, + RouterExtenderAccessor::ReplaceImpl, + RouterExtenderAccessor::MoveCommonUnderPageNode, + RouterExtenderAccessor::BackImpl, + RouterExtenderAccessor::RunPageImpl, + RouterExtenderAccessor::ClearImpl + }; + return &RouterExtenderAccessorImpl; +} +} \ No newline at end of file diff --git a/frameworks/core/interfaces/native/implementation/search_modifier.cpp b/frameworks/core/interfaces/native/implementation/search_modifier.cpp index 73a64dec9f4f771a3d9a8bc127b91a33dd7517c2..7791aec1a92f19f47ed32de863775e9b3a5b7641 100644 --- a/frameworks/core/interfaces/native/implementation/search_modifier.cpp +++ b/frameworks/core/interfaces/native/implementation/search_modifier.cpp @@ -740,6 +740,12 @@ void OnWillChangeImpl(Ark_NativePointer node, } auto onWillChange = [callback = CallbackHelper(*optValue)](const ChangeValueInfo& value) -> bool { Converter::ConvContext ctx; + Ark_TextChangeOptions textChangeOptions = { + .rangeBefore = Converter::ArkValue(value.rangeBefore), + .rangeAfter = Converter::ArkValue(value.rangeAfter), + .oldContent = Converter::ArkValue(value.oldContent, &ctx), + .oldPreviewText = Converter::ArkValue(value.oldPreviewText, &ctx), + }; Ark_EditableTextChangeValue changeValue = { .content = Converter::ArkValue(value.value, &ctx), .previewText = { @@ -748,10 +754,7 @@ void OnWillChangeImpl(Ark_NativePointer node, }, .options = { .tag = INTEROP_TAG_OBJECT, - .value.rangeBefore = Converter::ArkValue(value.rangeBefore), - .value.rangeAfter = Converter::ArkValue(value.rangeAfter), - .value.oldContent = Converter::ArkValue(value.oldContent, &ctx), - .value.oldPreviewText = Converter::ArkValue(value.oldPreviewText, &ctx), + .value = textChangeOptions } }; return callback.InvokeWithOptConvertResult(changeValue) diff --git a/frameworks/core/interfaces/native/implementation/shape_modifier.cpp b/frameworks/core/interfaces/native/implementation/shape_modifier.cpp index e25ad6344acf1d65d51548f72e3a9adb96cc2ddf..d7492d70c8f64c02bb149a22c2558d5f0cd2158a 100644 --- a/frameworks/core/interfaces/native/implementation/shape_modifier.cpp +++ b/frameworks/core/interfaces/native/implementation/shape_modifier.cpp @@ -139,7 +139,7 @@ void StrokeDashArrayImpl(Ark_NativePointer node, // if odd,add twice auto length = dashArray.size(); if (length & 1) { - for (int32_t i = 0; i < length; i++) { + for (size_t i = 0; i < length; i++) { dashArray.emplace_back(dashArray[i]); } } diff --git a/frameworks/core/interfaces/native/implementation/text_area_modifier.cpp b/frameworks/core/interfaces/native/implementation/text_area_modifier.cpp index 500f0b8f7d96f8c99e8cca7492468a85d6d9097d..1467d24aaa9e841b1e676a4706e0501ee7f6715d 100644 --- a/frameworks/core/interfaces/native/implementation/text_area_modifier.cpp +++ b/frameworks/core/interfaces/native/implementation/text_area_modifier.cpp @@ -728,6 +728,12 @@ void OnWillChangeImpl(Ark_NativePointer node, } auto onWillChange = [callback = CallbackHelper(*optValue)](const ChangeValueInfo& value) -> bool { Converter::ConvContext ctx; + Ark_TextChangeOptions textChangeOptions = { + .rangeBefore = Converter::ArkValue(value.rangeBefore), + .rangeAfter = Converter::ArkValue(value.rangeAfter), + .oldContent = Converter::ArkValue(value.oldContent, &ctx), + .oldPreviewText = Converter::ArkValue(value.oldPreviewText, &ctx), + }; Ark_EditableTextChangeValue changeValue = { .content = Converter::ArkValue(value.value, &ctx), .previewText = { @@ -736,10 +742,7 @@ void OnWillChangeImpl(Ark_NativePointer node, }, .options = { .tag = INTEROP_TAG_OBJECT, - .value.rangeBefore = Converter::ArkValue(value.rangeBefore), - .value.rangeAfter = Converter::ArkValue(value.rangeAfter), - .value.oldContent = Converter::ArkValue(value.oldContent, &ctx), - .value.oldPreviewText = Converter::ArkValue(value.oldPreviewText, &ctx), + .value = textChangeOptions } }; return callback.InvokeWithOptConvertResult(changeValue) diff --git a/frameworks/core/interfaces/native/implementation/text_content_controller_base_accessor.cpp b/frameworks/core/interfaces/native/implementation/text_content_controller_base_accessor.cpp index e3324d772db339bd9342aee5ee9e93e37eea04ed..6f21bf6b914c022e0b208a96c6002af58679eb4c 100644 --- a/frameworks/core/interfaces/native/implementation/text_content_controller_base_accessor.cpp +++ b/frameworks/core/interfaces/native/implementation/text_content_controller_base_accessor.cpp @@ -98,7 +98,7 @@ Ark_String GetTextImpl(Ark_TextContentControllerBase peer, auto rangeConv = range ? Converter::OptConvert(*range) : std::nullopt; std::u16string content = peer->controller_->GetText(); int32_t startIndex = 0; - int32_t endIndex = content.length(); + int32_t endIndex = static_cast(content.length()); if (rangeConv) { startIndex = rangeConv->start; startIndex = startIndex < 0 ? 0 : startIndex; diff --git a/frameworks/core/interfaces/native/implementation/text_input_modifier.cpp b/frameworks/core/interfaces/native/implementation/text_input_modifier.cpp index 6b95b8144639108dedc295ff609243599ee38afc..a497940652f2b40948281a18e65b851424f2d74e 100644 --- a/frameworks/core/interfaces/native/implementation/text_input_modifier.cpp +++ b/frameworks/core/interfaces/native/implementation/text_input_modifier.cpp @@ -940,6 +940,12 @@ void OnWillChangeImpl(Ark_NativePointer node, } auto onWillChange = [callback = CallbackHelper(*optValue)](const ChangeValueInfo& value) -> bool { Converter::ConvContext ctx; + Ark_TextChangeOptions textChangeOptions = { + .rangeBefore = Converter::ArkValue(value.rangeBefore), + .rangeAfter = Converter::ArkValue(value.rangeAfter), + .oldContent = Converter::ArkValue(value.oldContent, &ctx), + .oldPreviewText = Converter::ArkValue(value.oldPreviewText, &ctx), + }; Ark_EditableTextChangeValue changeValue = { .content = Converter::ArkValue(value.value, &ctx), .previewText = { @@ -948,10 +954,7 @@ void OnWillChangeImpl(Ark_NativePointer node, }, .options = { .tag = INTEROP_TAG_OBJECT, - .value.rangeBefore = Converter::ArkValue(value.rangeBefore), - .value.rangeAfter = Converter::ArkValue(value.rangeAfter), - .value.oldContent = Converter::ArkValue(value.oldContent, &ctx), - .value.oldPreviewText = Converter::ArkValue(value.oldPreviewText, &ctx), + .value = textChangeOptions } }; return callback.InvokeWithOptConvertResult(changeValue) diff --git a/interfaces/ets/ani/curves/src/curves.cpp b/interfaces/ets/ani/curves/src/curves.cpp index 1c5b203b6c4513215b43ed40fca30419a10e789b..7762fe4ee1cfb622ad72ae9f03385fd1ab8f9e90 100644 --- a/interfaces/ets/ani/curves/src/curves.cpp +++ b/interfaces/ets/ani/curves/src/curves.cpp @@ -179,6 +179,9 @@ static CurvesObj* unwrapp(ani_env *env, ani_object object) static ani_double Interpolate([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_double fraction) { auto curveObject = unwrapp(env, object); + if (!curveObject) { + return 0.0; + } auto curveString = curveObject->curveString; float time = static_cast(fraction); time = std::clamp(time, 0.0f, 1.0f); @@ -224,9 +227,7 @@ static ani_object CubicBezierCurve([[maybe_unused]] ani_env *env, ani_object curve_object; - if (ANI_OK != env->Object_New(cls, ctor, &curve_object, reinterpret_cast(cubicBezierCurve))) { - return nullptr; - } + env->Object_New(cls, ctor, &curve_object, reinterpret_cast(cubicBezierCurve)); if (OHOS::Ace::Container::IsCurrentUseNewPipeline()) { return curve_object; @@ -359,9 +360,7 @@ static ani_object SpringResponsiveMotion([[maybe_unused]] ani_env *env, springResponsiveMotion->interpolate = Interpolate; static const char *className = "L@ohos/curves/curves/Curves;"; ani_class cls; - if (ANI_OK != env->FindClass(className, &cls)) { - return nullptr; - } + env->FindClass(className, &cls); ani_method ctor; if (ANI_OK != env->Class_FindMethod(cls, "", nullptr, &ctor)) { return nullptr; @@ -401,9 +400,7 @@ static ani_object SpringMotion([[maybe_unused]] ani_env *env, springMotion->interpolate = Interpolate; static const char *className = "L@ohos/curves/curves/Curves;"; ani_class cls; - if (ANI_OK != env->FindClass(className, &cls)) { - return nullptr; - } + env->FindClass(className, &cls); ani_method ctor; if (ANI_OK != env->Class_FindMethod(cls, "", nullptr, &ctor)) { return nullptr; @@ -527,10 +524,7 @@ static ani_object InterpolatingSpring([[maybe_unused]] ani_env* env, ani_object obj; - if (ANI_OK != env->Object_New(cls, ctor, &obj, reinterpret_cast(interpolatingCurve))) { - std::cerr << "New curve object Fail" << std::endl; - return nullptr; - } + env->Object_New(cls, ctor, &obj, reinterpret_cast(interpolatingCurve)); if (OHOS::Ace::Container::IsCurrentUseNewPipeline()) { return obj; diff --git a/interfaces/inner_api/ace_kit/src/napi/napi_parser.cpp b/interfaces/inner_api/ace_kit/src/napi/napi_parser.cpp index 38c7ce402eabf7fd468c3de57818098cb69019f3..2d6a76a93906a0c75dcb81376f375eb3d56199fa 100644 --- a/interfaces/inner_api/ace_kit/src/napi/napi_parser.cpp +++ b/interfaces/inner_api/ace_kit/src/napi/napi_parser.cpp @@ -184,6 +184,7 @@ RefPtr CreateResourceWrapper(const ResourceInfo& info) bool ParseIntegerToString(const ResourceInfo& info, std::string& result) { auto resourceWrapper = CreateResourceWrapper(info); + CHECK_NULL_RETURN(resourceWrapper, false); if (info.type == static_cast(ResourceType::INTEGER)) { if (info.resId == UNKNOWN_RESOURCE_ID) { result = std::to_string(resourceWrapper->GetIntByName(info.params[0])); @@ -215,6 +216,7 @@ std::string DimensionToString(Dimension dimension) bool ParseString(const ResourceInfo& info, std::string& result) { auto resourceWrapper = CreateResourceWrapper(info); + CHECK_NULL_RETURN(resourceWrapper, false); if (info.type == static_cast(ResourceType::PLURAL)) { std::string pluralResults; if (info.resId == UNKNOWN_RESOURCE_ID) { diff --git a/interfaces/napi/kits/observer/ui_observer_listener.cpp b/interfaces/napi/kits/observer/ui_observer_listener.cpp index fc63ccac13df278dd696bcc5705cc636ab72fae1..eecbd0e8ff55caedf8fded577f0aa82b223daa62 100644 --- a/interfaces/napi/kits/observer/ui_observer_listener.cpp +++ b/interfaces/napi/kits/observer/ui_observer_listener.cpp @@ -30,6 +30,14 @@ constexpr char GET_EVENT_TARGET_INFO[] = "getEventTargetInfo"; constexpr char IS_VALID[] = "isValid"; constexpr char GET_ID[] = "getId"; constexpr char GET_MODIFIER_KEY_STATE[] = "getModifierKeyState"; +constexpr char GET_FINGER_COUNT[] = "getFingerCount"; +constexpr char IS_FINGER_COUNT_LIMIT[] = "isFingerCountLimit"; +constexpr char GET_DIRECTION[] = "getDirection"; +constexpr char GET_DISTANCE[] = "getDistance"; +constexpr char GET_PANGESTURE_OPTIONS[] = "getPanGestureOptions"; +constexpr char SET_DIRECTION[] = "setDirection"; +constexpr char SET_DISTANCE[] = "setDistance"; +constexpr char SET_FINGERS[] = "setFingers"; constexpr int32_t PARAM_SIZE_ZERO = 0; constexpr int32_t PARAM_SIZE_ONE = 1; constexpr int32_t PARAM_SIZE_TWO = 2; @@ -50,63 +58,98 @@ static NG::PanRecognizer* GetCurrentGestureRecognizer( static napi_value GetTag(napi_env env, napi_callback_info info) { - napi_handle_scope scope = nullptr; - napi_open_handle_scope(env, &scope); - CHECK_NULL_RETURN(scope, nullptr); + napi_escapable_handle_scope scope = nullptr; + auto status = napi_open_escapable_handle_scope(env, &scope); + if (status != napi_ok) { + return nullptr; + } NG::PanRecognizer* current = GetCurrentGestureRecognizer(env, info); - CHECK_NULL_RETURN(current, nullptr); + if (!current) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } napi_value result = nullptr; auto gestureInfo = current->GetGestureInfo(); - CHECK_NULL_RETURN(gestureInfo, nullptr); + if (!gestureInfo) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } if (gestureInfo->GetTag().has_value()) { std::string tag = gestureInfo->GetTag().value(); napi_create_string_utf8(env, tag.c_str(), NAPI_AUTO_LENGTH, &result); } else { napi_get_undefined(env, &result); } - napi_close_handle_scope(env, scope); - return result; + napi_value newResult = nullptr; + napi_escape_handle(env, scope, result, &newResult); + napi_close_escapable_handle_scope(env, scope); + return newResult; } static napi_value GetType(napi_env env, napi_callback_info info) { - napi_handle_scope scope = nullptr; - napi_open_handle_scope(env, &scope); - CHECK_NULL_RETURN(scope, nullptr); + napi_escapable_handle_scope scope = nullptr; + auto status = napi_open_escapable_handle_scope(env, &scope); + if (status != napi_ok) { + return nullptr; + } NG::PanRecognizer* current = GetCurrentGestureRecognizer(env, info); - CHECK_NULL_RETURN(current, nullptr); + if (!current) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } napi_value result = nullptr; auto gestureInfo = current->GetGestureInfo(); - CHECK_NULL_RETURN(gestureInfo, nullptr); + if (!gestureInfo) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } napi_create_int32(env, static_cast(gestureInfo->GetRecognizerType()), &result); - napi_close_handle_scope(env, scope); - return result; + napi_value newResult = nullptr; + napi_escape_handle(env, scope, result, &newResult); + napi_close_escapable_handle_scope(env, scope); + return newResult; } static napi_value IsBuiltIn(napi_env env, napi_callback_info info) { - napi_handle_scope scope = nullptr; - napi_open_handle_scope(env, &scope); - CHECK_NULL_RETURN(scope, nullptr); + napi_escapable_handle_scope scope = nullptr; + auto status = napi_open_escapable_handle_scope(env, &scope); + if (status != napi_ok) { + return nullptr; + } NG::PanRecognizer* current = GetCurrentGestureRecognizer(env, info); - CHECK_NULL_RETURN(current, nullptr); + if (!current) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } napi_value result = nullptr; auto gestureInfo = current->GetGestureInfo(); - CHECK_NULL_RETURN(gestureInfo, nullptr); + if (!gestureInfo) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } napi_get_boolean(env, gestureInfo->IsSystemGesture(), &result); - napi_close_handle_scope(env, scope); - return result; + napi_value newResult = nullptr; + napi_escape_handle(env, scope, result, &newResult); + napi_close_escapable_handle_scope(env, scope); + return newResult; } static napi_value SetEnabled(napi_env env, napi_callback_info info) { napi_handle_scope scope = nullptr; - napi_open_handle_scope(env, &scope); - CHECK_NULL_RETURN(scope, nullptr); + auto status = napi_open_handle_scope(env, &scope); + if (status != napi_ok) { + return nullptr; + } size_t argc = PARAM_SIZE_ONE; napi_value argv[PARAM_SIZE_ONE] = { nullptr }; NG::PanRecognizer* current = GetCurrentGestureRecognizer(env, info, &argc, argv); - CHECK_NULL_RETURN(current, nullptr); + if (!current) { + napi_close_handle_scope(env, scope); + return nullptr; + } napi_valuetype valueType = napi_undefined; NAPI_CALL(env, napi_typeof(env, argv[PARAM_SIZE_ZERO], &valueType)); NAPI_ASSERT(env, (valueType == napi_boolean), "Invalid arguments"); @@ -119,46 +162,78 @@ static napi_value SetEnabled(napi_env env, napi_callback_info info) static napi_value IsEnabled(napi_env env, napi_callback_info info) { - napi_handle_scope scope = nullptr; - napi_open_handle_scope(env, &scope); - CHECK_NULL_RETURN(scope, nullptr); + napi_escapable_handle_scope scope = nullptr; + auto status = napi_open_escapable_handle_scope(env, &scope); + if (status != napi_ok) { + return nullptr; + } NG::PanRecognizer* current = GetCurrentGestureRecognizer(env, info); - CHECK_NULL_RETURN(current, nullptr); + if (!current) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } napi_value result = nullptr; napi_get_boolean(env, current->IsEnabled(), &result); - napi_close_handle_scope(env, scope); - return result; + napi_value newResult = nullptr; + napi_escape_handle(env, scope, result, &newResult); + napi_close_escapable_handle_scope(env, scope); + return newResult; } static napi_value GetState(napi_env env, napi_callback_info info) { - napi_handle_scope scope = nullptr; - napi_open_handle_scope(env, &scope); - CHECK_NULL_RETURN(scope, nullptr); + napi_escapable_handle_scope scope = nullptr; + auto status = napi_open_escapable_handle_scope(env, &scope); + if (status != napi_ok) { + return nullptr; + } NG::PanRecognizer* current = GetCurrentGestureRecognizer(env, info); - CHECK_NULL_RETURN(current, nullptr); + if (!current) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } napi_value result = nullptr; napi_create_int32(env, static_cast(current->GetRefereeState()), &result); - napi_close_handle_scope(env, scope); + napi_value newResult = nullptr; + napi_escape_handle(env, scope, result, &newResult); + napi_close_escapable_handle_scope(env, scope); + return newResult; +} + +static napi_value GetId(napi_env env, napi_callback_info info) +{ + napi_value result = nullptr; + void* data = nullptr; + napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &data); + auto inspectorId = static_cast(data); + CHECK_NULL_RETURN(inspectorId, nullptr); + napi_create_string_utf8(env, (*inspectorId).c_str(), NAPI_AUTO_LENGTH, &result); return result; } static napi_value GetEventTargetInfo(napi_env env, napi_callback_info info) { - napi_handle_scope scope = nullptr; - napi_open_handle_scope(env, &scope); - CHECK_NULL_RETURN(scope, nullptr); + napi_escapable_handle_scope scope = nullptr; + auto status = napi_open_escapable_handle_scope(env, &scope); + if (status != napi_ok) { + return nullptr; + } NG::PanRecognizer* current = GetCurrentGestureRecognizer(env, info); - CHECK_NULL_RETURN(current, nullptr); + if (!current) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } napi_value result = nullptr; napi_create_object(env, &result); napi_value funcValue = nullptr; auto attactNode = current->GetAttachedNode().Upgrade(); - CHECK_NULL_RETURN(attactNode, nullptr); - auto inspectorId = std::make_shared(attactNode->GetInspectorIdValue("")); - auto inspectorIdHolder = std::make_unique>(inspectorId); - auto* rawPtr = inspectorIdHolder.release(); - auto status = napi_wrap( + if (!attactNode) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } + auto inspectorId = std::make_unique(attactNode->GetInspectorIdValue("")); + auto* rawPtr = inspectorId.release(); + status = napi_wrap( env, result, rawPtr, [](napi_env env, void* data, void* hint) { auto origin = static_cast(data); @@ -170,34 +245,164 @@ static napi_value GetEventTargetInfo(napi_env env, napi_callback_info info) if (status != napi_ok) { LOGE("napi_wrap failed"); delete rawPtr; + napi_close_escapable_handle_scope(env, scope); return nullptr; } - auto getId = [](napi_env env, napi_callback_info info) -> napi_value { - napi_value result = nullptr; - void* data = nullptr; - napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &data); - auto inspectorId = static_cast*>(data); - CHECK_NULL_RETURN(inspectorId, nullptr); - napi_create_string_utf8(env, (*inspectorId)->c_str(), NAPI_AUTO_LENGTH, &result); - return result; - }; - napi_create_function(env, GET_ID, 0, getId, rawPtr, &funcValue); + + napi_create_function(env, GET_ID, 0, GetId, rawPtr, &funcValue); napi_set_named_property(env, result, GET_ID, funcValue); - napi_close_handle_scope(env, scope); - return result; + napi_value newResult = nullptr; + napi_escape_handle(env, scope, result, &newResult); + napi_close_escapable_handle_scope(env, scope); + return newResult; } static napi_value IsValid(napi_env env, napi_callback_info info) { - napi_handle_scope scope = nullptr; - napi_open_handle_scope(env, &scope); - CHECK_NULL_RETURN(scope, nullptr); + napi_escapable_handle_scope scope = nullptr; + auto status = napi_open_escapable_handle_scope(env, &scope); + if (status != napi_ok) { + return nullptr; + } NG::PanRecognizer* current = GetCurrentGestureRecognizer(env, info); - CHECK_NULL_RETURN(current, nullptr); + if (!current) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } napi_value result = nullptr; napi_get_boolean(env, current->IsInResponseLinkRecognizers(), &result); - napi_close_handle_scope(env, scope); - return result; + napi_value newResult = nullptr; + napi_escape_handle(env, scope, result, &newResult); + napi_close_escapable_handle_scope(env, scope); + return newResult; +} + +static napi_value GetFingerCount(napi_env env, napi_callback_info info) +{ + napi_escapable_handle_scope scope = nullptr; + auto status = napi_open_escapable_handle_scope(env, &scope); + if (status != napi_ok) { + return nullptr; + } + NG::PanRecognizer* current = GetCurrentGestureRecognizer(env, info); + if (!current) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } + napi_value result = nullptr; + napi_create_int32(env, static_cast(current->GetFingers()), &result); + napi_value newResult = nullptr; + napi_escape_handle(env, scope, result, &newResult); + napi_close_escapable_handle_scope(env, scope); + return newResult; +} + +static napi_value IsFingerCountLimit(napi_env env, napi_callback_info info) +{ + napi_escapable_handle_scope scope = nullptr; + auto status = napi_open_escapable_handle_scope(env, &scope); + if (status != napi_ok) { + return nullptr; + } + NG::PanRecognizer* current = GetCurrentGestureRecognizer(env, info); + if (!current) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } + napi_value result = nullptr; + napi_get_boolean(env, current->GetLimitFingerCount(), &result); + napi_value newResult = nullptr; + napi_escape_handle(env, scope, result, &newResult); + napi_close_escapable_handle_scope(env, scope); + return newResult; +} + +struct PanRecognizerWrapper { + NG::PanRecognizer* recognizer; +}; + +static napi_value GetDistance(napi_env env, napi_callback_info info) +{ + double scale = Dimension(1.0, DimensionUnit::VP).ConvertToPx(); + if (NearZero(scale)) { + scale = 1.0; + } + napi_value thisArg; + napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr); + PanRecognizerWrapper* wrapper = nullptr; + napi_unwrap(env, thisArg, reinterpret_cast(&wrapper)); + CHECK_NULL_RETURN(wrapper, nullptr); + auto current = wrapper->recognizer; + CHECK_NULL_RETURN(current, nullptr); + napi_value napiDistance = nullptr; + napi_create_double(env, current->GetDistance() / scale, &napiDistance); + return napiDistance; +} + +static napi_value GetDirection(napi_env env, napi_callback_info info) +{ + napi_value thisArg; + napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr); + PanRecognizerWrapper* wrapper = nullptr; + napi_unwrap(env, thisArg, reinterpret_cast(&wrapper)); + CHECK_NULL_RETURN(wrapper, nullptr); + auto current = wrapper->recognizer; + CHECK_NULL_RETURN(current, nullptr); + napi_value napiDirection = nullptr; + napi_create_uint32(env, static_cast(current->GetDirection().type), &napiDirection); + return napiDirection; +} + +static napi_value GetPanGestureOptions(napi_env env, napi_callback_info info) +{ + napi_escapable_handle_scope scope = nullptr; + auto status = napi_open_escapable_handle_scope(env, &scope); + if (status != napi_ok) { + return nullptr; + } + NG::PanRecognizer* current = GetCurrentGestureRecognizer(env, info); + if (!current) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } + napi_value result = nullptr; + napi_value funcValue = nullptr; + napi_create_object(env, &result); + + PanRecognizerWrapper* wrapper = new PanRecognizerWrapper { current }; + status = napi_wrap( + env, result, wrapper, + [](napi_env env, void* data, void* hint) { + auto castData = reinterpret_cast(data); + if (castData) { + delete castData; + } + }, + nullptr, nullptr); + if (status != napi_ok) { + LOGE("Failed to wrap native object"); + delete wrapper; + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } + + auto setDirection = [](napi_env env, napi_callback_info info) -> napi_value { return nullptr; }; + auto setDistance = [](napi_env env, napi_callback_info info) -> napi_value { return nullptr; }; + auto setFingers = [](napi_env env, napi_callback_info info) -> napi_value { return nullptr; }; + napi_create_function(env, GET_DIRECTION, NAPI_AUTO_LENGTH, GetDirection, nullptr, &funcValue); + napi_set_named_property(env, result, GET_DIRECTION, funcValue); + napi_create_function(env, GET_DISTANCE, NAPI_AUTO_LENGTH, GetDistance, nullptr, &funcValue); + napi_set_named_property(env, result, GET_DISTANCE, funcValue); + napi_create_function(env, SET_DIRECTION, NAPI_AUTO_LENGTH, setDirection, nullptr, &funcValue); + napi_set_named_property(env, result, SET_DIRECTION, funcValue); + napi_create_function(env, SET_DISTANCE, NAPI_AUTO_LENGTH, setDistance, nullptr, &funcValue); + napi_set_named_property(env, result, SET_DISTANCE, funcValue); + napi_create_function(env, SET_FINGERS, NAPI_AUTO_LENGTH, setFingers, nullptr, &funcValue); + napi_set_named_property(env, result, SET_FINGERS, funcValue); + napi_value newResult = nullptr; + napi_escape_handle(env, scope, result, &newResult); + napi_close_escapable_handle_scope(env, scope); + return newResult; } bool CheckKeysPressed(const std::vector& pressedKeyCodes, std::vector& checkKeyCodes) @@ -281,16 +486,25 @@ static GestureEvent* GetBaseEventInfo( static napi_value GetModifierKeyState(napi_env env, napi_callback_info info) { - napi_handle_scope scope = nullptr; - napi_open_handle_scope(env, &scope); - CHECK_NULL_RETURN(scope, nullptr); + napi_escapable_handle_scope scope = nullptr; + auto status = napi_open_escapable_handle_scope(env, &scope); + if (status != napi_ok) { + return nullptr; + } size_t argc = PARAM_SIZE_ONE; napi_value argv = nullptr; GestureEvent* gestureEventInfo = GetBaseEventInfo(env, info, &argc, &argv); - CHECK_NULL_RETURN(gestureEventInfo, nullptr); + if (!gestureEventInfo) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } bool ret = false; - NAPI_CALL(env, napi_is_array(env, argv, &ret)); + status = napi_is_array(env, argv, &ret); + if (status != napi_ok) { + napi_close_escapable_handle_scope(env, scope); + return nullptr; + } auto pressedKeyCodes = gestureEventInfo->GetPressedKeyCodes(); bool checkRet = false; uint32_t length = 0; @@ -310,12 +524,13 @@ static napi_value GetModifierKeyState(napi_env env, napi_callback_info info) } } } - checkRet = CheckKeysPressed(pressedKeyCodes, checkedKeyCodes); napi_value result = nullptr; napi_get_boolean(env, checkRet, &result); - napi_close_handle_scope(env, scope); - return result; + napi_value newResult = nullptr; + napi_escape_handle(env, scope, result, &newResult); + napi_close_escapable_handle_scope(env, scope); + return newResult; } } @@ -615,9 +830,15 @@ void UIObserverListener::OnPanGestureStateChange(const GestureEvent& gestureEven napi_create_object(env_, &objValueFrameNode); auto container = Container::Current(); - CHECK_NULL_VOID(container); + if (!container) { + napi_close_handle_scope(env_, scope); + return; + } auto frontEnd = container->GetFrontend(); - CHECK_NULL_VOID(frontEnd); + if (!frontEnd) { + napi_close_handle_scope(env_, scope); + return; + } auto nodeId = frameNode->GetId(); objValueFrameNode = frontEnd->GetFrameNodeValueByNodeId(nodeId); @@ -881,34 +1102,12 @@ void UIObserverListener::AddFingerListInfo(napi_value objValueClickEvent, const if (napi_is_array(env_, napiFingerList, &isArray) != napi_ok || !isArray) { return; } - double scale = Dimension(1.0, DimensionUnit::VP).ConvertToPx(); - if (NearZero(scale)) { - scale = 1.0; - } int32_t index = 0; if (fingerList.size() > 0) { for (auto finger : fingerList) { napi_value napiFinger = nullptr; napi_create_object(env_, &napiFinger); - - napi_value napiId = nullptr; - napi_create_double(env_, finger.fingerId_, &napiId); - napi_set_named_property(env_, napiFinger, "id", napiId); - const OHOS::Ace::Offset& globalLocation = finger.globalLocation_; - const OHOS::Ace::Offset& localLocation = finger.localLocation_; - napi_value napiGlobalX = nullptr; - napi_create_double(env_, globalLocation.GetX() / scale, &napiGlobalX); - napi_set_named_property(env_, napiFinger, "globalX", napiGlobalX); - napi_value napiGlobalY = nullptr; - napi_create_double(env_, globalLocation.GetY() / scale, &napiGlobalY); - napi_set_named_property(env_, napiFinger, "globalY", napiGlobalY); - napi_value napiLocalX = nullptr; - napi_create_double(env_, localLocation.GetX() / scale, &napiLocalX); - napi_set_named_property(env_, napiFinger, "localX", napiLocalX); - napi_value napiLocalY = nullptr; - napi_create_double(env_, localLocation.GetY() / scale, &napiLocalY); - napi_set_named_property(env_, napiFinger, "localY", napiLocalY); - + AddFingerObjectInfo(napiFinger, finger); napi_set_element(env_, napiFingerList, index++, napiFinger); } } @@ -916,6 +1115,41 @@ void UIObserverListener::AddFingerListInfo(napi_value objValueClickEvent, const napi_close_handle_scope(env_, scope); } +void UIObserverListener::AddFingerObjectInfo(napi_value napiFinger, const FingerInfo& finger) +{ + double scale = Dimension(1.0, DimensionUnit::VP).ConvertToPx(); + if (NearZero(scale)) { + scale = 1.0; + } + napi_value napiId = nullptr; + napi_create_double(env_, finger.fingerId_, &napiId); + napi_set_named_property(env_, napiFinger, "id", napiId); + napi_value napiHand = nullptr; + napi_create_int32(env_, finger.operatingHand_, &napiHand); + napi_set_named_property(env_, napiFinger, "hand", napiHand); + const OHOS::Ace::Offset& globalLocation = finger.globalLocation_; + const OHOS::Ace::Offset& localLocation = finger.localLocation_; + const OHOS::Ace::Offset& screenLocaltion = finger.screenLocation_; + napi_value napiGlobalX = nullptr; + napi_create_double(env_, globalLocation.GetX() / scale, &napiGlobalX); + napi_set_named_property(env_, napiFinger, "globalX", napiGlobalX); + napi_value napiGlobalY = nullptr; + napi_create_double(env_, globalLocation.GetY() / scale, &napiGlobalY); + napi_set_named_property(env_, napiFinger, "globalY", napiGlobalY); + napi_value napiLocalX = nullptr; + napi_create_double(env_, localLocation.GetX() / scale, &napiLocalX); + napi_set_named_property(env_, napiFinger, "localX", napiLocalX); + napi_value napiLocalY = nullptr; + napi_create_double(env_, localLocation.GetY() / scale, &napiLocalY); + napi_set_named_property(env_, napiFinger, "localY", napiLocalY); + napi_value napiDisplayX = nullptr; + napi_create_double(env_, screenLocaltion.GetX() / scale, &napiDisplayX); + napi_set_named_property(env_, napiFinger, "displayX", napiDisplayX); + napi_value napiDisplayY = nullptr; + napi_create_double(env_, screenLocaltion.GetY() / scale, &napiDisplayY); + napi_set_named_property(env_, napiFinger, "displayY", napiDisplayY); +} + void UIObserverListener::AddClickEventInfoOne(napi_value objValueClickEvent, const ClickInfo& clickInfo) { napi_handle_scope scope = nullptr; @@ -1012,6 +1246,8 @@ void UIObserverListener::AddGestureEventInfoFour(napi_value objValueEvent, const nullptr, nullptr); if (status != napi_ok) { LOGE("napi_wrap failed"); + delete info; + napi_close_handle_scope(env_, scope); return; } napi_value funcValue = nullptr; @@ -1040,6 +1276,8 @@ void UIObserverListener::AddGestureRecognizerInfo( nullptr, nullptr); if (status != napi_ok) { LOGE("napi_wrap failed"); + current->DecRefCount(); + napi_close_handle_scope(env_, scope); return; } @@ -1060,6 +1298,12 @@ void UIObserverListener::AddGestureRecognizerInfo( napi_set_named_property(env_, objValueGestureRecognizer, GET_EVENT_TARGET_INFO, funcValue); napi_create_function(env_, IS_VALID, 0, IsValid, nullptr, &funcValue); napi_set_named_property(env_, objValueGestureRecognizer, IS_VALID, funcValue); + napi_create_function(env_, GET_FINGER_COUNT, 0, GetFingerCount, nullptr, &funcValue); + napi_set_named_property(env_, objValueGestureRecognizer, GET_FINGER_COUNT, funcValue); + napi_create_function(env_, IS_FINGER_COUNT_LIMIT, 0, IsFingerCountLimit, nullptr, &funcValue); + napi_set_named_property(env_, objValueGestureRecognizer, IS_FINGER_COUNT_LIMIT, funcValue); + napi_create_function(env_, GET_PANGESTURE_OPTIONS, 0, GetPanGestureOptions, nullptr, &funcValue); + napi_set_named_property(env_, objValueGestureRecognizer, GET_PANGESTURE_OPTIONS, funcValue); napi_close_handle_scope(env_, scope); } diff --git a/interfaces/napi/kits/observer/ui_observer_listener.h b/interfaces/napi/kits/observer/ui_observer_listener.h index feffd91bbc3ae502f4b24cb091fd9c4e6f4fc6e9..d64b572cc7d2a33ae74dd98e6c66c04f5a87946e 100644 --- a/interfaces/napi/kits/observer/ui_observer_listener.h +++ b/interfaces/napi/kits/observer/ui_observer_listener.h @@ -65,6 +65,7 @@ private: void AddFingerListInfo(napi_value objValueClickEvent, const GestureEvent& gestureEventInfo); void AddClickEventInfoOne(napi_value objValueClickEvent, const ClickInfo& clickInfo); void AddClickEventInfoTwo(napi_value objValueClickEvent, const ClickInfo& clickInfo); + void AddFingerObjectInfo(napi_value napiFinger, const FingerInfo& finger); void AddGestureRecognizerInfo(napi_value objValueGestureRecognizer, const RefPtr& current); void AddTargetObject(napi_value objValueEvent, const BaseEventInfo& baseEventInfo); napi_env env_ = nullptr;