diff --git a/frameworks/ets/ani/BUILD.gn b/frameworks/ets/ani/BUILD.gn index 55e2f44454..9764999efc 100644 --- a/frameworks/ets/ani/BUILD.gn +++ b/frameworks/ets/ani/BUILD.gn @@ -60,5 +60,6 @@ group("ani_packages") { "${ability_runtime_path}/frameworks/ets/ani/vertical_panel_manager:vertical_panel_manager_ani_kit", "${ability_runtime_path}/frameworks/ets/ani/want:want_ani_kit", "${ability_runtime_path}/frameworks/ets/ani/wantagent:aniwantagent", + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager:distributedmissionmanager_ani_pack", ] } diff --git a/frameworks/ets/ani/ui_ability/include/ets_ability_context.h b/frameworks/ets/ani/ui_ability/include/ets_ability_context.h index 098a8023ca..b038257e27 100644 --- a/frameworks/ets/ani/ui_ability/include/ets_ability_context.h +++ b/frameworks/ets/ani/ui_ability/include/ets_ability_context.h @@ -162,6 +162,7 @@ public: static void SetMissionIconCheck(ani_env *env, ani_object aniObj, ani_object pixelMapObj); static void SetMissionWindowIcon(ani_env *env, ani_object aniObj, ani_object pixelMapObj, ani_object callbackobj); + static void SetMissionContinueState(ani_env *env, ani_object aniObj, ani_object state, ani_object callbackObj); private: void OnSetAbilityInstanceInfo(ani_env *env, ani_object aniObj, ani_string labelObj, ani_object iconObj, @@ -169,6 +170,7 @@ private: void OnSetAbilityInstanceInfoInner(ani_env *env, std::string& label, std::shared_ptr icon, ani_object callback, ani_vm *etsVm, ani_ref callbackRef); void OnSetMissionIcon(ani_env *env, ani_object aniObj, ani_object pixelMapObj, ani_object callbackObj); + void OnSetMissionContinueState(ani_env *env, ani_object aniObj, ani_object stateObj, ani_object callbackObj); #endif private: void InheritWindowMode(AAFwk::Want &want); diff --git a/frameworks/ets/ani/ui_ability/include/ets_ui_ability.h b/frameworks/ets/ani/ui_ability/include/ets_ui_ability.h index 0845ef6b7d..9509b7e8d2 100644 --- a/frameworks/ets/ani/ui_ability/include/ets_ui_ability.h +++ b/frameworks/ets/ani/ui_ability/include/ets_ui_ability.h @@ -92,6 +92,14 @@ public: */ void OnConfigurationUpdated(const Configuration &configuration) override; + int32_t OnContinue(AAFwk::WantParams &wantParams, bool &isAsyncOnContinue, + const AppExecFwk::AbilityInfo &abilityInfo) override; + int32_t OnContinueAsyncCB(ani_ref aniWantParamsRef, int32_t status, + const AppExecFwk::AbilityInfo &abilityInfo) override; + bool OnContinueReturnPromise(ani_env* aniEnv, ani_ref aniWantParamRef, const AppExecFwk::AbilityInfo &abilityInfo); + bool CallObjectOnContinueMethod(ani_method method, ani_ref wantParamRef, int32_t& onContinueResult, + bool& isPromise); + /** * @brief Update Contextconfiguration */ diff --git a/frameworks/ets/ani/ui_ability/src/ets_ability_context.cpp b/frameworks/ets/ani/ui_ability/src/ets_ability_context.cpp index 8cb759668b..4939f3b502 100644 --- a/frameworks/ets/ani/ui_ability/src/ets_ability_context.cpp +++ b/frameworks/ets/ani/ui_ability/src/ets_ability_context.cpp @@ -776,6 +776,17 @@ void EtsAbilityContext::SetMissionIconCheck( return; } } + +void EtsAbilityContext::SetMissionContinueState(ani_env *env, ani_object aniObj, ani_object stateObj, + ani_object callbackObj) +{ + auto etsContext = GetEtsAbilityContext(env, aniObj); + if (etsContext == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "null etsContext"); + return; + } + etsContext->OnSetMissionContinueState(env, aniObj, stateObj, callbackObj); +} #endif void EtsAbilityContext::RestoreWindowStage( @@ -2500,6 +2511,35 @@ void EtsAbilityContext::OnSetMissionIcon(ani_env *env, ani_object aniObj, ani_ob AppExecFwk::AsyncCallback(env, callbackObj, EtsErrorUtil::CreateErrorByNativeErr(env, static_cast(innerErrCode)), nullptr); } + +void EtsAbilityContext::OnSetMissionContinueState(ani_env *env, ani_object aniObj, ani_object stateObj, + ani_object callbackObj) +{ + auto context = context_.lock(); + if (context == nullptr) { + TAG_LOGE(AAFwkTag::CONTEXT, "context is nullptr"); + AppExecFwk::AsyncCallback(env, callbackObj, + EtsErrorUtil::CreateError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT), nullptr); + return; + } + int state = 0; + bool result = AAFwk::AniEnumConvertUtil::EnumConvert_EtsToNative(env, stateObj, state); + if (result == false) { + TAG_LOGE(AAFwkTag::CONTEXT, "Unwrap state failed"); + AppExecFwk::AsyncCallback(env, callbackObj, + EtsErrorUtil::CreateError(env, AbilityErrorCode::ERROR_CODE_INVALID_PARAM), nullptr); + return; + } + AAFwk::ContinueState fwkState = AAFwk::ContinueState::CONTINUESTATE_UNKNOWN; + if (state == AAFwk::ContinueState::CONTINUESTATE_ACTIVE) { + fwkState = AAFwk::ContinueState::CONTINUESTATE_ACTIVE; + } else { + fwkState = AAFwk::ContinueState::CONTINUESTATE_INACTIVE; + } + auto innerErrCode = context->SetMissionContinueState(fwkState); + AppExecFwk::AsyncCallback(env, callbackObj, + EtsErrorUtil::CreateErrorByNativeErr(env, static_cast(innerErrCode)), nullptr); +} #endif void EtsAbilityContext::OnStartAbilityAsCaller(ani_env *env, ani_object aniObj, ani_object wantObj, @@ -2818,6 +2858,10 @@ bool BindNativeMethods(ani_env *env, ani_class &cls) ani_native_function { "nativeSetMissionWindowIcon", "C{@ohos.multimedia.image.image.PixelMap}C{utils.AbilityUtils.AsyncCallbackWrapper}:", reinterpret_cast(EtsAbilityContext::SetMissionWindowIcon) }, + ani_native_function { "nativeSetMissionContinueState", + "C{@ohos.app.ability.AbilityConstant.AbilityConstant.ContinueState}" + "C{utils.AbilityUtils.AsyncCallbackWrapper}:", + reinterpret_cast(EtsAbilityContext::SetMissionContinueState) }, }; if ((status = env->Class_BindNativeMethods(cls, functions.data(), functions.size())) != ANI_OK) { TAG_LOGE(AAFwkTag::CONTEXT, "Class_BindNativeMethods failed status: %{public}d", status); diff --git a/frameworks/ets/ani/ui_ability/src/ets_ui_ability.cpp b/frameworks/ets/ani/ui_ability/src/ets_ui_ability.cpp index 01e1adacd0..9ac0fd0d29 100644 --- a/frameworks/ets/ani/ui_ability/src/ets_ui_ability.cpp +++ b/frameworks/ets/ani/ui_ability/src/ets_ui_ability.cpp @@ -157,6 +157,42 @@ void OnPrepareTerminatePromiseCallback(ani_env *env, ani_object aniObj, ani_bool TAG_LOGI(AAFwkTag::UIABILITY, "OnPrepareTerminatePromiseCallback end"); } +void OnContinuePromiseCallback(ani_env *env, ani_object aniObj, ani_ref continueResult) +{ + TAG_LOGI(AAFwkTag::UIABILITY, "OnContinuePromiseCallback called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "null env"); + return; + } + ani_long continueCallbackPtr = 0; + ani_status status = ANI_ERROR; + if ((status = env->Object_GetFieldByName_Long(aniObj, "continueCallbackPoint", &continueCallbackPtr)) != ANI_OK) { + TAG_LOGE(AAFwkTag::UIABILITY, "Object_GetFieldByName_Long status: %{public}d", status); + return; + } + if (continueCallbackPtr == 0) { + TAG_LOGE(AAFwkTag::UIABILITY, "null continueCallbackPtr"); + return; + } + auto *callbackInfo = reinterpret_cast *>(continueCallbackPtr); + if (callbackInfo == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "null callbackInfo"); + return; + } + int32_t intResult = AppExecFwk::ContinuationManagerStage::ON_CONTINUE_ERR; + if (!AAFwk::AniEnumConvertUtil::EnumConvert_EtsToNative( + env, reinterpret_cast(continueResult), intResult)) { + TAG_LOGE(AAFwkTag::UIABILITY, "EnumConvert_EtsToNative failed"); + } + TAG_LOGI(AAFwkTag::UIABILITY, "OnContinuePromiseCallback result = %{public}d", intResult); + callbackInfo->Call(intResult); + AppExecFwk::AbilityTransactionCallbackInfo::Destroy(callbackInfo, env); + if ((status = env->Object_SetFieldByName_Long(aniObj, "continueCallbackPoint", 0)) != ANI_OK) { + TAG_LOGE(AAFwkTag::UIABILITY, "Object_SetFieldByName_Long status: %{public}d", status); + return; + } +} + ani_object GetBindingContext(const std::weak_ptr &abilityContextWeakPtr) { auto abilityContext = abilityContextWeakPtr.lock(); @@ -296,9 +332,11 @@ bool EtsUIAbility::BindNativeMethods() } std::call_once(singletonFlag_, [&status, env, cls]() { std::array functions = { - ani_native_function { "nativeOnDestroyCallback", ":", reinterpret_cast(OnDestroyPromiseCallback) }, - ani_native_function { "nativeOnPrepareToTerminateCallback", "z:", + ani_native_function { "nativeOnDestroyCallback", ":V", reinterpret_cast(OnDestroyPromiseCallback) }, + ani_native_function { "nativeOnPrepareToTerminateCallback", "Z:V", reinterpret_cast(OnPrepareTerminatePromiseCallback) }, + ani_native_function { "nativeOnContinueCallback", ON_CONTINUE_SIG, + reinterpret_cast(OnContinuePromiseCallback) }, }; status = env->Class_BindNativeMethods(cls, functions.data(), functions.size()); }); @@ -1614,6 +1652,178 @@ void EtsUIAbility::OnConfigurationUpdated(const Configuration &configuration) abilityContext_->NotifyBindingObjectConfigUpdate(); } +int32_t EtsUIAbility::OnContinue(AAFwk::WantParams &wantParams, bool &isAsyncOnContinue, + const AppExecFwk::AbilityInfo &abilityInfo) +{ + using namespace AppExecFwk; + auto aniEnv = etsRuntime_.GetAniEnv(); + if (aniEnv == nullptr || etsAbilityObj_ == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "env null or etsAbilityObj_ null"); + return ContinuationManagerStage::ON_CONTINUE_ERR; + } + ani_method method = nullptr; + ani_status status = aniEnv->Class_FindMethod(etsAbilityObj_->aniCls, "callOnContinue", ON_CONTINUE_SIG, &method); + if (status != ANI_OK || method == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "FindMethod callOnContinue failed %{public}d, or null method", status); + return ContinuationManagerStage::ON_CONTINUE_ERR; + } + ani_ref wantParamRef = AppExecFwk::WrapWantParams(aniEnv, wantParams); + if (wantParamRef == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "null wantParamRef"); + return ContinuationManagerStage::ON_CONTINUE_ERR; + } + EtsAbilityLifecycleCallbackArgs ability(etsAbilityObj_); + auto applicationContext = AbilityRuntime::Context::GetApplicationContext(); + if (applicationContext != nullptr) { + applicationContext->DispatchOnAbilityWillContinue(ability); + } + int32_t continueResult = ContinuationManagerStage::ON_CONTINUE_ERR; + bool isPromise = false; + bool callRet = CallObjectOnContinueMethod(method, wantParamRef, continueResult, isPromise); + if (!callRet) { + TAG_LOGE(AAFwkTag::UIABILITY, "Failed to CallObjectOnContinueMethod"); + return ContinuationManagerStage::ON_CONTINUE_ERR; + } + if (isPromise) { + if (true == OnContinueReturnPromise(aniEnv, wantParamRef, abilityInfo)) { + isAsyncOnContinue = true; + return ContinuationManagerStage::AGREE; + } + return ContinuationManagerStage::ON_CONTINUE_ERR; + } + TAG_LOGI(AAFwkTag::UIABILITY, "CallObjectOnContinueMethod, continueResult = %{public}d", continueResult); + if (!AppExecFwk::UnwrapWantParams(aniEnv, wantParamRef, wantParams)) { + TAG_LOGE(AAFwkTag::UIABILITY, "Failed to UnwrapWantParams"); + return ContinuationManagerStage::ON_CONTINUE_ERR; + } + if (applicationContext != nullptr) { + applicationContext->DispatchOnAbilityContinue(ability); + } + return (continueResult == ContinuationManagerStage::AGREE) ? + ContinuationManagerStage::AGREE : ContinuationManagerStage::REJECT; +} + +bool EtsUIAbility::OnContinueReturnPromise(ani_env* aniEnv, + ani_ref aniWantParamRef, const AppExecFwk::AbilityInfo &abilityInfo) +{ + TAG_LOGI(AAFwkTag::UIABILITY, "OnContinueReturnPromise called"); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "env null"); + return false; + } + auto *callbackInfo = AppExecFwk::AbilityTransactionCallbackInfo::Create(); + if (callbackInfo == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "null callbackInfo"); + return false; + } + ani_ref globalWantRef = nullptr; + if (ANI_OK != aniEnv->GlobalReference_Create(aniWantParamRef, &globalWantRef) || globalWantRef == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "GlobalReference_Create failed"); + AppExecFwk::AbilityTransactionCallbackInfo::Destroy(callbackInfo); + return false; + } + callbackInfo->SetFinalizeCallback([globalWantRef] (void* data) { + ani_env* env = reinterpret_cast(data); + if (env != nullptr && globalWantRef != nullptr) { + env->GlobalReference_Delete(globalWantRef); + } + }); + ani_long continueCallbackInfo = reinterpret_cast(callbackInfo); + ani_status status = aniEnv->Object_SetFieldByName_Long( + etsAbilityObj_->aniObj, "continueCallbackPoint", continueCallbackInfo); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::UIABILITY, "Object_SetFieldByName_Long status: %{public}d", status); + AppExecFwk::AbilityTransactionCallbackInfo::Destroy(callbackInfo, aniEnv); + return false; + } + auto weakThis = weak_from_this(); + auto asyncCallback = + [globalWantRef, weakThis, capturedInfo = abilityInfo] (int32_t result) { + auto ability = weakThis.lock(); + if (ability == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "null ability"); + return; + } + ability->OnContinueAsyncCB(globalWantRef, result, capturedInfo); + }; + callbackInfo->Push(asyncCallback); + return true; +} + +int32_t EtsUIAbility::OnContinueAsyncCB(ani_ref aniWantParamsRef, int32_t status, + const AppExecFwk::AbilityInfo &abilityInfo) +{ + TAG_LOGI(AAFwkTag::UIABILITY, "called"); + auto aniEnv = etsRuntime_.GetAniEnv(); + if (aniEnv == nullptr || etsAbilityObj_ == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "env null or etsAbilityObj_ null"); + return ERR_INVALID_VALUE; + } + AAFwk::WantParams wantParams; + if (!AppExecFwk::UnwrapWantParams(aniEnv, aniWantParamsRef, wantParams)) { + TAG_LOGE(AAFwkTag::UIABILITY, "Failed to UnwrapWantParams"); + return ERR_INVALID_VALUE; + } + EtsAbilityLifecycleCallbackArgs ability(etsAbilityObj_); + auto applicationContext = AbilityRuntime::Context::GetApplicationContext(); + if (applicationContext != nullptr) { + applicationContext->DispatchOnAbilityContinue(ability); + } + + Want want; + want.SetParams(wantParams); + want.AddFlags(want.FLAG_ABILITY_CONTINUATION); + want.SetElementName(abilityInfo.deviceId, abilityInfo.bundleName, abilityInfo.name, abilityInfo.moduleName); + int result = AAFwk::AbilityManagerClient::GetInstance()->StartContinuation(want, token_, status); + if (result != ERR_OK) { + TAG_LOGE(AAFwkTag::CONTINUATION, "StartContinuation failed: %{public}d", result); + } + TAG_LOGI(AAFwkTag::UIABILITY, "end"); + return result; +} + +bool EtsUIAbility::CallObjectOnContinueMethod(ani_method method, ani_ref wantParamRef, + int32_t& onContinueResult, bool& isPromise) +{ + TAG_LOGE(AAFwkTag::UIABILITY, "CallObjectOnContinueMethod"); + auto aniEnv = etsRuntime_.GetAniEnv(); + if (aniEnv == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "env null"); + return false; + } + if (etsAbilityObj_ == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "null etsAbilityObj_"); + return false; + } + isPromise = false; + ani_value args[] = { { .r = wantParamRef } }; + ani_ref result = nullptr; + ani_status status = ANI_OK; + if ((status = aniEnv->Object_CallMethod_Ref_A(etsAbilityObj_->aniObj, method, &result, args)) != ANI_OK || + result == nullptr) { + TAG_LOGE(AAFwkTag::UIABILITY, "CallMethod status: %{public}d, or null result", status); + ani_boolean unhandleException = false; + if (ANI_OK == aniEnv->ExistUnhandledError(&unhandleException) && unhandleException) { + TAG_LOGE(AAFwkTag::UIABILITY, "CallObjectOnContinueMethod, unhandleException, reset"); + aniEnv->ResetError(); + } + return false; + } + ani_boolean isUndefined = ANI_FALSE; + aniEnv->Reference_IsUndefined(result, &isUndefined); + if (isUndefined) { + TAG_LOGI(AAFwkTag::UIABILITY, "wait promise back"); + isPromise = true; + return true; + } + if (!AAFwk::AniEnumConvertUtil::EnumConvert_EtsToNative(aniEnv, + reinterpret_cast(result), onContinueResult)) { + TAG_LOGE(AAFwkTag::UIABILITY, "EnumConvert_EtsToNative failed"); + return false; + } + return true; +} + void EtsUIAbility::OnMemoryLevel(int level) { UIAbility::OnMemoryLevel(level); diff --git a/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets b/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets index d06d406fbd..c77adf6691 100644 --- a/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets +++ b/frameworks/ets/ets/@ohos.app.ability.UIAbility.ets @@ -44,10 +44,13 @@ export interface Callee { export default class UIAbility extends Ability { private destroyCallbackPoint: long; private prepareToTerminateCallbackPointer: long; + private continueCallbackPoint: long; private native nativeOnDestroyCallback(): void; private native nativeOnPrepareToTerminateCallback(prepareTermination: boolean): void; + private native nativeOnContinueCallback(result: AbilityConstant.OnContinueResult): void; + private callOnDestroy(): boolean { let p = this.onDestroy(); if (p instanceof Promise) { @@ -74,6 +77,16 @@ export default class UIAbility extends Ability { return false; } + private callOnContinue(wantParams: Record): AbilityConstant.OnContinueResult | undefined { + let p = this.onContinue(wantParams); + if (p instanceof Promise) { + let promiseResult = p as Promise; + promiseResult.then((result: AbilityConstant.OnContinueResult) => this.nativeOnContinueCallback(result)); + return undefined; + } + return p as AbilityConstant.OnContinueResult; + } + context: UIAbilityContext = new UIAbilityContext(); launchWant: Want = new Want(); lastRequestWant: Want = new Want(); @@ -95,6 +108,10 @@ export default class UIAbility extends Ability { onWindowStageRestore(windowStage: window.WindowStage): void { } + onContinue(wantParams: Record): AbilityConstant.OnContinueResult | Promise { + return AbilityConstant.OnContinueResult.REJECT; + } + onDestroy(): Promise | undefined { return undefined; } diff --git a/frameworks/ets/ets/application/UIAbilityContext.ets b/frameworks/ets/ets/application/UIAbilityContext.ets index a849986ff5..2b652f527f 100644 --- a/frameworks/ets/ets/application/UIAbilityContext.ets +++ b/frameworks/ets/ets/application/UIAbilityContext.ets @@ -34,6 +34,7 @@ import UIServiceExtensionConnectCallback from 'application.UIServiceExtensionCon import dialogRequest from '@ohos.app.ability.dialogRequest'; import image from '@ohos.multimedia.image'; import { LocalStorage } from '@ohos.arkui.stateManagement'; +import AbilityConstant from '@ohos.app.ability.AbilityConstant'; class Cleaner { public ptr: long = 0; @@ -168,6 +169,8 @@ export default class UIAbilityContext extends Context { private native nativeSetMissionIcon(icon: image.PixelMap, callback: AsyncCallbackWrapper): void; + private native nativeSetMissionContinueState(state: AbilityConstant.ContinueState, callback: AsyncCallbackWrapper): void; + private native nativeRevokeDelegator(callback: AsyncCallbackWrapper): void; private native nativeStartAppServiceExtensionAbility(want: Want, callback: AsyncCallbackWrapper): void; @@ -467,6 +470,24 @@ export default class UIAbilityContext extends Context { }); } + setMissionContinueState(state: AbilityConstant.ContinueState): Promise { + let p = new Promise((resolve: (data: undefined) => void, reject: (err: BusinessError) => void): void => { + let callback = new AsyncCallbackWrapper((err: BusinessError | null) => { + if (err == null || err.code == 0) { + resolve(undefined); + } else { + reject(err); + } + }); + taskpool.execute((): void => { + this.nativeSetMissionContinueState(state, callback); + }).catch((err: Error): void => { + reject(err as BusinessError); + }); + }); + return p; + } + connectServiceExtensionAbility(want: Want, options: ConnectOptions): long { return this.nativeConnectServiceExtensionAbility(want, options); } diff --git a/frameworks/ets/taihe/distributedmissionmanager/BUILD.gn b/frameworks/ets/taihe/distributedmissionmanager/BUILD.gn new file mode 100644 index 0000000000..78a888e8b0 --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/BUILD.gn @@ -0,0 +1,141 @@ +# Copyright (C) 2025-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("//build/config/components/ets_frontend/ets2abc_config.gni") +import("//build/ohos.gni") +import("//build/ohos/taihe_idl/taihe.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +subsystem_name = "ability" +part_name = "ability_runtime" +taihe_generated_file_path = "$taihe_file_path/out/$subsystem_name/$part_name" + +copy_taihe_idl("copy_taihe") { + sources = [ + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager/idl/ContinuableInfo.taihe", + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager/idl/ContinueCallback.taihe", + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager/idl/ContinueDeviceInfo.taihe", + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager/idl/ContinueMissionInfo.taihe", + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager/idl/MissionCallbacks.taihe", + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager/idl/MissionDeviceInfo.taihe", + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager/idl/MissionParameter.taihe", + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager/idl/ohos.distributedmissionmanager.taihe", + ] +} + +ohos_taihe("run_taihe") { + taihe_generated_file_path = "$taihe_generated_file_path" + deps = [ ":copy_taihe" ] + outputs = [ + "$taihe_generated_file_path/src/ohos.distributedmissionmanager.ani.cpp", + "$taihe_generated_file_path/src/ohos.distributedmissionmanager.abi.c", + "$taihe_generated_file_path/src/ContinuableInfo.ani.cpp", + "$taihe_generated_file_path/src/ContinuableInfo.abi.c", + "$taihe_generated_file_path/src/ContinueCallback.ani.cpp", + "$taihe_generated_file_path/src/ContinueCallback.abi.c", + "$taihe_generated_file_path/src/ContinueDeviceInfo.ani.cpp", + "$taihe_generated_file_path/src/ContinueDeviceInfo.abi.c", + "$taihe_generated_file_path/src/ContinueMissionInfo.ani.cpp", + "$taihe_generated_file_path/src/ContinueMissionInfo.abi.c", + "$taihe_generated_file_path/src/MissionCallbacks.ani.cpp", + "$taihe_generated_file_path/src/MissionCallbacks.abi.c", + "$taihe_generated_file_path/src/MissionDeviceInfo.ani.cpp", + "$taihe_generated_file_path/src/MissionDeviceInfo.abi.c", + "$taihe_generated_file_path/src/MissionParameter.ani.cpp", + "$taihe_generated_file_path/src/MissionParameter.abi.c", + ] +} + +taihe_shared_library("distributedmissionmanager_ani") { + taihe_generated_file_path = "$taihe_generated_file_path" + subsystem_name = "$subsystem_name" + part_name = "$part_name" + include_dirs = [ + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager/include", + "${ability_runtime_path}/frameworks/js/napi/mission_manager", + "${ability_runtime_path}/frameworks/ets/ani/ani_common/include", + ] + sources = get_target_outputs(":run_taihe") + sources += [ + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager/src/ani_constructor.cpp", + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager/src/ani_utils.cpp", + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager/src/ani_error_utils.cpp", + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager/src/ani_observer_utils.cpp", + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager/src/ani_remotelistener_utils.cpp", + "${ability_runtime_path}/frameworks/ets/taihe/distributedmissionmanager/src/ohos.distributedmissionmanager.impl.cpp", + "${ability_runtime_path}/frameworks/js/napi/mission_manager/dms_sa_client.cpp", + "${ability_runtime_path}/frameworks/js/napi/mission_manager/mission_continue_stub.cpp", + ] + deps = [ + ":run_taihe", + "${ability_runtime_innerkits_path}/ability_manager:ability_manager", + "${ability_runtime_innerkits_path}/ability_manager:mission_info", + "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", + ] + + if (os_level == "standard") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + } + cflags = [ + "-DHILOG_ENABLE", + "-fPIC", + "-g3", + ] + external_deps = [ + "ability_base:want", + "c_utils:utils", + "eventhandler:libeventhandler", + "hilog:libhilog", + "ipc:ipc_core", + "samgr:samgr_proxy", + ] + subsystem_name = "ability" + part_name = "ability_runtime" +} + +generate_static_abc("distributedmissionmanager_abc") { + base_url = "$taihe_generated_file_path" + files = [ + "$taihe_generated_file_path/@ohos.distributedMissionManager.ets", + "$taihe_generated_file_path/application.ContinuableInfo.ets", + "$taihe_generated_file_path/application.ContinueCallback.ets", + "$taihe_generated_file_path/application.ContinueDeviceInfo.ets", + "$taihe_generated_file_path/application.ContinueMissionInfo.ets", + "$taihe_generated_file_path/application.MissionCallbacks.ets", + "$taihe_generated_file_path/application.MissionDeviceInfo.ets", + "$taihe_generated_file_path/application.MissionParameter.ets", + ] + dst_file = "$target_out_dir/distributedmissionmanager.abc" + is_boot_abc = "True" + device_dst_file = "/system/framework/distributedmissionmanager.abc" + dependencies = [ ":run_taihe" ] +} + +ohos_prebuilt_etc("distributedmissionmanager_etc") { + source = "$target_out_dir/distributedmissionmanager.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":distributedmissionmanager_abc" ] +} + +group("distributedmissionmanager_ani_pack") { + deps = [ + ":distributedmissionmanager_ani", + ":distributedmissionmanager_etc", + ] +} diff --git a/frameworks/ets/taihe/distributedmissionmanager/idl/ContinuableInfo.taihe b/frameworks/ets/taihe/distributedmissionmanager/idl/ContinuableInfo.taihe new file mode 100644 index 0000000000..b0a29f671d --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/idl/ContinuableInfo.taihe @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025-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. + */ +@!namespace("application.ContinuableInfo") + +struct ContinuableInfo { + srcDeviceId: String; + bundleName: String; + srcBundleName: Optional; + continueType: Optional; +} \ No newline at end of file diff --git a/frameworks/ets/taihe/distributedmissionmanager/idl/ContinueCallback.taihe b/frameworks/ets/taihe/distributedmissionmanager/idl/ContinueCallback.taihe new file mode 100644 index 0000000000..f8250a715d --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/idl/ContinueCallback.taihe @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025-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. + */ +@!namespace("application.ContinueCallback") + +struct ContinueCallback { + onContinueDone: (result: i32) => void; +} diff --git a/frameworks/ets/taihe/distributedmissionmanager/idl/ContinueDeviceInfo.taihe b/frameworks/ets/taihe/distributedmissionmanager/idl/ContinueDeviceInfo.taihe new file mode 100644 index 0000000000..8fa8a96601 --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/idl/ContinueDeviceInfo.taihe @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025-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. + */ +@!namespace("application.ContinueDeviceInfo") + +struct ContinueDeviceInfo { + srcDeviceId: String; + dstDeviceId: String; + missionId: i32; + wantParam: @sts_type("Record") Opaque; +} diff --git a/frameworks/ets/taihe/distributedmissionmanager/idl/ContinueMissionInfo.taihe b/frameworks/ets/taihe/distributedmissionmanager/idl/ContinueMissionInfo.taihe new file mode 100644 index 0000000000..a45eb96239 --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/idl/ContinueMissionInfo.taihe @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025-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. + */ +@!namespace("application.ContinueMissionInfo") + +struct ContinueMissionInfo { + srcDeviceId: String; + dstDeviceId: String; + bundleName: String; + srcBundleName: Optional; + continueType: Optional; + wantParam: @sts_type("Record") Opaque; +} + diff --git a/frameworks/ets/taihe/distributedmissionmanager/idl/MissionCallbacks.taihe b/frameworks/ets/taihe/distributedmissionmanager/idl/MissionCallbacks.taihe new file mode 100644 index 0000000000..473f5edd2f --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/idl/MissionCallbacks.taihe @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025-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. + */ + +@!namespace("application.MissionCallbacks") + +struct MissionCallback { + notifyMissionsChanged : (deviceId: String) => void; + notifySnapshot : (deviceId: String, mission: i32) => void; + notifyNetDisconnect : (deviceId: String, state: i32) => void; +} diff --git a/frameworks/ets/taihe/distributedmissionmanager/idl/MissionDeviceInfo.taihe b/frameworks/ets/taihe/distributedmissionmanager/idl/MissionDeviceInfo.taihe new file mode 100644 index 0000000000..d2e34f3cb3 --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/idl/MissionDeviceInfo.taihe @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025-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. + */ + +@!namespace("application.MissionDeviceInfo") + +struct MissionDeviceInfo { + deviceId: String; +} \ No newline at end of file diff --git a/frameworks/ets/taihe/distributedmissionmanager/idl/MissionParameter.taihe b/frameworks/ets/taihe/distributedmissionmanager/idl/MissionParameter.taihe new file mode 100644 index 0000000000..86dd1743ee --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/idl/MissionParameter.taihe @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025-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. + */ + +@!namespace("application.MissionParameter") + +struct MissionParameter { + deviceId: String; + fixConflict: bool; + tag: i64; +} + diff --git a/frameworks/ets/taihe/distributedmissionmanager/idl/ohos.distributedmissionmanager.taihe b/frameworks/ets/taihe/distributedmissionmanager/idl/ohos.distributedmissionmanager.taihe new file mode 100644 index 0000000000..ab035c2060 --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/idl/ohos.distributedmissionmanager.taihe @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025-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. + */ + +@!namespace("@ohos.distributedMissionManager", "distributedMissionManager") +@!sts_export_default + +@!sts_inject_into_module(""" +import { AsyncCallback, Callback, BusinessError } from '@ohos.base'; +""") + +use ContinuableInfo as appContinuableInfo; +use MissionParameter as appMissionParameter; +use MissionDeviceInfo as appMissionDeviceInfo; +use MissionCallbacks as appMissionCallback; +use ContinueMissionInfo as appContinueMissionInfo; +use ContinueCallback as appContinueCallback; +use ContinueDeviceInfo as appContinueDeviceInfo; + +enum ContinueState : i32 { + ACTIVE = 0, + INACTIVE = 1, +} + +struct ContinueCallbackInfo { + state: ContinueState; + info: appContinuableInfo.ContinuableInfo; +} + +@!sts_inject(""" + static { loadLibrary("distributedmissionmanager_ani.z"); } + + function on(event: string, cb: (arg0 : Object) => void) : void { + switch (event) { + case "continueStateChange": { + onContinueStateChange(cb as (info: ContinueCallbackInfo) => void); + return; + } + default: throw new Error(`Unknown event: ${event}`); + } + } + function off(event: string, cb?: (arg0 : Object) => void) : void { + switch (event) { + case "continueStateChange": { + offContinueStateChange(cb); + return; + } + default: throw new Error(`Unknown type: ${event}`); + } + } +""") + +function OnContinueStateChange(f: (info: ContinueCallbackInfo) => void) : void; +function OffContinueStateChange(callbackOpt: Optional<(info: ContinueCallbackInfo) => void>) : void; + +@gen_async("startSyncRemoteMissions") +@gen_promise("startSyncRemoteMissions") +function StartSyncRemoteMissionsSync(parameter: appMissionParameter.MissionParameter): void; + +@gen_async("stopSyncRemoteMissions") +@gen_promise("stopSyncRemoteMissions") +function StopSyncRemoteMissionsSync(parameter: appMissionDeviceInfo.MissionDeviceInfo): void; + +@gen_async("registerMissionListener") +@gen_promise("registerMissionListener") +function RegisterMissionListenerSync(parameter: appMissionDeviceInfo.MissionDeviceInfo, options: appMissionCallback.MissionCallback): void; + +@gen_async("unRegisterMissionListener") +@gen_promise("unRegisterMissionListener") +function UnRegisterMissionListenerSync(parameter: appMissionDeviceInfo.MissionDeviceInfo): void; + +@rename("continueMission") +function ContinueMissionWithMissionInfoCallback(parameter: appContinueMissionInfo.ContinueMissionInfo, callback: (err: @sts_type("BusinessError") Opaque) => void): void; + +@rename("continueMission") +function ContinueMissionWithMissionInfoPromise(parameter: appContinueMissionInfo.ContinueMissionInfo): @sts_type("Promise") Opaque; + +@gen_async("continueMission") +@gen_promise("continueMission") +function ContinueMissionWithDeviceInfoSync(parameter: appContinueDeviceInfo.ContinueDeviceInfo, options: appContinueCallback.ContinueCallback) : void; diff --git a/frameworks/ets/taihe/distributedmissionmanager/include/ani_error_utils.h b/frameworks/ets/taihe/distributedmissionmanager/include/ani_error_utils.h new file mode 100644 index 0000000000..8e2ee9d46d --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/include/ani_error_utils.h @@ -0,0 +1,129 @@ +/* + * 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. + */ +#ifndef OHOS_ANI_ERROR_UTILS_H +#define OHOS_ANI_ERROR_UTILS_H +#include +#include "hilog_tag_wrapper.h" + +namespace ani_errorutils { + +void ThrowError(const char* message); +void ThrowError(int32_t code, const char* message); +ani_ref ToBusinessError(ani_env *env, int32_t code, const std::string &message); + +int32_t ErrorCodeReturn(int32_t code); +std::string ErrorMessageReturn(int32_t code); +bool AniPromiseCallback(ani_env* env, ani_resolver deferred, int32_t result, ani_ref resolveResult = nullptr); + +#define CHECK_AND_RETURN_RET_LOG(cond, ret, fmt, ...) \ + do { \ + if (!(cond)) { \ + TAG_LOGE(AAFwkTag::MISSION, fmt, ##__VA_ARGS__); \ + return ret; \ + } \ + } while (0) + +} // namespace ani_errorutils + +namespace OHOS { +namespace AAFwk { + +enum ErrorCode { + NO_ERROR = 0, + INVALID_PARAMETER = -1, + REMOTE_MISSION_NOT_FOUND = -2, + PERMISSION_DENY = -3, + REGISTRATION_NOT_FOUND = -4, + /** + * Result(201) for permission denied. + */ + PERMISSION_DENIED = 201, + /** + * Result(202) for non-system-app use system-api. + */ + NOT_SYSTEM_APP = 202, + /** + * Result(401) for parameter check failed. + */ + PARAMETER_CHECK_FAILED = 401, + /** + * Result(16300501) for the system ability work abnormally. + */ + SYSTEM_WORK_ABNORMALLY = 16300501, + /** + * Result(29360221) for failed to get the missionInfo of the specified missionId. + */ + NO_MISSION_INFO_FOR_MISSION_ID = 29360221, + /** + * Result(16300503) for the application is not installed on the remote end and installation-free is + * not supported. + */ + REMOTE_UNINSTALLED_AND_UNSUPPORT_FREEINSTALL_FOR_CONTINUE = 16300503, + /** + * Result(16300504) for the application is not installed on the remote end but installation-free is + * supported, try again with freeInstall flag. + */ + CONTINUE_WITHOUT_FREEINSTALL_FLAG = 16300504, + /** + * Result(16300506) throw to js for the local continuation task is already in progress. + */ + ERR_CONTINUE_ALREADY_IN_PROGRESS = 16300506, + /** + * Result(16300507) throw to js for Failed to get the missionInfo of the specified bundle name. + */ + ERR_GET_MISSION_INFO_OF_BUNDLE_NAME = 16300507, + /** + * Result(16300508) throw to js for bind error due to the remote device hotspot enable, try again after disable + * the remote device hotspot. + */ + ERR_BIND_REMOTE_HOTSPOT_ENABLE_STATE = 16300508, + /** + * Result(16300509) throw to js for the remote device has been linked with other devices, try again when + * the remote device is idle. + */ + ERR_BIND_REMOTE_IN_BUSY_LINK = 16300509, + /** + * Result(29360222) for the operation device must be the device where the application to be continued + * is located or the target device to be continued. + */ + OPERATION_DEVICE_NOT_INITIATOR_OR_TARGET = 29360222, + /** + * Result(29360223) for the local continuation task is already in progress. + */ + CONTINUE_ALREADY_IN_PROGRESS = 29360223, + /** + * Result(29360224) for the mission is dead, try again after restart mission. + */ + MISSION_FOR_CONTINUING_IS_NOT_ALIVE = 29360224, + /* + * Result(29360144) for get local deviceId fail. + */ + GET_LOCAL_DEVICE_ERR = 29360144, + /** + * Result(29360174) for get remote dms fail. + */ + GET_REMOTE_DMS_FAIL = 29360174, + /* + * Result(29360202) for continue remote not install and support free install. + */ + CONTINUE_REMOTE_UNINSTALLED_SUPPORT_FREEINSTALL = 29360202, + /* + * Result(29360203) for continue remote not install and not support free install. + */ + CONTINUE_REMOTE_UNINSTALLED_UNSUPPORT_FREEINSTALL = 29360203, +}; +} +} +#endif // OHOS_ANI_ERROR_UTILS_H diff --git a/frameworks/ets/taihe/distributedmissionmanager/include/ani_observer_utils.h b/frameworks/ets/taihe/distributedmissionmanager/include/ani_observer_utils.h new file mode 100644 index 0000000000..afdd9984f3 --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/include/ani_observer_utils.h @@ -0,0 +1,64 @@ +/* + * 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. + */ +#ifndef OHOS_ANI_OBSERVER_UTILS_H +#define OHOS_ANI_OBSERVER_UTILS_H +#include +#include + +#include "taihe/runtime.hpp" +#include "ohos.distributedmissionmanager.proj.hpp" +#include "ohos.distributedmissionmanager.impl.hpp" +#include "event_handler.h" +#include "event_runner.h" +#include "remote_on_listener_stub.h" + +namespace ani_observerutils { + +using namespace OHOS; + +using JsOnCallbackViewType = ::taihe::callback_view< + void(::ohos::distributedmissionmanager::ContinueCallbackInfo const&)>; +using JsOnCallbackType = ::taihe::callback; + +class JsBaseObserver { +public: + JsBaseObserver(); + virtual ~JsBaseObserver() {} + bool SendEventToMainThread(const std::function func); + + std::recursive_mutex mutex_; + static std::shared_ptr mainHandler_; +}; + +class MissionObserver : public JsBaseObserver, public AAFwk::RemoteOnListenerStub, + public std::enable_shared_from_this { +public: + MissionObserver(); + ~MissionObserver(); + bool AddCallback(JsOnCallbackType cb); + void DeleteCallback(::taihe::optional_view optCallback); + bool IsCallbackListEmpty(); + + void OnCallback(const uint32_t continueState, const std::string &srcDeviceId, + const std::string &bundleName, const std::string &continueType = "", + const std::string &srcBundleName = "") override; + void OnCallbackInMainThread(const ::ohos::distributedmissionmanager::ContinueCallbackInfo& info); + +protected: + std::vector callbackList_; +}; + +} // namespace ani_observerutils +#endif // OHOS_ANI_OBSERVER_UTILS_H diff --git a/frameworks/ets/taihe/distributedmissionmanager/include/ani_remotelistener_utils.h b/frameworks/ets/taihe/distributedmissionmanager/include/ani_remotelistener_utils.h new file mode 100644 index 0000000000..c59f00f76b --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/include/ani_remotelistener_utils.h @@ -0,0 +1,75 @@ +/* + * 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. + */ +#ifndef OHOS_ANI_REMOTELISTENER_UTILS_H +#define OHOS_ANI_REMOTELISTENER_UTILS_H +#include +#include + +#include "taihe/runtime.hpp" +#include "ohos.distributedmissionmanager.proj.hpp" +#include "ohos.distributedmissionmanager.impl.hpp" +#include "event_handler.h" +#include "event_runner.h" +#include "mission_continue_stub.h" +#include "refbase.h" +#include "remote_mission_listener_stub.h" + +namespace ani_remotelistenerutils { + +using namespace OHOS; + +class AniRemoteMissionListener : public AAFwk::RemoteMissionListenerStub { +public: + AniRemoteMissionListener(const ::MissionCallbacks::MissionCallback &ref); + virtual ~AniRemoteMissionListener(); + + void SetCallbacks(const ::MissionCallbacks::MissionCallback &ref); + void NotifyMissionsChanged(const std::string &deviceId) override; + void NotifySnapshot(const std::string &deviceId, int32_t missionId) override; + void NotifyNetDisconnect(const std::string &deviceId, int32_t state) override; + + void NotifyMissionsChangedInMainThread(const std::string &deviceId); + void NotifySnapshotInMainThread(const std::string &deviceId, int32_t missionId); + void NotifyNetDisconnectInMainThread(const std::string &deviceId, int32_t state); + + bool SendEventToMainThread(const std::function func); + void Release(); + +private: + ::MissionCallbacks::MissionCallback callbacks_; + std::recursive_mutex mutex_; + bool released_ = false; +}; + +class AniMissionContinue : public AAFwk::MissionContinueStub { +public: + explicit AniMissionContinue(::taihe::callback const& callback); + explicit AniMissionContinue(::ContinueCallback::ContinueCallback const& callback); + explicit AniMissionContinue(ani_env *env, ani_resolver deferred); + ~AniMissionContinue(); + bool SendEventToMainThread(const std::function func); + void OnContinueDone(int32_t result) override; + void OnContinueDoneInMainThread(int32_t result); + void PromiseResult(ani_env* currentEnv, int32_t result); + +private: + ani_vm *vm_ = nullptr; + std::optional<::taihe::callback> callbackByMissionInfo_; + std::optional<::ContinueCallback::ContinueCallback> callbackByDeviceInfo_; + ani_resolver deferred_ = nullptr; +}; + +} // namespace ani_observerutils +#endif // OHOS_ANI_REMOTELISTENER_UTILS_H diff --git a/frameworks/ets/taihe/distributedmissionmanager/include/ani_utils.h b/frameworks/ets/taihe/distributedmissionmanager/include/ani_utils.h new file mode 100644 index 0000000000..f2bc304569 --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/include/ani_utils.h @@ -0,0 +1,30 @@ +/* + * 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. + */ +#ifndef OHOS_ANI_UTILS_H +#define OHOS_ANI_UTILS_H + +#include +#include +#include +#include "taihe/runtime.hpp" + +namespace ani_utils { + +ani_status AniCreateInt(ani_env* env, int32_t value, ani_object& result); +void AniExecuteFunc(ani_vm* vm, const std::function func); + +} //namespace ani_utils +#endif + diff --git a/frameworks/ets/taihe/distributedmissionmanager/src/ani_constructor.cpp b/frameworks/ets/taihe/distributedmissionmanager/src/ani_constructor.cpp new file mode 100644 index 0000000000..dc6816a6cc --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/src/ani_constructor.cpp @@ -0,0 +1,71 @@ +/* + * 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 "ohos.distributedmissionmanager.ani.hpp" +#include "ContinueCallback.ani.hpp" +#include "MissionCallbacks.ani.hpp" +#include "ContinuableInfo.ani.hpp" +#include "MissionParameter.ani.hpp" +#include "ContinueDeviceInfo.ani.hpp" +#include "MissionDeviceInfo.ani.hpp" +#include "ContinueMissionInfo.ani.hpp" +#if __has_include() +#include +#elif __has_include() +#include +#else +#error "ani.h not found. Please ensure the Ani SDK is correctly installed." +#endif +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + ani_env *env; + if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) { + return ANI_ERROR; + } + ani_status status = ANI_OK; + if (ANI_OK != ohos::distributedmissionmanager::ANIRegister(env)) { + std::cerr << "Error from ohos::data::distributedkvstore::ANIRegister" << std::endl; + status = ANI_ERROR; + } + if (ANI_OK != ContinueCallback::ANIRegister(env)) { + std::cerr << "Error from ContinueCallback::ANIRegister" << std::endl; + status = ANI_ERROR; + } + if (ANI_OK != MissionCallbacks::ANIRegister(env)) { + std::cerr << "Error from MissionCallbacks::ANIRegister" << std::endl; + status = ANI_ERROR; + } + if (ANI_OK != ContinuableInfo::ANIRegister(env)) { + std::cerr << "Error from ContinuableInfo::ANIRegister" << std::endl; + status = ANI_ERROR; + } + if (ANI_OK != MissionParameter::ANIRegister(env)) { + std::cerr << "Error from MissionParameter::ANIRegister" << std::endl; + status = ANI_ERROR; + } + if (ANI_OK != ContinueDeviceInfo::ANIRegister(env)) { + std::cerr << "Error from ContinueDeviceInfo::ANIRegister" << std::endl; + status = ANI_ERROR; + } + if (ANI_OK != MissionDeviceInfo::ANIRegister(env)) { + std::cerr << "Error from MissionDeviceInfo::ANIRegister" << std::endl; + status = ANI_ERROR; + } + if (ANI_OK != ContinueMissionInfo::ANIRegister(env)) { + std::cerr << "Error from ContinueMissionInfo::ANIRegister" << std::endl; + status = ANI_ERROR; + } + *result = ANI_VERSION_1; + return status; +} diff --git a/frameworks/ets/taihe/distributedmissionmanager/src/ani_error_utils.cpp b/frameworks/ets/taihe/distributedmissionmanager/src/ani_error_utils.cpp new file mode 100644 index 0000000000..68bcc641d7 --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/src/ani_error_utils.cpp @@ -0,0 +1,182 @@ +/* + * 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 + +#include "taihe/runtime.hpp" +#include "ani_error_utils.h" +#include "ability_manager_errors.h" + +namespace ani_errorutils { +using namespace OHOS::AAFwk; + +constexpr int32_t ERR_INVALID_VALUE = -1; +constexpr char CLASS_NAME_BUSINESSERROR[] = "@ohos.base.BusinessError"; + +int32_t ErrorCodeReturn(int32_t code) +{ + switch (code) { + case NO_ERROR: + return NO_ERROR; + case CHECK_PERMISSION_FAILED: + return PERMISSION_DENIED; + case DMS_PERMISSION_DENIED: + return PERMISSION_DENIED; + case ERR_INVALID_VALUE: + return PARAMETER_CHECK_FAILED; + case INVALID_PARAMETERS_ERR: + return PARAMETER_CHECK_FAILED; + case REGISTER_REMOTE_MISSION_LISTENER_FAIL: + return PARAMETER_CHECK_FAILED; + case NO_MISSION_INFO_FOR_MISSION_ID: + return NO_MISSION_INFO_FOR_MISSION_ID; + case CONTINUE_REMOTE_UNINSTALLED_UNSUPPORT_FREEINSTALL: + return REMOTE_UNINSTALLED_AND_UNSUPPORT_FREEINSTALL_FOR_CONTINUE; + case CONTINUE_REMOTE_UNINSTALLED_SUPPORT_FREEINSTALL: + return CONTINUE_WITHOUT_FREEINSTALL_FLAG; + case OPERATION_DEVICE_NOT_INITIATOR_OR_TARGET: + return OPERATION_DEVICE_NOT_INITIATOR_OR_TARGET; + case CONTINUE_ALREADY_IN_PROGRESS: + return CONTINUE_ALREADY_IN_PROGRESS; + case MISSION_FOR_CONTINUING_IS_NOT_ALIVE: + return MISSION_FOR_CONTINUING_IS_NOT_ALIVE; + case ERR_NOT_SYSTEM_APP: + return NOT_SYSTEM_APP; + default: + return SYSTEM_WORK_ABNORMALLY; + }; +} + +std::string ErrorMessageReturn(int32_t code) +{ + switch (code) { + case NO_ERROR: + return std::string(); + case PERMISSION_DENIED: + return std::string("permission denied"); + case PARAMETER_CHECK_FAILED: + return std::string("parameter check failed."); + case SYSTEM_WORK_ABNORMALLY: + return std::string("the system ability work abnormally."); + case NO_MISSION_INFO_FOR_MISSION_ID: + return std::string("failed to get the missionInfo of the specified missionId."); + case REMOTE_UNINSTALLED_AND_UNSUPPORT_FREEINSTALL_FOR_CONTINUE: + return std::string("the application is not installed on the " + "remote end and installation-free is not supported."); + case CONTINUE_WITHOUT_FREEINSTALL_FLAG: + return std::string("The application is not installed on the remote end and " + "installation-free is supported. Try again with the freeInstall flag."); + case OPERATION_DEVICE_NOT_INITIATOR_OR_TARGET: + return std::string("The operation device must be the device where the " + "application to be continued is currently located or the target device."); + case ERR_CONTINUE_ALREADY_IN_PROGRESS: + case CONTINUE_ALREADY_IN_PROGRESS: + return std::string("the local continuation task is already in progress."); + case MISSION_FOR_CONTINUING_IS_NOT_ALIVE: + return std::string("the mission for continuing is not alive, " + "try again after restart this mission."); + case ERR_GET_MISSION_INFO_OF_BUNDLE_NAME: + return std::string("Failed to get the missionInfo of the specified bundle name."); + case ERR_BIND_REMOTE_HOTSPOT_ENABLE_STATE: + return std::string("bind error due to the remote device hotspot enable, try again after disable " + "the remote device hotspot."); + case ERR_BIND_REMOTE_IN_BUSY_LINK: + return std::string("the remote device has been linked with other devices, try again when " + "the remote device is idle."); + case NOT_SYSTEM_APP: + return std::string("The app is not system-app."); + default: + return std::string("the system ability work abnormally."); + }; +} + +void ThrowError(const char* message) +{ + if (message == nullptr) { + return; + } + std::string errMsg(message); + taihe::set_error(errMsg); +} + +void ThrowError(int32_t code, const char* message) +{ + TAG_LOGE(AAFwkTag::MISSION, "ThrowError, code = %{public}d", code); + if (message == nullptr) { + return; + } + std::string errMsg(message); + taihe::set_business_error(code, errMsg); +} + +ani_ref ToBusinessError(ani_env *env, int32_t code, const std::string &message) +{ + if (env == nullptr) { + return nullptr; + } + ani_class cls {}; + CHECK_AND_RETURN_RET_LOG(env->FindClass(CLASS_NAME_BUSINESSERROR, &cls) == ANI_OK, nullptr, + "find class %{public}s failed", CLASS_NAME_BUSINESSERROR); + ani_method ctor {}; + CHECK_AND_RETURN_RET_LOG(env->Class_FindMethod(cls, "", ":", &ctor) == ANI_OK, nullptr, + "find method BusinessError constructor failed"); + ani_object error {}; + CHECK_AND_RETURN_RET_LOG(env->Object_New(cls, ctor, &error) == ANI_OK, nullptr, + "new object %{public}s failed", CLASS_NAME_BUSINESSERROR); + CHECK_AND_RETURN_RET_LOG( + env->Object_SetPropertyByName_Int(error, "code", static_cast(code)) == ANI_OK, nullptr, + "set property BusinessError.code failed"); + if (message.size() > 0) { + ani_string messageRef {}; + CHECK_AND_RETURN_RET_LOG(env->String_NewUTF8(message.c_str(), message.size(), &messageRef) == ANI_OK, nullptr, + "new message string failed"); + CHECK_AND_RETURN_RET_LOG( + env->Object_SetPropertyByName_Ref(error, "message", static_cast(messageRef)) == ANI_OK, nullptr, + "set property BusinessError.message failed"); + } + return error; +} + +bool AniPromiseCallback(ani_env* env, ani_resolver deferred, int32_t result, ani_ref resolveResult) +{ + ani_status status = ANI_OK; + if (result != NO_ERROR) { + int32_t errCode = ErrorCodeReturn(result); + std::string errMessage = ErrorMessageReturn(result); + ani_ref errobj = ToBusinessError(env, errCode, errMessage); + if (errobj == nullptr) { + TAG_LOGE(AAFwkTag::MISSION, "ToBusinessError failed"); + return false; + } + if ((status = env->PromiseResolver_Reject(deferred, static_cast(errobj))) != ANI_OK) { + TAG_LOGE(AAFwkTag::MISSION, "PromiseResolver_Reject failed, status = %{public}d", status); + return false; + } + return true; + } + ani_ref promiseResult = resolveResult; + if (promiseResult == nullptr) { + if ((status = env->GetUndefined(&promiseResult)) != ANI_OK) { + TAG_LOGE(AAFwkTag::MISSION, "get undefined value failed, status = %{public}d", status); + return false; + } + } + if ((status = env->PromiseResolver_Resolve(deferred, promiseResult)) != ANI_OK) { + TAG_LOGE(AAFwkTag::MISSION, "PromiseResolver_Resolve failed, status = %{public}d", status); + return false; + } + return true; +} + +} // namespace OHOS::DistributedKVStore \ No newline at end of file diff --git a/frameworks/ets/taihe/distributedmissionmanager/src/ani_observer_utils.cpp b/frameworks/ets/taihe/distributedmissionmanager/src/ani_observer_utils.cpp new file mode 100644 index 0000000000..5505414007 --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/src/ani_observer_utils.cpp @@ -0,0 +1,133 @@ +/* + * 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 "ani_observer_utils.h" +#include +#include + +#include "hilog_tag_wrapper.h" + +namespace ani_observerutils { + +std::shared_ptr JsBaseObserver::mainHandler_; +static std::once_flag g_handlerOnceFlag; + +JsBaseObserver::JsBaseObserver() +{ +} + +bool JsBaseObserver::SendEventToMainThread(const std::function func) +{ + if (func == nullptr) { + return false; + } + std::call_once(g_handlerOnceFlag, [] { + auto runner = OHOS::AppExecFwk::EventRunner::GetMainEventRunner(); + if (runner) { + mainHandler_ = std::make_shared(runner); + } + }); + if (!mainHandler_) { + TAG_LOGI(AAFwkTag::MISSION, "Failed to initialize event handler"); + return false; + } + mainHandler_->PostTask(func, "", 0, OHOS::AppExecFwk::EventQueue::Priority::IMMEDIATE, {}); + return true; +} + +MissionObserver::MissionObserver() +{ + TAG_LOGI(AAFwkTag::MISSION, "DataObserver"); +} + +MissionObserver::~MissionObserver() +{ + TAG_LOGI(AAFwkTag::MISSION, "~DataObserver"); +} + +bool MissionObserver::AddCallback(JsOnCallbackType cb) +{ + std::lock_guard lock(mutex_); + for (auto &item : callbackList_) { + if (item == cb) { + TAG_LOGI(AAFwkTag::MISSION, "AddCallback duplicated"); + return false; + } + } + callbackList_.push_back(cb); + return true; +} + +void MissionObserver::DeleteCallback(::taihe::optional_view optCallback) +{ + std::lock_guard lock(mutex_); + if (!optCallback.has_value()) { + callbackList_.clear(); + TAG_LOGI(AAFwkTag::MISSION, "DeleteCallback, clear"); + return; + } + auto paramCallback = optCallback.value(); + for (auto iter = callbackList_.begin(); iter != callbackList_.end();) { + if (paramCallback == *iter) { + iter = callbackList_.erase(iter); + TAG_LOGI(AAFwkTag::MISSION, "DeleteCallback, remove item"); + } else { + ++iter; + } + } +} + +bool MissionObserver::IsCallbackListEmpty() +{ + std::lock_guard lock(mutex_); + return callbackList_.size() == 0; +} + +void MissionObserver::OnCallback(const uint32_t continueState, const std::string &srcDeviceId, + const std::string &bundleName, const std::string &continueType, + const std::string &srcBundleName) +{ + TAG_LOGI(AAFwkTag::MISSION, "MissionObserver::OnCallback"); + auto taiheState = ohos::distributedmissionmanager::ContinueState::from_value(continueState); + ::ContinuableInfo::ContinuableInfo taiheInfo = {}; + taiheInfo.srcDeviceId = srcDeviceId; + taiheInfo.bundleName = bundleName; + taiheInfo.srcBundleName = ::taihe::optional<::taihe::string>::make(srcBundleName); + taiheInfo.continueType = ::taihe::optional<::taihe::string>::make(continueType); + ::ohos::distributedmissionmanager::ContinueCallbackInfo callbackInfo = { .state = taiheState, .info = taiheInfo }; + + wptr weakthis = this; + SendEventToMainThread([callbackInfo, weakthis] { + auto sptrthis = weakthis.promote(); + if (sptrthis != nullptr) { + sptrthis->OnCallbackInMainThread(callbackInfo); + } + }); +} + +void MissionObserver::OnCallbackInMainThread(const ::ohos::distributedmissionmanager::ContinueCallbackInfo& info) +{ + TAG_LOGI(AAFwkTag::MISSION, "MissionObserver::OnCallbackInMainThread"); + std::vector callbackListTemp; + { + std::lock_guard lock(mutex_); + callbackListTemp = callbackList_; + } + for (auto iter = callbackListTemp.begin(); iter != callbackListTemp.end();) { + auto &jsfunc = *iter; + jsfunc(info); + } +} + +} // namespace ani_observerutils \ No newline at end of file diff --git a/frameworks/ets/taihe/distributedmissionmanager/src/ani_remotelistener_utils.cpp b/frameworks/ets/taihe/distributedmissionmanager/src/ani_remotelistener_utils.cpp new file mode 100644 index 0000000000..f5b6ff2a3f --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/src/ani_remotelistener_utils.cpp @@ -0,0 +1,237 @@ +/* + * 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 "ani_remotelistener_utils.h" +#include "ani_error_utils.h" +#include "ani_utils.h" +#include +#include + +#include "hilog_tag_wrapper.h" + +namespace ani_remotelistenerutils { + +static std::shared_ptr mainHandler_; +static std::once_flag g_handlerOnceFlag; + +AniRemoteMissionListener::AniRemoteMissionListener(const ::MissionCallbacks::MissionCallback &ref) + :callbacks_(ref) +{ + TAG_LOGI(AAFwkTag::MISSION, "AniRemoteMissionListener constructor"); +} + +AniRemoteMissionListener::~AniRemoteMissionListener() +{ + TAG_LOGI(AAFwkTag::MISSION, "~AniRemoteMissionListener"); +} + +void AniRemoteMissionListener::SetCallbacks(const ::MissionCallbacks::MissionCallback &ref) +{ + callbacks_ = ref; +} + +void AniRemoteMissionListener::NotifyMissionsChanged(const std::string &deviceId) +{ + TAG_LOGI(AAFwkTag::MISSION, "NotifyMissionsChanged"); + wptr weakthis = this; + SendEventToMainThread([copyId = deviceId, weakthis] { + auto sptrthis = weakthis.promote(); + if (sptrthis != nullptr) { + sptrthis->NotifyMissionsChangedInMainThread(copyId); + } + }); +} + +void AniRemoteMissionListener::NotifySnapshot(const std::string &deviceId, int32_t missionId) +{ + TAG_LOGI(AAFwkTag::MISSION, "NotifySnapshot"); + wptr weakthis = this; + SendEventToMainThread([copyId = deviceId, missionId, weakthis] { + auto sptrthis = weakthis.promote(); + if (sptrthis != nullptr) { + sptrthis->NotifySnapshotInMainThread(copyId, missionId); + } + }); +} + +void AniRemoteMissionListener::NotifyNetDisconnect(const std::string &deviceId, int32_t state) +{ + TAG_LOGI(AAFwkTag::MISSION, "NotifyNetDisconnect"); + wptr weakthis = this; + SendEventToMainThread([copyId = deviceId, state, weakthis] { + auto sptrthis = weakthis.promote(); + if (sptrthis != nullptr) { + sptrthis->NotifyNetDisconnectInMainThread(copyId, state); + } + }); +} + +void AniRemoteMissionListener::NotifyMissionsChangedInMainThread(const std::string &deviceId) +{ + TAG_LOGI(AAFwkTag::MISSION, "NotifyMissionsChangedInMainThread"); + std::lock_guard lock(mutex_); + if (released_) { + return; + } + ::taihe::string taiheDeviceId(deviceId); + callbacks_.notifyMissionsChanged(taiheDeviceId); +} + +void AniRemoteMissionListener::NotifySnapshotInMainThread(const std::string &deviceId, int32_t missionId) +{ + TAG_LOGI(AAFwkTag::MISSION, "NotifySnapshotInMainThread"); + std::lock_guard lock(mutex_); + if (released_) { + return; + } + ::taihe::string taiheDeviceId(deviceId); + callbacks_.notifySnapshot(taiheDeviceId, missionId); +} + +void AniRemoteMissionListener::NotifyNetDisconnectInMainThread(const std::string &deviceId, int32_t state) +{ + TAG_LOGI(AAFwkTag::MISSION, "NotifyNetDisconnectInMainThread"); + std::lock_guard lock(mutex_); + if (released_) { + return; + } + ::taihe::string taiheDeviceId(deviceId); + callbacks_.notifyNetDisconnect(taiheDeviceId, state); +} + +bool AniRemoteMissionListener::SendEventToMainThread(const std::function func) +{ + if (func == nullptr) { + return false; + } + std::call_once(g_handlerOnceFlag, [] { + auto runner = OHOS::AppExecFwk::EventRunner::GetMainEventRunner(); + if (runner) { + mainHandler_ = std::make_shared(runner); + } + }); + if (!mainHandler_) { + TAG_LOGI(AAFwkTag::MISSION, "Failed to initialize event handler"); + return false; + } + mainHandler_->PostTask(func, "", 0, OHOS::AppExecFwk::EventQueue::Priority::IMMEDIATE, {}); + return true; +} + +void AniRemoteMissionListener::Release() +{ + std::lock_guard lock(mutex_); + released_ = true; +} + +AniMissionContinue::AniMissionContinue(::taihe::callback const& callback) + :callbackByMissionInfo_(callback) +{ + TAG_LOGI(AAFwkTag::MISSION, "AniMissionContinue constructor"); +} + +AniMissionContinue::AniMissionContinue(::ContinueCallback::ContinueCallback const& callback) + :callbackByDeviceInfo_(callback) +{ + TAG_LOGI(AAFwkTag::MISSION, "AniMissionContinue constructor"); +} + +AniMissionContinue::AniMissionContinue(ani_env *env, ani_resolver deferred) +{ + deferred_ = deferred; + env->GetVM(&vm_); +} + +AniMissionContinue::~AniMissionContinue() +{ + TAG_LOGI(AAFwkTag::MISSION, "~AniMissionContinue"); +} + +bool AniMissionContinue::SendEventToMainThread(const std::function func) +{ + if (func == nullptr) { + return false; + } + std::call_once(g_handlerOnceFlag, [] { + auto runner = OHOS::AppExecFwk::EventRunner::GetMainEventRunner(); + if (runner) { + mainHandler_ = std::make_shared(runner); + } + }); + if (!mainHandler_) { + TAG_LOGI(AAFwkTag::MISSION, "Failed to initialize event handler"); + return false; + } + mainHandler_->PostTask(func, "", 0, OHOS::AppExecFwk::EventQueue::Priority::IMMEDIATE, {}); + return true; +} + +void AniMissionContinue::OnContinueDone(int32_t result) +{ + TAG_LOGI(AAFwkTag::MISSION, "AniMissionContinue::OnContinueDone result %{public}d", result); + if (deferred_ != nullptr) { + if (vm_ == nullptr) { + TAG_LOGI(AAFwkTag::MISSION, "OnContinueDone null env or vm"); + return; + } + ani_utils::AniExecuteFunc(vm_, [this, result] (ani_env* currentEnv) { + this->PromiseResult(currentEnv, result); + }); + } else { + wptr weakThis = this; + SendEventToMainThread([weakThis, result] { + auto sptr = weakThis.promote(); + if (sptr) { + sptr->OnContinueDoneInMainThread(result); + } + }); + } +} + +void AniMissionContinue::OnContinueDoneInMainThread(int32_t result) +{ + TAG_LOGI(AAFwkTag::MISSION, "AniMissionContinue::OnContinueDoneInMainThread"); + ani_env *env = taihe::get_env(); + if (env == nullptr) { + return; + } + int32_t errCode = ani_errorutils::ErrorCodeReturn(result); + std::string errMessage = ani_errorutils::ErrorMessageReturn(result); + if (callbackByDeviceInfo_.has_value()) { + callbackByDeviceInfo_.value().onContinueDone(errCode); + } else if (callbackByMissionInfo_.has_value()) { + if (result == 0) { + ani_ref undefined = nullptr; + env->GetUndefined(&undefined); + callbackByMissionInfo_.value()(reinterpret_cast(undefined)); + } else { + ani_ref errobj = ani_errorutils::ToBusinessError(env, errCode, errMessage); + callbackByMissionInfo_.value()(reinterpret_cast(errobj)); + } + } +} + +void AniMissionContinue::PromiseResult(ani_env* currentEnv, int32_t result) +{ + TAG_LOGI(AAFwkTag::MISSION, "PromiseResult"); + if (currentEnv == nullptr) { + return; + } + if (deferred_) { + ani_errorutils::AniPromiseCallback(currentEnv, deferred_, result); + deferred_ = nullptr; + } +} + +} // namespace ani_observerutils \ No newline at end of file diff --git a/frameworks/ets/taihe/distributedmissionmanager/src/ani_utils.cpp b/frameworks/ets/taihe/distributedmissionmanager/src/ani_utils.cpp new file mode 100644 index 0000000000..ce3bdca11b --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/src/ani_utils.cpp @@ -0,0 +1,74 @@ +/* + * 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. + */ +#define LOG_TAG "AniUtils" +#include "ani_utils.h" +#include "hilog_tag_wrapper.h" + +namespace ani_utils { + +ani_status AniCreateInt(ani_env* env, int32_t value, ani_object& result) +{ + ani_status state; + ani_class intClass; + if ((state = env->FindClass("std.core.Int", &intClass)) != ANI_OK) { + TAG_LOGE(AAFwkTag::MISSION, "FindClass std/core/Int failed, %{public}d", state); + return state; + } + ani_method intClassCtor; + if ((state = env->Class_FindMethod(intClass, "", "i:", &intClassCtor)) != ANI_OK) { + TAG_LOGE(AAFwkTag::MISSION, "Class_FindMethod Int ctor failed, %{public}d", state); + return state; + } + ani_int aniValue = value; + if ((state = env->Object_New(intClass, intClassCtor, &result, aniValue)) != ANI_OK) { + TAG_LOGE(AAFwkTag::MISSION, "New Int object failed, %{public}d", state); + } + if (state != ANI_OK) { + result = nullptr; + } + return state; +} + +void AniExecuteFunc(ani_vm* vm, const std::function func) +{ + TAG_LOGI(AAFwkTag::MISSION, "AniExecutePromise"); + if (vm == nullptr) { + TAG_LOGE(AAFwkTag::MISSION, "AniExecutePromise, vm error"); + return; + } + ani_env *currentEnv = nullptr; + ani_status aniResult = vm->GetEnv(ANI_VERSION_1, ¤tEnv); + if (ANI_OK == aniResult && currentEnv != nullptr) { + TAG_LOGI(AAFwkTag::MISSION, "AniExecutePromise, env exist"); + func(currentEnv); + return; + } + + ani_env* newEnv = nullptr; + ani_options aniArgs { 0, nullptr }; + aniResult = vm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &newEnv); + if (ANI_OK != aniResult || newEnv == nullptr) { + TAG_LOGE(AAFwkTag::MISSION, "AniExecutePromise, AttachCurrentThread error"); + return; + } + func(newEnv); + aniResult = vm->DetachCurrentThread(); + if (ANI_OK != aniResult) { + TAG_LOGE(AAFwkTag::MISSION, "AniExecutePromise, DetachCurrentThread error"); + return; + } +} + +} //namespace ani_utils \ No newline at end of file diff --git a/frameworks/ets/taihe/distributedmissionmanager/src/ohos.distributedmissionmanager.impl.cpp b/frameworks/ets/taihe/distributedmissionmanager/src/ohos.distributedmissionmanager.impl.cpp new file mode 100644 index 0000000000..9f14767026 --- /dev/null +++ b/frameworks/ets/taihe/distributedmissionmanager/src/ohos.distributedmissionmanager.impl.cpp @@ -0,0 +1,320 @@ +/* + * 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 + +#include "ohos.distributedmissionmanager.proj.hpp" +#include "ohos.distributedmissionmanager.impl.hpp" +#include "taihe/runtime.hpp" +#include "ability_manager_client.h" +#include "ani_common_want.h" +#include "ani_error_utils.h" +#include "ani_observer_utils.h" +#include "ani_remotelistener_utils.h" +#include "dms_continueInfo.h" +#include "dms_sa_client.h" +#include "hilog_tag_wrapper.h" +#include "mission_continue_interface.h" + +namespace { +using namespace OHOS; +using namespace OHOS::AAFwk; +using namespace OHOS::AppExecFwk; + +constexpr size_t VALUE_BUFFER_SIZE = 128; +constexpr const char* ON_CONTINUTESTATE_CHANGE = "continueStateChange"; + +std::mutex registrationLock_; +std::map> registrationMap_; + +std::recursive_mutex onLock_; +std::map> registrationOfOnMap_; + +void OnContinueStateChange(ani_observerutils::JsOnCallbackViewType callback) +{ + std::lock_guard lock(onLock_); + sptr registrationOfOnItem; + auto item = registrationOfOnMap_.find(ON_CONTINUTESTATE_CHANGE); + if (item != registrationOfOnMap_.end()) { + registrationOfOnItem = registrationOfOnMap_[ON_CONTINUTESTATE_CHANGE]; + } else { + registrationOfOnItem = new (std::nothrow) ani_observerutils::MissionObserver(); + } + bool addRet = registrationOfOnItem->AddCallback(callback); + if (!addRet) { + return; + } + + int32_t result = DmsSaClient::GetInstance().AddListener(ON_CONTINUTESTATE_CHANGE, registrationOfOnItem); + if (result == OHOS::AAFwk::NO_ERROR) { + TAG_LOGI(AAFwkTag::MISSION, "DmsSaClient AddListener success"); + registrationOfOnMap_[ON_CONTINUTESTATE_CHANGE] = registrationOfOnItem; + } else { + TAG_LOGE(AAFwkTag::MISSION, "DmsSaClient AddListener failed, %{public}d", result); + int32_t errCode = ani_errorutils::ErrorCodeReturn(result); + std::string errInfo = ani_errorutils::ErrorMessageReturn(errCode); + ani_errorutils::ThrowError(errCode, errInfo.c_str()); + } +} + +void OffContinueStateChange(::taihe::optional_view callbackOpt) +{ + std::lock_guard autoLock(onLock_); + sptr registrationOfOnItem; + auto item = registrationOfOnMap_.find(ON_CONTINUTESTATE_CHANGE); + if (item != registrationOfOnMap_.end()) { + registrationOfOnItem = registrationOfOnMap_[ON_CONTINUTESTATE_CHANGE]; + } else { + TAG_LOGI(AAFwkTag::MISSION, "ON_CONTINUTESTATE_CHANGE callback empty"); + return; + } + registrationOfOnItem->DeleteCallback(callbackOpt); + + if (!registrationOfOnItem->IsCallbackListEmpty()) { + TAG_LOGI(AAFwkTag::MISSION, "callback not empty, return"); + return; + } + int32_t result = DmsSaClient::GetInstance().DelListener(ON_CONTINUTESTATE_CHANGE, registrationOfOnItem); + if (result == OHOS::AAFwk::NO_ERROR) { + TAG_LOGI(AAFwkTag::MISSION, "DmsSaClient DelListener success"); + registrationOfOnMap_.erase(ON_CONTINUTESTATE_CHANGE); + } else { + TAG_LOGE(AAFwkTag::MISSION, "DmsSaClient DelListener failed, %{public}d", result); + int32_t errCode = ani_errorutils::ErrorCodeReturn(result); + std::string errInfo = ani_errorutils::ErrorMessageReturn(errCode); + ani_errorutils::ThrowError(errCode, errInfo.c_str()); + } +} + +bool CheckDeviceIdValid(std::string deviceId) +{ + if (deviceId.length() > VALUE_BUFFER_SIZE) { + TAG_LOGE(AAFwkTag::MISSION, "deviceId length not correct"); + std::string errInfo = "Parameter error. The length of \"deviceId\" must be less than " + + std::to_string(VALUE_BUFFER_SIZE); + ani_errorutils::ThrowError(ErrorCode::PARAMETER_CHECK_FAILED, errInfo.c_str()); + return false; + } + return true; +} + +void StartSyncRemoteMissionsSync(::MissionParameter::MissionParameter const& parameter) +{ + std::string deviceId(parameter.deviceId); + if (!CheckDeviceIdValid(deviceId)) { + return; + } + + int32_t result = AbilityManagerClient::GetInstance()->StartSyncRemoteMissions(deviceId, + parameter.fixConflict, parameter.tag); + if (result != 0) { + TAG_LOGE(AAFwkTag::MISSION, "StartSyncRemoteMissions failed, %{public}d", result); + int32_t errCode = ani_errorutils::ErrorCodeReturn(result); + std::string errInfo = ani_errorutils::ErrorMessageReturn(errCode); + ani_errorutils::ThrowError(errCode, errInfo.c_str()); + } +} + +void StopSyncRemoteMissionsSync(::MissionDeviceInfo::MissionDeviceInfo const& parameter) +{ + std::string deviceId(parameter.deviceId); + if (!CheckDeviceIdValid(deviceId)) { + return; + } + + int32_t result = AbilityManagerClient::GetInstance()->StopSyncRemoteMissions(deviceId); + if (result != 0) { + TAG_LOGE(AAFwkTag::MISSION, "StopSyncRemoteMissions failed, %{public}d", result); + int32_t errCode = ani_errorutils::ErrorCodeReturn(result); + std::string errInfo = ani_errorutils::ErrorMessageReturn(errCode); + ani_errorutils::ThrowError(errCode, errInfo.c_str()); + } +} + +void RegisterMissionListenerSync(::MissionDeviceInfo::MissionDeviceInfo const& parameter, + ::MissionCallbacks::MissionCallback const& options) +{ + std::string deviceId(parameter.deviceId); + if (!CheckDeviceIdValid(deviceId)) { + return; + } + std::lock_guard autoLock(registrationLock_); + sptr registration; + auto item = registrationMap_.find(deviceId); + if (item != registrationMap_.end()) { + TAG_LOGI(AAFwkTag::MISSION, "registration exits"); + registration = registrationMap_[deviceId]; + registration->SetCallbacks(options); + } else { + TAG_LOGI(AAFwkTag::MISSION, "registration not exits"); + registration = new (std::nothrow) ani_remotelistenerutils::AniRemoteMissionListener(options); + } + if (registration == nullptr) { + TAG_LOGE(AAFwkTag::MISSION, "null missionRegistration"); + int32_t errCode = ani_errorutils::ErrorCodeReturn(-1); + std::string errInfo = ani_errorutils::ErrorMessageReturn(errCode); + ani_errorutils::ThrowError(errCode, errInfo.c_str()); + return; + } + + int32_t result = AbilityManagerClient::GetInstance()->RegisterMissionListener(deviceId, registration); + if (result == OHOS::AAFwk::NO_ERROR) { + TAG_LOGI(AAFwkTag::MISSION, "AbilityManagerClient RegisterMissionListener success"); + registrationMap_[deviceId] = registration; + } else { + TAG_LOGE(AAFwkTag::MISSION, "AbilityManagerClient RegisterMissionListener failed, %{public}d", result); + int32_t errCode = ani_errorutils::ErrorCodeReturn(result); + std::string errInfo = ani_errorutils::ErrorMessageReturn(errCode); + ani_errorutils::ThrowError(errCode, errInfo.c_str()); + } +} + +void UnRegisterMissionListenerSync(::MissionDeviceInfo::MissionDeviceInfo const& parameter) +{ + std::string deviceId(parameter.deviceId); + if (!CheckDeviceIdValid(deviceId)) { + return; + } + + std::lock_guard autoLock(registrationLock_); + sptr registration; + auto item = registrationMap_.find(deviceId); + if (item != registrationMap_.end()) { + TAG_LOGI(AAFwkTag::MISSION, "registration exits"); + registration = registrationMap_[deviceId]; + } else { + TAG_LOGI(AAFwkTag::MISSION, "registration not exits"); + int32_t errCode = ani_errorutils::ErrorCodeReturn(INVALID_PARAMETERS_ERR); + std::string errInfo = ani_errorutils::ErrorMessageReturn(errCode); + ani_errorutils::ThrowError(errCode, errInfo.c_str()); + return; + } + int32_t result = AbilityManagerClient::GetInstance()->UnRegisterMissionListener(deviceId, registration); + if (result == OHOS::AAFwk::NO_ERROR) { + TAG_LOGI(AAFwkTag::MISSION, "AbilityManagerClient UnRegisterMissionListener success"); + registration->Release(); + registrationMap_.erase(deviceId); + } else { + TAG_LOGE(AAFwkTag::MISSION, "AbilityManagerClient UnRegisterMissionListener failed, %{public}d", result); + int32_t errCode = ani_errorutils::ErrorCodeReturn(result); + std::string errInfo = ani_errorutils::ErrorMessageReturn(errCode); + ani_errorutils::ThrowError(errCode, errInfo.c_str()); + } +} + +OHOS::AAFwk::ContinueMissionInfo ParseContinueMissionInfoFromTaihe(ani_env* env, + ::ContinueMissionInfo::ContinueMissionInfo const& parameter) +{ + TAG_LOGI(AAFwkTag::MISSION, "ParseContinueMissionInfoFromTaihe"); + OHOS::AAFwk::ContinueMissionInfo continueMissionInfo; + continueMissionInfo.dstDeviceId = std::string(parameter.dstDeviceId); + continueMissionInfo.srcDeviceId = std::string(parameter.srcDeviceId); + continueMissionInfo.bundleName = std::string(parameter.bundleName); + if (parameter.srcBundleName.has_value()) { + continueMissionInfo.srcBundleName = std::string(parameter.srcBundleName.value()); + } + if (parameter.continueType.has_value()) { + continueMissionInfo.continueType = std::string(parameter.continueType.value()); + } + UnwrapWantParams(env, reinterpret_cast(parameter.wantParam), continueMissionInfo.wantParams); + continueMissionInfo.wantParams.DumpInfo(0); + return continueMissionInfo; +} + +void ContinueMissionWithMissionInfoCallback(::ContinueMissionInfo::ContinueMissionInfo const& parameter, + ::taihe::callback_view callback) +{ + TAG_LOGI(AAFwkTag::MISSION, "ContinueMissionWithMissionInfoCallbackSync"); + ani_env *env = taihe::get_env(); + if (env == nullptr) { + ani_errorutils::ThrowError(SYSTEM_WORK_ABNORMALLY, "ani env is null"); + return; + } + OHOS::AAFwk::ContinueMissionInfo continueMissionInfo = ParseContinueMissionInfoFromTaihe(env, parameter); + auto continuation = sptr::MakeSptr(callback); + + int32_t result = AAFwk::AbilityManagerClient::GetInstance()->ContinueMission(continueMissionInfo, continuation); + TAG_LOGI(AAFwkTag::MISSION, "AbilityManagerClient ContinueMission return %{public}d", result); + if (result != OHOS::AAFwk::NO_ERROR) { + continuation->OnContinueDone(result); + } +} + +uintptr_t ContinueMissionWithMissionInfoPromise(::ContinueMissionInfo::ContinueMissionInfo const& parameter) +{ + TAG_LOGI(AAFwkTag::MISSION, "ContinueMissionWithMissionInfoPromiseSync"); + ani_env *env = taihe::get_env(); + if (env == nullptr) { + ani_errorutils::ThrowError(SYSTEM_WORK_ABNORMALLY, "ani env is null"); + return 0; + } + ani_status status = ANI_OK; + ani_object promise = nullptr; + ani_resolver deferred = nullptr; + if ((status = env->Promise_New(&deferred, &promise)) != ANI_OK) { + TAG_LOGI(AAFwkTag::MISSION, "create promise object failed, status = %{public}d", status); + ani_errorutils::ThrowError(SYSTEM_WORK_ABNORMALLY, "new promise failed"); + return 0; + } + OHOS::AAFwk::ContinueMissionInfo continueMissionInfo = ParseContinueMissionInfoFromTaihe(env, parameter); + auto continuation = sptr::MakeSptr(env, deferred); + int32_t result = AAFwk::AbilityManagerClient::GetInstance()->ContinueMission(continueMissionInfo, continuation); + TAG_LOGI(AAFwkTag::MISSION, "AbilityManagerClient ContinueMission return %{public}d", result); + if (result != OHOS::AAFwk::NO_ERROR) { + continuation->OnContinueDone(result); + } + return reinterpret_cast(promise); +} + +void ContinueMissionWithDeviceInfoSync(::ContinueDeviceInfo::ContinueDeviceInfo const& parameter, + ::ContinueCallback::ContinueCallback const& options) +{ + TAG_LOGI(AAFwkTag::MISSION, "ContinueMissionWithDeviceInfoSync"); + ani_env *env = taihe::get_env(); + if (env == nullptr) { + ani_errorutils::ThrowError(SYSTEM_WORK_ABNORMALLY, "ani env is null"); + return; + } + AAFwk::WantParams wantParams; + OHOS::AAFwk::ContinueMissionInfo continueMissionInfo; + continueMissionInfo.dstDeviceId = std::string(parameter.dstDeviceId); + continueMissionInfo.srcDeviceId = std::string(parameter.srcDeviceId); + UnwrapWantParams(env, reinterpret_cast(parameter.wantParam), continueMissionInfo.wantParams); + + auto continuation = sptr::MakeSptr(options); + int32_t result = AAFwk::AbilityManagerClient::GetInstance()->ContinueMission( + continueMissionInfo.srcDeviceId, continueMissionInfo.dstDeviceId, + parameter.missionId, continuation, continueMissionInfo.wantParams); + TAG_LOGI(AAFwkTag::MISSION, "AbilityManagerClient ContinueMission return %{public}d", result); + if (result != OHOS::AAFwk::NO_ERROR) { + int32_t errCode = ani_errorutils::ErrorCodeReturn(result); + std::string errInfo = ani_errorutils::ErrorMessageReturn(errCode); + ani_errorutils::ThrowError(errCode, errInfo.c_str()); + } +} + +} // namespace + +// Since these macros are auto-generate, lint will cause false positive. +// NOLINTBEGIN +TH_EXPORT_CPP_API_OnContinueStateChange(OnContinueStateChange); +TH_EXPORT_CPP_API_OffContinueStateChange(OffContinueStateChange); +TH_EXPORT_CPP_API_StartSyncRemoteMissionsSync(StartSyncRemoteMissionsSync); +TH_EXPORT_CPP_API_StopSyncRemoteMissionsSync(StopSyncRemoteMissionsSync); +TH_EXPORT_CPP_API_RegisterMissionListenerSync(RegisterMissionListenerSync); +TH_EXPORT_CPP_API_UnRegisterMissionListenerSync(UnRegisterMissionListenerSync); +TH_EXPORT_CPP_API_ContinueMissionWithMissionInfoCallback(ContinueMissionWithMissionInfoCallback); +TH_EXPORT_CPP_API_ContinueMissionWithMissionInfoPromise(ContinueMissionWithMissionInfoPromise); +TH_EXPORT_CPP_API_ContinueMissionWithDeviceInfoSync(ContinueMissionWithDeviceInfoSync); +// NOLINTEND diff --git a/frameworks/native/ability/native/ui_ability.cpp b/frameworks/native/ability/native/ui_ability.cpp index 9c3fc3a0fb..d90fa14a80 100644 --- a/frameworks/native/ability/native/ui_ability.cpp +++ b/frameworks/native/ability/native/ui_ability.cpp @@ -575,6 +575,13 @@ int32_t UIAbility::OnContinueAsyncCB(napi_ref jsWantParams, int32_t status, return ERR_OK; } +int32_t UIAbility::OnContinueAsyncCB(ani_ref aniWantParamsRef, int32_t status, + const AppExecFwk::AbilityInfo &abilityInfo) +{ + TAG_LOGD(AAFwkTag::UIABILITY, "called"); + return ERR_OK; +} + int32_t UIAbility::OnContinue(AAFwk::WantParams &wantParams, bool &isAsyncOnContinue, const AppExecFwk::AbilityInfo &abilityInfo) { diff --git a/interfaces/kits/native/ability/native/ability_transaction_callback_info.h b/interfaces/kits/native/ability/native/ability_transaction_callback_info.h index 13719a287c..4978a7e22b 100644 --- a/interfaces/kits/native/ability/native/ability_transaction_callback_info.h +++ b/interfaces/kits/native/ability/native/ability_transaction_callback_info.h @@ -39,8 +39,9 @@ public: return new(std::nothrow) AbilityTransactionCallbackInfo(); } - static void Destroy(AbilityTransactionCallbackInfo *callbackInfo) + static void Destroy(AbilityTransactionCallbackInfo *callbackInfo, void* data = nullptr) { + callbackInfo->Finalize(data); delete callbackInfo; } @@ -49,6 +50,19 @@ public: callbackStack_.push(callback); } + void SetFinalizeCallback(const std::function &finalize) + { + finalizeCallback_ = finalize; + } + + void Finalize(void* data) + { + if (finalizeCallback_ != nullptr) { + finalizeCallback_(data); + finalizeCallback_ = nullptr; + } + } + void Call(T &callbackResult) { while (!callbackStack_.empty()) { @@ -65,6 +79,7 @@ public: private: std::stack callbackStack_ {}; + std::function finalizeCallback_ {}; }; template<> @@ -80,7 +95,7 @@ public: return new(std::nothrow) AbilityTransactionCallbackInfo(); } - static void Destroy(AbilityTransactionCallbackInfo *callbackInfo) + static void Destroy(AbilityTransactionCallbackInfo *callbackInfo, [[maybe_unused]]void* data = nullptr) { delete callbackInfo; } diff --git a/interfaces/kits/native/ability/native/ui_ability.h b/interfaces/kits/native/ability/native/ui_ability.h index e27988ee7b..150e4501c6 100644 --- a/interfaces/kits/native/ability/native/ui_ability.h +++ b/interfaces/kits/native/ability/native/ui_ability.h @@ -290,6 +290,9 @@ public: virtual int32_t OnContinueAsyncCB(napi_ref jsWantParams, int32_t status, const AppExecFwk::AbilityInfo &abilityInfo); + virtual int32_t OnContinueAsyncCB(ani_ref aniWantParamsRef, int32_t status, + const AppExecFwk::AbilityInfo &abilityInfo); + /** * @brief Prepare user data of local Ability. * @param wantParams Indicates the user data to be saved.