diff --git a/test/moduletest/BUILD.gn b/test/moduletest/BUILD.gn
index d50ce1f10679051219f0a1b61b698fdf92c42a4a..bc24f05dd45143db6d6eb0018ab82dc491925034 100644
--- a/test/moduletest/BUILD.gn
+++ b/test/moduletest/BUILD.gn
@@ -64,6 +64,7 @@ group("moduletest") {
"quick_fix:moduletest",
"running_infos_module_test:moduletest",
"start_option_display_id_test:moduletest",
+ "ui_extension_ability_test:moduletest",
"//third_party/icu/icu4c:shared_icuuc",
"//third_party/jsoncpp:jsoncpp",
]
diff --git a/test/moduletest/ui_extension_ability_test/BUILD.gn b/test/moduletest/ui_extension_ability_test/BUILD.gn
new file mode 100644
index 0000000000000000000000000000000000000000..625a69c20ebddaa16fd600a0cbb05090874a1efe
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/BUILD.gn
@@ -0,0 +1,22 @@
+# Copyright (c) 2023 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.
+
+group("moduletest") {
+ testonly = true
+
+ deps = [
+ "ui_extension_connect_module_test:moduletest",
+ "ui_extension_provider_bundle:assisthap",
+ "ui_extension_user_bundle:assisthap",
+ ]
+}
diff --git a/test/moduletest/ui_extension_ability_test/ohos_test/BUILD.gn b/test/moduletest/ui_extension_ability_test/ohos_test/BUILD.gn
new file mode 100644
index 0000000000000000000000000000000000000000..7b7ae726679736bd64ab35e5fd9763997a31865a
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ohos_test/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright (c) 2023 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/ohos.gni")
+
+ohos_copy("copy_ohos_test") {
+ subsystem_name = "ability"
+ part_name = "ability_runtime"
+ sources = [ "./ohos_test.xml" ]
+ outputs = [ "$root_out_dir/tests/moduletest/ability_runtime/ui_extension/resource/ohos_test.xml" ]
+}
diff --git a/test/moduletest/ui_extension_ability_test/ohos_test/ohos_test.xml b/test/moduletest/ui_extension_ability_test/ohos_test/ohos_test.xml
new file mode 100644
index 0000000000000000000000000000000000000000..80067a7d98c0ca142bf96a304fa8e5f1b70892ce
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ohos_test/ohos_test.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/BUILD.gn b/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/BUILD.gn
new file mode 100644
index 0000000000000000000000000000000000000000..8c06a8e40be442744ba2bfdfc4ed47cd711c63ab
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/BUILD.gn
@@ -0,0 +1,63 @@
+# Copyright (c) 2023 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/ohos.gni")
+import("//build/test.gni")
+import("//foundation/ability/ability_runtime/ability_runtime.gni")
+
+ohos_moduletest("ui_extension_connect_module_test") {
+ module_out_path = "ability_runtime/ui_extension"
+
+ sources = [
+ "ui_extension_connect_module_test.cpp",
+ "ui_extension_connect_module_test_connection.cpp",
+ "ui_extension_connect_module_test_observer.cpp",
+ ]
+
+ configs = [ "${ability_runtime_services_path}/common:common_config" ]
+
+ cflags = []
+
+ if (target_cpu == "arm") {
+ cflags += [ "-DBINDER_IPC_32BIT" ]
+ }
+
+ deps = [
+ "${ability_runtime_path}/test/moduletest/ui_extension_ability_test/ohos_test:copy_ohos_test",
+ "//third_party/googletest:gmock_main",
+ "//third_party/googletest:gtest_main",
+ ]
+
+ external_deps = [
+ "ability_base:session_info",
+ "ability_base:want",
+ "ability_runtime:ability_manager",
+ "ability_runtime:app_manager",
+ "access_token:libaccesstoken_sdk",
+ "access_token:libnativetoken",
+ "access_token:libtoken_setproc",
+ "bundle_framework:appexecfwk_base",
+ "bundle_framework:appexecfwk_core",
+ "c_utils:utils",
+ "ffrt:libffrt",
+ "hilog:libhilog",
+ "ipc:ipc_core",
+ "safwk:system_ability_fwk",
+ "samgr:samgr_proxy",
+ ]
+}
+
+group("moduletest") {
+ testonly = true
+ deps = [ ":ui_extension_connect_module_test" ]
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/ui_extension_connect_module_test.cpp b/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/ui_extension_connect_module_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8e635c976adaf12d834558599d4c87a16d251e98
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/ui_extension_connect_module_test.cpp
@@ -0,0 +1,646 @@
+/*
+ * Copyright (c) 2023 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
+#include
+
+#include "ability_manager_client.h"
+#include "ability_util.h"
+#include "accesstoken_kit.h"
+#include "app_mgr_interface.h"
+#include "hilog_wrapper.h"
+#include "nativetoken_kit.h"
+#include "if_system_ability_manager.h"
+#include "iservice_registry.h"
+#include "session_info.h"
+#include "system_ability_definition.h"
+#include "token_setproc.h"
+#include "ui_extension_connect_module_test_connection.h"
+#include "ui_extension_connect_module_test_observer.h"
+#include "want.h"
+
+using namespace testing;
+using namespace testing::ext;
+
+namespace OHOS {
+namespace AAFwk {
+namespace {
+const int CONNECT_TIMEOUT_MS = 5 * 1000;
+const int32_t MAIN_USER_ID = 100;
+
+const std::string TARGET_BUNDLE_NAME = "com.ohos.uiextensionprovider";
+const std::string TARGET_ABILITY_NAME = "UIExtensionProvider";
+const std::string TARGET_MODULE_NAME = "entry";
+
+const std::string USER_BUNDLE_NAME = "com.ohos.uiextensionuser";
+const std::string USER_ABILITY_NAME = "EntryAbility";
+const std::string USER_MODULE_NAME = "entry";
+
+static void SetNativeToken()
+{
+ uint64_t tokenId;
+ const char **perms = new const char *[2];
+ perms[0] = "ohos.permission.CONNECT_UI_EXTENSION_ABILITY";
+ perms[1] = "ohos.permission.RUNNING_STATE_OBSERVER";
+ NativeTokenInfoParams infoInstance = {
+ .dcapsNum = 0,
+ .permsNum = 2,
+ .aclsNum = 0,
+ .dcaps = nullptr,
+ .perms = perms,
+ .acls = nullptr,
+ .aplStr = "system_core",
+ };
+
+ infoInstance.processName = "SetUpTestCase";
+ tokenId = GetAccessTokenId(&infoInstance);
+ SetSelfTokenID(tokenId);
+ OHOS::Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo();
+ delete[] perms;
+}
+} // namespace
+
+using IAbilityConnection = AppExecFwk::IAbilityConnection;
+using IApplicationStateObserver = AppExecFwk::IApplicationStateObserver;
+
+class UIExtensionConnectModuleTest : public testing::Test {
+public:
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+ void SetUp() override;
+ void TearDown() override;
+
+ void WaitUntilConnectDone(const sptr &connection);
+ void WaitUntilDisConnectDone(const sptr &connection);
+ void WaitUntilProcessCreated(const sptr &observer);
+ void WaitUntilProcessDied(const sptr &observer);
+ void WaitUntilAbilityForeground(const sptr &observer);
+ void WaitUntilAbilityBackground(const sptr &observer);
+
+ void RegisterApplicationStateObserver(const sptr &observer);
+ void UnregisterApplicationStateObserver(const sptr &observer);
+ static sptr appMgr_;
+};
+
+sptr UIExtensionConnectModuleTest::appMgr_ = nullptr;
+
+void UIExtensionConnectModuleTest::SetUpTestCase(void)
+{
+ auto systemAbilityMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
+ if (systemAbilityMgr == nullptr) {
+ HILOG_ERROR("Failed to get SystemAbilityManager.");
+ return;
+ }
+
+ auto remoteObj = systemAbilityMgr->GetSystemAbility(APP_MGR_SERVICE_ID);
+ if (remoteObj == nullptr) {
+ HILOG_ERROR("Remote object is nullptr.");
+ return;
+ }
+
+ sptr appMgr = iface_cast(remoteObj);
+ if (appMgr == nullptr) {
+ HILOG_ERROR("App mgr is nullptr.");
+ return;
+ }
+
+ appMgr_ = appMgr;
+}
+
+void UIExtensionConnectModuleTest::TearDownTestCase(void)
+{}
+
+void UIExtensionConnectModuleTest::SetUp()
+{}
+
+void UIExtensionConnectModuleTest::TearDown()
+{}
+
+void UIExtensionConnectModuleTest::RegisterApplicationStateObserver(const sptr &observer)
+{
+ std::vector bundleNameList;
+ bundleNameList.push_back(TARGET_BUNDLE_NAME);
+ bundleNameList.push_back(USER_BUNDLE_NAME);
+ auto ret = appMgr_->RegisterApplicationStateObserver(observer, bundleNameList);
+ if (ret != ERR_OK) {
+ HILOG_ERROR("Register failed.");
+ }
+}
+
+void UIExtensionConnectModuleTest::UnregisterApplicationStateObserver(const sptr &observer)
+{
+ auto ret = appMgr_->UnregisterApplicationStateObserver(observer);
+ if (ret != ERR_OK) {
+ HILOG_ERROR("Unregister failed.");
+ }
+}
+
+void UIExtensionConnectModuleTest::WaitUntilConnectDone(const sptr &connection)
+{
+ std::unique_lock lock(connection->connectMutex_);
+ auto waitStatus = connection->connectCondation_.wait_for(lock, std::chrono::milliseconds(CONNECT_TIMEOUT_MS),
+ [connection]() {
+ return connection->connectFinished_;
+ });
+ EXPECT_EQ(waitStatus, true);
+ EXPECT_EQ(connection->connectFinished_, true);
+}
+
+void UIExtensionConnectModuleTest::WaitUntilDisConnectDone(
+ const sptr &connection)
+{
+ std::unique_lock lock(connection->connectMutex_);
+ auto waitStatus = connection->connectCondation_.wait_for(lock, std::chrono::milliseconds(CONNECT_TIMEOUT_MS),
+ [connection]() {
+ return connection->disConnectFinished_;
+ });
+ EXPECT_EQ(waitStatus, true);
+ EXPECT_EQ(connection->disConnectFinished_, true);
+}
+
+void UIExtensionConnectModuleTest::WaitUntilProcessCreated(const sptr &observer)
+{
+ std::unique_lock lock(observer->observerMutex_);
+ auto waitStatus = observer->observerCondation_.wait_for(lock, std::chrono::milliseconds(CONNECT_TIMEOUT_MS),
+ [observer]() {
+ return observer->processCreated_;
+ });
+ EXPECT_EQ(waitStatus, true);
+ EXPECT_EQ(observer->processCreated_, true);
+}
+
+void UIExtensionConnectModuleTest::WaitUntilProcessDied(const sptr &observer)
+{
+ std::unique_lock lock(observer->observerMutex_);
+ auto waitStatus = observer->observerCondation_.wait_for(lock, std::chrono::milliseconds(CONNECT_TIMEOUT_MS),
+ [observer]() {
+ return observer->processDied_;
+ });
+ EXPECT_EQ(waitStatus, true);
+ EXPECT_EQ(observer->processDied_, true);
+}
+
+void UIExtensionConnectModuleTest::WaitUntilAbilityForeground(
+ const sptr &observer)
+{
+ std::unique_lock lock(observer->observerMutex_);
+ auto waitStatus = observer->observerCondation_.wait_for(lock, std::chrono::milliseconds(CONNECT_TIMEOUT_MS),
+ [observer]() {
+ return observer->processForegrounded_;
+ });
+ EXPECT_EQ(waitStatus, true);
+ EXPECT_EQ(observer->processForegrounded_, true);
+}
+
+void UIExtensionConnectModuleTest::WaitUntilAbilityBackground(
+ const sptr &observer)
+{
+ std::unique_lock lock(observer->observerMutex_);
+ auto waitStatus = observer->observerCondation_.wait_for(lock, std::chrono::milliseconds(CONNECT_TIMEOUT_MS),
+ [observer]() {
+ return observer->processBackgrounded_;
+ });
+ EXPECT_EQ(waitStatus, true);
+ EXPECT_EQ(observer->processBackgrounded_, true);
+}
+
+/**
+ * @tc.name: ConnectUIExtensionAbility_0100
+ * @tc.desc: basic function test.
+ * @tc.type: FUNC
+ * @tc.require: issueI5OD2E
+ */
+HWTEST_F(UIExtensionConnectModuleTest, ConnectUIExtensionAbility_0100, TestSize.Level1)
+{
+ HILOG_INFO("start.");
+
+ auto currentId = GetSelfTokenID();
+ SetNativeToken();
+
+ auto observer = sptr::MakeSptr();
+ RegisterApplicationStateObserver(observer);
+
+ Want providerWant;
+ AppExecFwk::ElementName providerElement("0", TARGET_BUNDLE_NAME, TARGET_ABILITY_NAME, TARGET_MODULE_NAME);
+ providerWant.SetElement(providerElement);
+
+ auto connection = sptr::MakeSptr();
+ ASSERT_NE(connection, nullptr);
+
+ auto sessionInfo = sptr::MakeSptr();
+ ASSERT_NE(sessionInfo, nullptr);
+
+ // Connect ui extension ability firstly.
+ auto connectInfo = sptr::MakeSptr();
+ ASSERT_NE(connectInfo, nullptr);
+ connectInfo->hostBundleName = USER_BUNDLE_NAME;
+ connectInfo->uiExtensionAbilityId = 0;
+ auto ret = AbilityManagerClient::GetInstance()->ConnectUIExtensionAbility(providerWant, connection, sessionInfo,
+ DEFAULT_INVAL_VALUE, connectInfo);
+ EXPECT_EQ(ret, ERR_OK);
+ HILOG_INFO("UIExtensonAbility id %{public}d", connectInfo->uiExtensionAbilityId);
+ EXPECT_NE(connectInfo->uiExtensionAbilityId, 0);
+
+ // Wait until OnAbilityConnectDone has triggered.
+ WaitUntilConnectDone(connection);
+
+ // Send uiextensionability id to ui extension user
+ // start ui extension user
+ Want userWant;
+ AppExecFwk::ElementName userElement("0", USER_BUNDLE_NAME, USER_ABILITY_NAME, USER_MODULE_NAME);
+ userWant.SetElement(userElement);
+ ret = AbilityManagerClient::GetInstance()->StartAbility(userWant);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until ability has foregrounded
+ WaitUntilAbilityForeground(observer);
+
+ // Disconnect ui extension ability.
+ // wish can't be destroyed, cause there exist ui extension component.
+ ret = AbilityManagerClient::GetInstance()->DisconnectAbility(connection);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until OnAbilityDisconnectDone has triggered.
+ WaitUntilDisConnectDone(connection);
+
+ // Destroy ui extension user, this testcase should executed in screen-on.
+ sptr token = nullptr;
+ ret = AbilityManagerClient::GetInstance()->GetTopAbility(token);
+ EXPECT_EQ(ret, ERR_OK);
+
+ int resultCode = 0;
+ Want resultWant;
+ ret = AbilityManagerClient::GetInstance()->TerminateAbility(token, resultCode, &resultWant);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until ability has terminate
+ WaitUntilProcessDied(observer);
+ UnregisterApplicationStateObserver(observer);
+ HILOG_INFO("finish.");
+}
+
+/**
+ * @tc.name: ConnectUIExtensionAbility_0200
+ * @tc.desc: basic function test.
+ * @tc.type: FUNC
+ * @tc.require: issueI5OD2E
+ */
+HWTEST_F(UIExtensionConnectModuleTest, ConnectUIExtensionAbility_0200, TestSize.Level1)
+{
+ HILOG_INFO("start.");
+
+ auto currentId = GetSelfTokenID();
+ SetNativeToken();
+
+ auto observer = sptr::MakeSptr();
+ RegisterApplicationStateObserver(observer);
+
+ Want providerWant;
+ AppExecFwk::ElementName providerElement("0", TARGET_BUNDLE_NAME, TARGET_ABILITY_NAME, TARGET_MODULE_NAME);
+ providerWant.SetElement(providerElement);
+
+ auto connection = sptr::MakeSptr();
+ ASSERT_NE(connection, nullptr);
+
+ auto sessionInfo = sptr::MakeSptr();
+ ASSERT_NE(sessionInfo, nullptr);
+
+ // Connect ui extension ability firstly.
+ auto connectInfo = sptr::MakeSptr();
+ ASSERT_NE(connectInfo, nullptr);
+ connectInfo->hostBundleName = USER_BUNDLE_NAME;
+ connectInfo->uiExtensionAbilityId = 0;
+ auto ret = AbilityManagerClient::GetInstance()->ConnectUIExtensionAbility(providerWant, connection, sessionInfo,
+ DEFAULT_INVAL_VALUE, connectInfo);
+ EXPECT_EQ(ret, ERR_OK);
+ HILOG_INFO("UIExtensonAbility id %{public}d", connectInfo->uiExtensionAbilityId);
+ EXPECT_NE(connectInfo->uiExtensionAbilityId, 0);
+
+ // Wait until OnAbilityConnectDone has triggered.
+ WaitUntilConnectDone(connection);
+
+ // start ui extension user
+ Want userWant;
+ AppExecFwk::ElementName userElement("0", USER_BUNDLE_NAME, USER_ABILITY_NAME, USER_MODULE_NAME);
+ userWant.SetElement(userElement);
+ ret = AbilityManagerClient::GetInstance()->StartAbility(userWant);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until ability has foregrounded
+ WaitUntilAbilityForeground(observer);
+
+ // Destroy ui extension user.
+ sptr token = nullptr;
+ ret = AbilityManagerClient::GetInstance()->GetTopAbility(token);
+ EXPECT_EQ(ret, ERR_OK);
+
+ int resultCode = 0;
+ Want resultWant;
+ ret = AbilityManagerClient::GetInstance()->TerminateAbility(token, resultCode, &resultWant);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until ability has background
+ WaitUntilAbilityBackground(observer);
+
+ // Disconnect ui extension ability.
+ ret = AbilityManagerClient::GetInstance()->DisconnectAbility(connection);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until OnAbilityDisconnectDone has triggered.
+ WaitUntilDisConnectDone(connection);
+
+ // Wait until ability has terminate
+ WaitUntilProcessDied(observer);
+
+ SetSelfTokenID(currentId);
+ UnregisterApplicationStateObserver(observer);
+ HILOG_INFO("finish.");
+}
+
+/**
+ * @tc.name: ConnectUIExtensionAbility_0300
+ * @tc.desc: basic function test.
+ * @tc.type: FUNC
+ * @tc.require: issueI5OD2E
+ */
+HWTEST_F(UIExtensionConnectModuleTest, ConnectUIExtensionAbility_0300, TestSize.Level1)
+{
+ HILOG_INFO("start.");
+
+ auto currentId = GetSelfTokenID();
+ SetNativeToken();
+
+ auto observer = sptr::MakeSptr();
+ RegisterApplicationStateObserver(observer);
+
+ // start ui extension user
+ Want userWant;
+ AppExecFwk::ElementName userElement("0", USER_BUNDLE_NAME, USER_ABILITY_NAME, USER_MODULE_NAME);
+ userWant.SetElement(userElement);
+ auto ret = AbilityManagerClient::GetInstance()->StartAbility(userWant);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until ability has foregrounded
+ WaitUntilAbilityForeground(observer);
+
+ // Destroy ui extension user.
+ sptr token = nullptr;
+ ret = AbilityManagerClient::GetInstance()->GetTopAbility(token);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Minimize ui extension user
+ ret = AbilityManagerClient::GetInstance()->MinimizeAbility(token);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until ability has background
+ WaitUntilAbilityBackground(observer);
+
+ int resultCode = 0;
+ Want resultWant;
+ ret = AbilityManagerClient::GetInstance()->TerminateAbility(token, resultCode, &resultWant);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until ability has terminate
+ WaitUntilProcessDied(observer);
+
+ SetSelfTokenID(currentId);
+ UnregisterApplicationStateObserver(observer);
+ HILOG_INFO("finish.");
+}
+
+/**
+ * @tc.name: ConnectUIExtensionAbility_0400
+ * @tc.desc: basic function test.
+ * @tc.type: FUNC
+ * @tc.require: issueI5OD2E
+ */
+HWTEST_F(UIExtensionConnectModuleTest, ConnectUIExtensionAbility_0400, TestSize.Level1)
+{
+ HILOG_INFO("start.");
+
+ auto currentId = GetSelfTokenID();
+ SetNativeToken();
+
+ auto observer = sptr::MakeSptr();
+ RegisterApplicationStateObserver(observer);
+
+ Want providerWant;
+ AppExecFwk::ElementName providerElement("0", TARGET_BUNDLE_NAME, TARGET_ABILITY_NAME, TARGET_MODULE_NAME);
+ providerWant.SetElement(providerElement);
+
+ auto connection = sptr::MakeSptr();
+ ASSERT_NE(connection, nullptr);
+
+ auto sessionInfo = sptr::MakeSptr();
+ ASSERT_NE(sessionInfo, nullptr);
+
+ // Connect ui extension ability firstly.
+ auto connectInfo = sptr::MakeSptr();
+ ASSERT_NE(connectInfo, nullptr);
+ connectInfo->hostBundleName = USER_BUNDLE_NAME;
+ connectInfo->uiExtensionAbilityId = 0;
+ auto ret = AbilityManagerClient::GetInstance()->ConnectUIExtensionAbility(providerWant, connection, sessionInfo,
+ DEFAULT_INVAL_VALUE, connectInfo);
+ EXPECT_EQ(ret, ERR_OK);
+ HILOG_INFO("UIExtensonAbility id %{public}d", connectInfo->uiExtensionAbilityId);
+ EXPECT_NE(connectInfo->uiExtensionAbilityId, 0);
+
+ // Wait until OnAbilityConnectDone has triggered.
+ WaitUntilConnectDone(connection);
+
+ // Disconnect ui extension ability.
+ // wish can't be destroyed, cause there exist ui extension component.
+ ret = AbilityManagerClient::GetInstance()->DisconnectAbility(connection);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until OnAbilityDisconnectDone has triggered.
+ WaitUntilDisConnectDone(connection);
+
+ // Wait until ability has terminate
+ WaitUntilProcessDied(observer);
+
+ SetSelfTokenID(currentId);
+ UnregisterApplicationStateObserver(observer);
+ HILOG_INFO("finish.");
+}
+
+/**
+ * @tc.name: ConnectUIExtensionAbility_0500
+ * @tc.desc: basic function test.
+ * @tc.type: FUNC
+ * @tc.require: issueI5OD2E
+ */
+HWTEST_F(UIExtensionConnectModuleTest, ConnectUIExtensionAbility_0500, TestSize.Level1)
+{
+ HILOG_INFO("start.");
+
+ auto currentId = GetSelfTokenID();
+ SetNativeToken();
+
+ auto observer = sptr::MakeSptr();
+ RegisterApplicationStateObserver(observer);
+
+ Want providerWant;
+ AppExecFwk::ElementName providerElement("0", TARGET_BUNDLE_NAME, TARGET_ABILITY_NAME, TARGET_MODULE_NAME);
+ providerWant.SetElement(providerElement);
+
+ auto connection = sptr::MakeSptr();
+ ASSERT_NE(connection, nullptr);
+
+ auto sessionInfo = sptr::MakeSptr();
+ ASSERT_NE(sessionInfo, nullptr);
+
+ // Connect ui extension ability firstly.
+ auto connectInfo = sptr::MakeSptr();
+ ASSERT_NE(connectInfo, nullptr);
+ connectInfo->hostBundleName = USER_BUNDLE_NAME;
+ connectInfo->uiExtensionAbilityId = 0;
+ auto ret = AbilityManagerClient::GetInstance()->ConnectUIExtensionAbility(providerWant, connection, sessionInfo,
+ DEFAULT_INVAL_VALUE, connectInfo);
+ EXPECT_EQ(ret, ERR_OK);
+ HILOG_INFO("UIExtensonAbility id %{public}d", connectInfo->uiExtensionAbilityId);
+ EXPECT_NE(connectInfo->uiExtensionAbilityId, 0);
+
+ // Wait until OnAbilityConnectDone has triggered.
+ WaitUntilConnectDone(connection);
+
+ // Send uiextensionability id to ui extension user
+ // start ui extension user
+ Want userWant;
+ AppExecFwk::ElementName userElement("0", USER_BUNDLE_NAME, USER_ABILITY_NAME, USER_MODULE_NAME);
+ userWant.SetElement(userElement);
+ ret = AbilityManagerClient::GetInstance()->StartAbility(userWant);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until ability has foregrounded
+ WaitUntilAbilityForeground(observer);
+
+ // Disconnect ui extension ability.
+ // wish can't be destroyed, cause there exist ui extension component.
+ ret = AbilityManagerClient::GetInstance()->DisconnectAbility(connection);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until OnAbilityDisconnectDone has triggered.
+ WaitUntilDisConnectDone(connection);
+
+ // Destroy ui extension user, this testcase should executed in screen-on.
+ sptr token = nullptr;
+ ret = AbilityManagerClient::GetInstance()->GetTopAbility(token);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Minimize ui extension user
+ ret = AbilityManagerClient::GetInstance()->MinimizeAbility(token);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until ability has background
+ WaitUntilAbilityBackground(observer);
+
+ int resultCode = 0;
+ Want resultWant;
+ ret = AbilityManagerClient::GetInstance()->TerminateAbility(token, resultCode, &resultWant);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until ability has terminate
+ WaitUntilProcessDied(observer);
+
+ SetSelfTokenID(currentId);
+ UnregisterApplicationStateObserver(observer);
+ HILOG_INFO("finish.");
+}
+
+/**
+ * @tc.name: ConnectUIExtensionAbility_0600
+ * @tc.desc: basic function test.
+ * @tc.type: FUNC
+ * @tc.require: issueI5OD2E
+ */
+HWTEST_F(UIExtensionConnectModuleTest, ConnectUIExtensionAbility_0600, TestSize.Level1)
+{
+ HILOG_INFO("start.");
+
+ auto currentId = GetSelfTokenID();
+ SetNativeToken();
+
+ auto observer = sptr::MakeSptr();
+ RegisterApplicationStateObserver(observer);
+
+ Want providerWant;
+ AppExecFwk::ElementName providerElement("0", TARGET_BUNDLE_NAME, TARGET_ABILITY_NAME, TARGET_MODULE_NAME);
+ providerWant.SetElement(providerElement);
+
+ auto connection = sptr::MakeSptr();
+ ASSERT_NE(connection, nullptr);
+
+ auto sessionInfo = sptr::MakeSptr();
+ ASSERT_NE(sessionInfo, nullptr);
+
+ // Connect ui extension ability firstly.
+ auto connectInfo = sptr::MakeSptr();
+ ASSERT_NE(connectInfo, nullptr);
+ connectInfo->hostBundleName = USER_BUNDLE_NAME;
+ connectInfo->uiExtensionAbilityId = 0;
+ auto ret = AbilityManagerClient::GetInstance()->ConnectUIExtensionAbility(providerWant, connection, sessionInfo,
+ DEFAULT_INVAL_VALUE, connectInfo);
+ EXPECT_EQ(ret, ERR_OK);
+ HILOG_INFO("UIExtensonAbility id %{public}d", connectInfo->uiExtensionAbilityId);
+ EXPECT_NE(connectInfo->uiExtensionAbilityId, 0);
+
+ // Wait until OnAbilityConnectDone has triggered.
+ WaitUntilConnectDone(connection);
+
+ // start ui extension user
+ Want userWant;
+ AppExecFwk::ElementName userElement("0", USER_BUNDLE_NAME, USER_ABILITY_NAME, USER_MODULE_NAME);
+ userWant.SetElement(userElement);
+ ret = AbilityManagerClient::GetInstance()->StartAbility(userWant);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until ability has foregrounded
+ WaitUntilAbilityForeground(observer);
+
+ // Destroy ui extension user.
+ sptr token = nullptr;
+ ret = AbilityManagerClient::GetInstance()->GetTopAbility(token);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Minimize ui extension user
+ ret = AbilityManagerClient::GetInstance()->MinimizeAbility(token);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until ability has background
+ WaitUntilAbilityBackground(observer);
+
+ int resultCode = 0;
+ Want resultWant;
+ ret = AbilityManagerClient::GetInstance()->TerminateAbility(token, resultCode, &resultWant);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until ability has background
+ WaitUntilAbilityBackground(observer);
+
+ // Disconnect ui extension ability.
+ ret = AbilityManagerClient::GetInstance()->DisconnectAbility(connection);
+ EXPECT_EQ(ret, ERR_OK);
+
+ // Wait until OnAbilityDisconnectDone has triggered.
+ WaitUntilDisConnectDone(connection);
+
+ SetSelfTokenID(currentId);
+ UnregisterApplicationStateObserver(observer);
+ HILOG_INFO("finish.");
+}
+} // namespace AAFwk
+} // namespace OHOS
\ No newline at end of file
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/ui_extension_connect_module_test_connection.cpp b/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/ui_extension_connect_module_test_connection.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5695b9e14e501785dcffe523a010169dcb54b928
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/ui_extension_connect_module_test_connection.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2023 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 "ui_extension_connect_module_test_connection.h"
+#include "hilog_wrapper.h"
+
+namespace OHOS {
+namespace AAFwk {
+void UIExtensionConnectModuleTestConnection::OnAbilityConnectDone(const AppExecFwk::ElementName& element,
+ const sptr& remoteObject, int resultCode)
+{
+ HILOG_INFO("element: %{public}s", element.GetURI().c_str());
+ std::unique_lock lock(connectMutex_);
+ connectFinished_ = true;
+ connectCondation_.notify_one();
+}
+
+void UIExtensionConnectModuleTestConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName& element,
+ int resultCode)
+{
+ HILOG_INFO("element: %{public}s", element.GetURI().c_str());
+ std::unique_lock lock(connectMutex_);
+ disConnectFinished_ = true;
+ connectCondation_.notify_one();
+}
+} // namespace AAFwk
+} // namespace OHOS
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/ui_extension_connect_module_test_connection.h b/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/ui_extension_connect_module_test_connection.h
new file mode 100644
index 0000000000000000000000000000000000000000..3894bb1d87309a505741517273bccc8446a9844c
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/ui_extension_connect_module_test_connection.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2023 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_ABILITY_RUNTIME_UI_EXTENSION_CONNECT_MODULE_TEST_CONNECTION_H
+#define OHOS_ABILITY_RUNTIME_UI_EXTENSION_CONNECT_MODULE_TEST_CONNECTION_H
+
+#include "ability_connect_callback_stub.h"
+
+namespace OHOS {
+namespace AAFwk {
+class UIExtensionConnectModuleTestConnection : public AbilityConnectionStub {
+public:
+ UIExtensionConnectModuleTestConnection() = default;
+ ~UIExtensionConnectModuleTestConnection() = default;
+
+ std::condition_variable connectCondation_;
+ std::mutex connectMutex_;
+ bool connectFinished_ = false;
+ bool disConnectFinished_ = false;
+
+private:
+ void OnAbilityConnectDone(const AppExecFwk::ElementName& element,
+ const sptr& remoteObject, int resultCode) override;
+ void OnAbilityDisconnectDone(const AppExecFwk::ElementName& element, int resultCode) override;
+};
+} // namespace AAFwk
+} // namespace OHOS
+#endif // OHOS_ABILITY_RUNTIME_UI_EXTENSION_CONNECT_MODULE_TEST_CONNECTION_H
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/ui_extension_connect_module_test_observer.cpp b/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/ui_extension_connect_module_test_observer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..459fdc3407885adbd7c9850556191e0df450f058
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/ui_extension_connect_module_test_observer.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2023 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 "ui_extension_connect_module_test_observer.h"
+#include "hilog_wrapper.h"
+
+namespace OHOS {
+namespace AAFwk {
+namespace {
+const std::string TARGET_BUNDLE_NAME = "com.ohos.uiextensionprovider";
+} // namespace
+
+void UIExtensionConnectModuleTestObserver::OnProcessCreated(const AppExecFwk::ProcessData &processData)
+{
+ HILOG_INFO("bundleName: %{public}s, abilityState: %{public}d", processData.bundleName.c_str(), processData.state);
+ std::unique_lock lock(observerMutex_);
+ if (processData.bundleName == TARGET_BUNDLE_NAME) {
+ processCreated_ = true;
+ observerCondation_.notify_one();
+ }
+}
+
+void UIExtensionConnectModuleTestObserver::OnProcessStateChanged(const AppExecFwk::ProcessData &processData)
+{
+ HILOG_INFO("bundleName: %{public}s, abilityState: %{public}d", processData.bundleName.c_str(), processData.state);
+ std::unique_lock lock(observerMutex_);
+ if (processData.bundleName == TARGET_BUNDLE_NAME) {
+ if (processData.state == AppExecFwk::AppProcessState::APP_STATE_FOREGROUND) {
+ processForegrounded_ = true;
+ observerCondation_.notify_one();
+ } else if (processData.state == AppExecFwk::AppProcessState::APP_STATE_BACKGROUND) {
+ processBackgrounded_ = true;
+ observerCondation_.notify_one();
+ }
+ }
+}
+
+void UIExtensionConnectModuleTestObserver::OnProcessDied(const AppExecFwk::ProcessData &processData)
+{
+ HILOG_INFO("bundleName: %{public}s, abilityState: %{public}d", processData.bundleName.c_str(), processData.state);
+ std::unique_lock lock(observerMutex_);
+ if (processData.bundleName == TARGET_BUNDLE_NAME) {
+ processDied_ = true;
+ observerCondation_.notify_one();
+ }
+}
+
+void UIExtensionConnectModuleTestObserver::OnAbilityStateChanged(const AppExecFwk::AbilityStateData &abilityStateData)
+{
+ HILOG_INFO("bundleName: %{public}s, abilityState: %{public}d", abilityStateData.bundleName.c_str(),
+ abilityStateData.abilityState);
+}
+
+void UIExtensionConnectModuleTestObserver::OnExtensionStateChanged(const AppExecFwk::AbilityStateData &abilityStateData)
+{
+ HILOG_INFO("bundleName: %{public}s, abilityState: %{public}d", abilityStateData.bundleName.c_str(),
+ abilityStateData.abilityState);
+}
+} // namespace AAFwk
+} // namespace OHOS
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/ui_extension_connect_module_test_observer.h b/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/ui_extension_connect_module_test_observer.h
new file mode 100644
index 0000000000000000000000000000000000000000..c988415ac0270551d3798b431582a375d2839981
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_connect_module_test/ui_extension_connect_module_test_observer.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2023 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_ABILITY_RUNTIME_UI_EXTENSION_CONNECT_MODULE_TEST_OBSERVER_H
+#define OHOS_ABILITY_RUNTIME_UI_EXTENSION_CONNECT_MODULE_TEST_OBSERVER_H
+
+#include "application_state_observer_stub.h"
+
+namespace OHOS {
+namespace AAFwk {
+class UIExtensionConnectModuleTestObserver : public AppExecFwk::ApplicationStateObserverStub {
+public:
+ UIExtensionConnectModuleTestObserver() = default;
+ ~UIExtensionConnectModuleTestObserver() = default;
+
+ std::condition_variable observerCondation_;
+ std::mutex observerMutex_;
+ bool processCreated_ = false;
+ bool processForegrounded_ = false;
+ bool processBackgrounded_ = false;
+ bool processDied_ = false;
+
+private:
+ void OnProcessCreated(const AppExecFwk::ProcessData &processData) override;
+ void OnProcessStateChanged(const AppExecFwk::ProcessData &processData) override;
+ void OnProcessDied(const AppExecFwk::ProcessData &processData) override;
+ void OnAbilityStateChanged(const AppExecFwk::AbilityStateData &abilityStateData) override;
+ void OnExtensionStateChanged(const AppExecFwk::AbilityStateData &abilityStateData) override;
+};
+} // namespace AAFwk
+} // namespace OHOS
+#endif // OHOS_ABILITY_RUNTIME_UI_EXTENSION_CONNECT_MODULE_TEST_OBSERVER_H
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/AppScope/app.json b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/AppScope/app.json
new file mode 100644
index 0000000000000000000000000000000000000000..64896469a1ca6c6e60c3ae8ed828d93957578955
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/AppScope/app.json
@@ -0,0 +1,12 @@
+{
+ "app": {
+ "bundleName": "com.ohos.uiextensionprovider",
+ "vendor": "example",
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "icon": "$media:app_icon",
+ "label": "$string:app_name",
+ "minAPIVersion": 10,
+ "targetAPIVersion": 10
+ }
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/AppScope/resources/base/element/string.json b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/AppScope/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..3d475cfa283e49167b2700c24fc4e904b8f26bad
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/AppScope/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "UIExtensionProvider"
+ }
+ ]
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/AppScope/resources/base/media/app_icon.png b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/AppScope/resources/base/media/app_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/AppScope/resources/base/media/app_icon.png differ
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/BUILD.gn b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/BUILD.gn
new file mode 100644
index 0000000000000000000000000000000000000000..1020906c0de2604d2089cc2582f9a2731b28b208
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/BUILD.gn
@@ -0,0 +1,51 @@
+# Copyright (c) 2023 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/ohos.gni")
+
+ohos_hap("ui_extension_provider_hap") {
+ hap_profile = "entry/src/main/module.json"
+
+ deps = [
+ ":ui_extension_provider_js_assets",
+ ":ui_extension_provider_resources",
+ ]
+
+ ets2abc = true
+ certificate_profile = "signature/openharmony_sx.p7b"
+ hap_name = "ui_extension_provider"
+ subsystem_name = "ability"
+ part_name = "ability_runtime"
+ final_hap_path = "$root_out_dir/tests/moduletest/ability_runtime/ui_extension/resource/${hap_name}.hap"
+}
+
+ohos_js_assets("ui_extension_provider_js_assets") {
+ hap_profile = "entry/src/main/module.json"
+ source_dir = "entry/src/main/ets"
+}
+
+ohos_app_scope("ui_extension_provider_app_profile") {
+ app_profile = "AppScope/app.json"
+ sources = [ "AppScope/resources" ]
+}
+
+ohos_resources("ui_extension_provider_resources") {
+ sources = [ "entry/src/main/resources" ]
+ deps = [ ":ui_extension_provider_app_profile" ]
+ hap_profile = "entry/src/main/module.json"
+}
+
+group("assisthap") {
+ testonly = true
+ deps = [ ":ui_extension_provider_hap" ]
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/IdlServiceExt/IIdlServiceExt.idl b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/IdlServiceExt/IIdlServiceExt.idl
new file mode 100644
index 0000000000000000000000000000000000000000..5e07d743c67ad03d7cfebed8e2e5adfd6917c649
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/IdlServiceExt/IIdlServiceExt.idl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+interface OHOS.IIdlServiceExt {
+ int ProcessData([in] int data);
+ void InsertDataToMap([in] String key, [in] int val);
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/IdlServiceExt/i_idl_service_ext.ts b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/IdlServiceExt/i_idl_service_ext.ts
new file mode 100644
index 0000000000000000000000000000000000000000..66b27b45e2626a1a06fd6b0d35600e68b2e39779
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/IdlServiceExt/i_idl_service_ext.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+export default interface IIdlServiceExt {
+ processData(data: number, callback: processDataCallback): void;
+ insertDataToMap(key: string, val: number, callback: insertDataToMapCallback): void;
+}
+export type processDataCallback = (errCode: number, returnValue: number) => void;
+export type insertDataToMapCallback = (errCode: number) => void;
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/IdlServiceExt/idl_service_ext_impl.ts b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/IdlServiceExt/idl_service_ext_impl.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3cf1823646864952665f9b1ed7ecb5c701c47242
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/IdlServiceExt/idl_service_ext_impl.ts
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2023 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 { processDataCallback } from './i_idl_service_ext';
+import { insertDataToMapCallback } from './i_idl_service_ext';
+import IdlServiceExtStub from './idl_service_ext_stub';
+
+const ERR_OK = 0;
+const TAG: string = "[IdlServiceExtImpl]";
+
+// 开发者需要在这个类型里对接口进行实现
+export default class ServiceExtImpl extends IdlServiceExtStub {
+ processData(data: number, callback: processDataCallback): void {
+ // 开发者自行实现业务逻辑
+ console.info(TAG, `processData: ${data}`);
+ callback(ERR_OK, data + 1);
+ }
+
+ insertDataToMap(key: string, val: number, callback: insertDataToMapCallback): void {
+ // 开发者自行实现业务逻辑
+ console.info(TAG, `insertDataToMap, key: ${key} val: ${val}`);
+ callback(ERR_OK);
+ }
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/IdlServiceExt/idl_service_ext_proxy.ts b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/IdlServiceExt/idl_service_ext_proxy.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d6b1cfe4f50eaef190429094e34acfaedce1bf39
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/IdlServiceExt/idl_service_ext_proxy.ts
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2023 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 {processDataCallback} from "./i_idl_service_ext";
+import {insertDataToMapCallback} from "./i_idl_service_ext";
+import IIdlServiceExt from "./i_idl_service_ext";
+import rpc from "@ohos.rpc";
+
+export default class IdlServiceExtProxy implements IIdlServiceExt {
+ constructor(proxy) {
+ this.proxy = proxy;
+ }
+
+ processData(data: number, callback: processDataCallback): void
+ {
+ let _option = new rpc.MessageOption();
+ let _data = new rpc.MessageParcel();
+ let _reply = new rpc.MessageParcel();
+ _data.writeInt(data);
+ this.proxy.sendMessageRequest(IdlServiceExtProxy.COMMAND_PROCESS_DATA, _data, _reply, _option).then(function(result) {
+ if (result.errCode === 0) {
+ let _errCode = result.reply.readInt();
+ if (_errCode != 0) {
+ let _returnValue = undefined;
+ callback(_errCode, _returnValue);
+ return;
+ }
+ let _returnValue = result.reply.readInt();
+ callback(_errCode, _returnValue);
+ } else {
+ console.log("sendMessageRequest failed, errCode: " + result.errCode);
+ }
+ })
+ }
+
+ insertDataToMap(key: string, val: number, callback: insertDataToMapCallback): void
+ {
+ let _option = new rpc.MessageOption();
+ let _data = new rpc.MessageParcel();
+ let _reply = new rpc.MessageParcel();
+ _data.writeString(key);
+ _data.writeInt(val);
+ this.proxy.sendMessageRequest(IdlServiceExtProxy.COMMAND_INSERT_DATA_TO_MAP, _data, _reply, _option).then(function(result) {
+ if (result.errCode === 0) {
+ let _errCode = result.reply.readInt();
+ callback(_errCode);
+ } else {
+ console.log("sendMessageRequest failed, errCode: " + result.errCode);
+ }
+ })
+ }
+
+ static readonly COMMAND_PROCESS_DATA = 1;
+ static readonly COMMAND_INSERT_DATA_TO_MAP = 2;
+ private proxy
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/IdlServiceExt/idl_service_ext_stub.ts b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/IdlServiceExt/idl_service_ext_stub.ts
new file mode 100644
index 0000000000000000000000000000000000000000..af481a1697d59e2e2e7ee67b064d9a6b42c541bb
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/IdlServiceExt/idl_service_ext_stub.ts
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2023 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 {processDataCallback} from "./i_idl_service_ext";
+import {insertDataToMapCallback} from "./i_idl_service_ext";
+import IIdlServiceExt from "./i_idl_service_ext";
+import rpc from "@ohos.rpc";
+
+export default class IdlServiceExtStub extends rpc.RemoteObject implements IIdlServiceExt {
+ constructor(des: string) {
+ super(des);
+ }
+
+ async onRemoteMessageRequest(code: number, data, reply, option): Promise {
+ console.log("onRemoteMessageRequest called, code = " + code);
+ switch(code) {
+ case IdlServiceExtStub.COMMAND_PROCESS_DATA: {
+ let _data = data.readInt();
+ this.processData(_data, (errCode, returnValue) => {
+ reply.writeInt(errCode);
+ if (errCode == 0) {
+ reply.writeInt(returnValue);
+ }
+ });
+ return true;
+ }
+ case IdlServiceExtStub.COMMAND_INSERT_DATA_TO_MAP: {
+ let _key = data.readString();
+ let _val = data.readInt();
+ this.insertDataToMap(_key, _val, (errCode) => {
+ reply.writeInt(errCode);
+ });
+ return true;
+ }
+ default: {
+ console.log("invalid request code" + code);
+ break;
+ }
+ }
+ return false;
+ }
+
+ processData(data: number, callback: processDataCallback): void{}
+ insertDataToMap(key: string, val: number, callback: insertDataToMapCallback): void{}
+
+ static readonly COMMAND_PROCESS_DATA = 1;
+ static readonly COMMAND_INSERT_DATA_TO_MAP = 2;
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/entryability/EntryAbility.ets b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/entryability/EntryAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..078a52eb8bb31b173c165c608ea399eaa4455d72
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/entryability/EntryAbility.ets
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2023 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 AbilityConstant from '@ohos.app.ability.AbilityConstant';
+import hilog from '@ohos.hilog';
+import UIAbility from '@ohos.app.ability.UIAbility';
+import Want from '@ohos.app.ability.Want';
+import window from '@ohos.window';
+
+export default class EntryAbility extends UIAbility {
+ onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
+ }
+
+ onDestroy() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
+ }
+
+ onWindowStageCreate(windowStage: window.WindowStage) {
+ // Main window is created, set main page for this ability
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
+
+ windowStage.loadContent('pages/Index', (err, data) => {
+ if (err.code) {
+ hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
+ return;
+ }
+ hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
+ });
+ }
+
+ onWindowStageDestroy() {
+ // Main window is destroyed, release UI related resources
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
+ }
+
+ onForeground() {
+ // Ability has brought to foreground
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
+ }
+
+ onBackground() {
+ // Ability has back to background
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
+ }
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/pages/Extension.ets b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/pages/Extension.ets
new file mode 100644
index 0000000000000000000000000000000000000000..4b2ee4d0244a2f2da7822c45a9c5173558e73eca
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/pages/Extension.ets
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2023 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 UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession';
+
+let storage = LocalStorage.getShared();
+const TAG: string = '[testTag] ExtensionPage'
+
+@Entry(storage)
+@Component
+struct Extension {
+ @State message: string = 'UIExtension Provider';
+ private session: UIExtensionContentSession | undefined = storage.get('session');
+
+ onPageShow() {
+ console.info(TAG, 'show');
+ // if u wanna use setReceiveDataCallback, you should be a system app.
+ // this.session?.setReceiveDataCallback((data) => {
+ // this.message = JSON.stringify(data);
+ // })
+ }
+
+ build() {
+ Row() {
+ Column() {
+ Text(this.message)
+ .fontSize(20)
+ .fontWeight(FontWeight.Bold)
+ .textAlign(TextAlign.Center)
+
+ Button("send data")
+ .width('80%')
+ .type(ButtonType.Capsule)
+ .margin({
+ top: 20
+ })
+ .onClick(() => {
+ this.session?.sendData({ "data": 543321 });
+ })
+
+ Button("terminate self")
+ .width('80%')
+ .type(ButtonType.Capsule)
+ .margin({
+ top: 20
+ })
+ .onClick(() => {
+ this.session?.terminateSelf();
+ storage.clear();
+ })
+
+ Button("terminate self with result")
+ .width('80%')
+ .type(ButtonType.Capsule)
+ .margin({
+ top: 20
+ })
+ .onClick(() => {
+ this.session?.terminateSelfWithResult({
+ resultCode: 0,
+ want: {
+ bundleName: "com.ohos.uiextensionprovider",
+ parameters: { "result": 123456 }
+ }
+ })
+ })
+ }
+ }
+ .height('100%')
+ }
+}
\ No newline at end of file
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/pages/Index.ets b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/pages/Index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..c0e40e0d3a9e577ef8612c49a3f14d2e097bc45b
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/pages/Index.ets
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+@Entry
+@Component
+struct Index {
+ @State message: string = 'UIExtension MainPage';
+
+ build() {
+ Row() {
+ Column() {
+ Text(this.message)
+ .fontSize(30)
+ .fontWeight(FontWeight.Bold)
+ }
+ .width('100%')
+ }
+ .height('100%')
+ }
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/uiextensionability/UIExtensionAbility.ets b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/uiextensionability/UIExtensionAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..3a8a1405ca36e90ffba92d8dd5d7262638636a2a
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/ets/uiextensionability/UIExtensionAbility.ets
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2023 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 UIExtensionAbility from '@ohos.app.ability.UIExtensionAbility'
+import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession';
+import Want from '@ohos.app.ability.Want';
+import ServiceExtImpl from '../IdlServiceExt/idl_service_ext_impl';
+
+const TAG: string = '[testTag] UIExtAbility';
+
+export default class UIExtAbility extends UIExtensionAbility {
+ serviceExtImpl = new ServiceExtImpl("ExtImpl");
+ onCreate() {
+ console.log(TAG, `onCreate`);
+ }
+
+ onForeground() {
+ console.log(TAG, `onForeground`);
+ }
+
+ onBackground() {
+ console.log(TAG, `onBackground`);
+ }
+
+ onDestroy() {
+ console.log(TAG, `onDestroy`);
+ }
+
+ onSessionCreate(want: Want, session: UIExtensionContentSession) {
+ console.log(TAG, `onSessionCreate, want: ${JSON.stringify(want)}`);
+ let storage: LocalStorage = new LocalStorage();
+ storage.setOrCreate('session', session);
+ session.loadContent('pages/Extension', storage);
+ }
+
+ onSessionDestroy(session: UIExtensionContentSession) {
+ console.log(TAG, `onSessionDestroy`);
+ }
+
+ // just for test connect ui extension ability
+ onConnect(want: Want) {
+ console.log(TAG, `onConnect, want: ${JSON.stringify(want)}`);
+ return this.serviceExtImpl;
+ }
+
+ onDisConnect(want: Want) {
+ console.log(TAG, `onDisConnect, want: ${JSON.stringify(want)}`);
+ }
+};
\ No newline at end of file
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/module.json b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/module.json
new file mode 100644
index 0000000000000000000000000000000000000000..2adb8dedbafa5b2797ad9d5d15730c600eecfc33
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/module.json
@@ -0,0 +1,48 @@
+{
+ "module": {
+ "name": "entry",
+ "type": "entry",
+ "description": "$string:module_desc",
+ "mainElement": "EntryAbility",
+ "deviceTypes": [
+ "phone",
+ "tablet",
+ "2in1"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false,
+ "pages": "$profile:main_pages",
+ "abilities": [
+ {
+ "name": "EntryAbility",
+ "srcEntry": "./ets/entryability/EntryAbility.ets",
+ "description": "$string:EntryAbility_desc",
+ "icon": "$media:icon",
+ "label": "$string:EntryAbility_label",
+ "startWindowIcon": "$media:startIcon",
+ "startWindowBackground": "$color:start_window_background",
+ "exported": true,
+ "skills": [
+ {
+ "entities": [
+ "entity.system.home"
+ ],
+ "actions": [
+ "action.system.home"
+ ]
+ }
+ ]
+ }
+ ],
+ "extensionAbilities": [
+ {
+ "name": "UIExtensionProvider",
+ "srcEntry": "./ets/uiextensionability/UIExtensionAbility.ets",
+ "description": "$string:UIExtensionAbility_desc",
+ "label": "$string:UIExtensionAbility_label",
+ "type": "sys/commonUI",
+ "exported": true
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/resources/base/element/color.json b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/resources/base/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#FFFFFF"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/resources/base/element/string.json b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..8c40e6e7a04d3c78973feb371dd9bcafbc59a391
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/resources/base/element/string.json
@@ -0,0 +1,24 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "label"
+ },
+ {
+ "name": "UIExtensionAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "UIExtensionAbility_label",
+ "value": "label"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/resources/base/media/icon.png b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/resources/base/media/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/resources/base/media/icon.png differ
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/resources/base/media/startIcon.png b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/resources/base/media/startIcon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/resources/base/media/startIcon.png differ
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/resources/base/profile/main_pages.json b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/resources/base/profile/main_pages.json
new file mode 100644
index 0000000000000000000000000000000000000000..363b79bdaba6bd433638a0635564d7aa635be55c
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/entry/src/main/resources/base/profile/main_pages.json
@@ -0,0 +1,6 @@
+{
+ "src": [
+ "pages/Index",
+ "pages/Extension"
+ ]
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/signature/openharmony_sx.p7b b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/signature/openharmony_sx.p7b
new file mode 100644
index 0000000000000000000000000000000000000000..8b3a30ef5dfec0780b78cdf8b303a98dc9743f56
Binary files /dev/null and b/test/moduletest/ui_extension_ability_test/ui_extension_provider_bundle/signature/openharmony_sx.p7b differ
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/AppScope/app.json b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/AppScope/app.json
new file mode 100644
index 0000000000000000000000000000000000000000..1c12e211dad38359fedb201a9e5e9507ccbfaa1e
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/AppScope/app.json
@@ -0,0 +1,12 @@
+{
+ "app": {
+ "bundleName": "com.ohos.uiextensionuser",
+ "vendor": "example",
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "icon": "$media:app_icon",
+ "label": "$string:app_name",
+ "minAPIVersion": 10,
+ "targetAPIVersion": 10
+ }
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/AppScope/resources/base/element/string.json b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/AppScope/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..05e001635d51f82e4f15168b3b556e5850eef2ca
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/AppScope/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "UIExtensionUser"
+ }
+ ]
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/AppScope/resources/base/media/app_icon.png b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/AppScope/resources/base/media/app_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/AppScope/resources/base/media/app_icon.png differ
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/BUILD.gn b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/BUILD.gn
new file mode 100644
index 0000000000000000000000000000000000000000..b17f82f47c40a96b69b1769292cdacf8782738aa
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/BUILD.gn
@@ -0,0 +1,51 @@
+# Copyright (c) 2023 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/ohos.gni")
+
+ohos_hap("ui_extension_user_hap") {
+ hap_profile = "entry/src/main/module.json"
+
+ deps = [
+ ":ui_extension_user_js_assets",
+ ":ui_extension_user_resources",
+ ]
+
+ ets2abc = true
+ certificate_profile = "signature/openharmony_sx.p7b"
+ hap_name = "ui_extension_user"
+ subsystem_name = "ability"
+ part_name = "ability_runtime"
+ final_hap_path = "$root_out_dir/tests/moduletest/ability_runtime/ui_extension/resource/${hap_name}.hap"
+}
+
+ohos_js_assets("ui_extension_user_js_assets") {
+ hap_profile = "entry/src/main/module.json"
+ source_dir = "entry/src/main/ets"
+}
+
+ohos_app_scope("ui_extension_user_app_profile") {
+ app_profile = "AppScope/app.json"
+ sources = [ "AppScope/resources" ]
+}
+
+ohos_resources("ui_extension_user_resources") {
+ sources = [ "entry/src/main/resources" ]
+ deps = [ ":ui_extension_user_app_profile" ]
+ hap_profile = "entry/src/main/module.json"
+}
+
+group("assisthap") {
+ testonly = true
+ deps = [ ":ui_extension_user_hap" ]
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/ets/entryability/EntryAbility.ets b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/ets/entryability/EntryAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..078a52eb8bb31b173c165c608ea399eaa4455d72
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/ets/entryability/EntryAbility.ets
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2023 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 AbilityConstant from '@ohos.app.ability.AbilityConstant';
+import hilog from '@ohos.hilog';
+import UIAbility from '@ohos.app.ability.UIAbility';
+import Want from '@ohos.app.ability.Want';
+import window from '@ohos.window';
+
+export default class EntryAbility extends UIAbility {
+ onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
+ }
+
+ onDestroy() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
+ }
+
+ onWindowStageCreate(windowStage: window.WindowStage) {
+ // Main window is created, set main page for this ability
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
+
+ windowStage.loadContent('pages/Index', (err, data) => {
+ if (err.code) {
+ hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
+ return;
+ }
+ hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
+ });
+ }
+
+ onWindowStageDestroy() {
+ // Main window is destroyed, release UI related resources
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
+ }
+
+ onForeground() {
+ // Ability has brought to foreground
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
+ }
+
+ onBackground() {
+ // Ability has back to background
+ hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
+ }
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/ets/pages/Index.ets b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/ets/pages/Index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..09e0cdc96dac392e6f81d754cdea36eaa74ae356
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/ets/pages/Index.ets
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+@Entry
+@Component
+struct Index {
+ @State message: string = 'UIExtension User';
+ private myProxy: UIExtensionProxy | undefined = undefined;
+
+ build() {
+ Row() {
+ Column() {
+ Text(this.message)
+ .fontSize(30)
+ .size({ width: '100%', height: '50' })
+ .fontWeight(FontWeight.Bold)
+ .textAlign(TextAlign.Center)
+
+ UIExtensionComponent(
+ {
+ bundleName: 'com.ohos.uiextensionprovider',
+ abilityName: 'UIExtensionProvider',
+ moduleName: 'entry',
+ parameters: {
+ 'ability.want.params.uiExtensionType': 'sys/commonUI',
+ }
+ })
+ .onRemoteReady((proxy) => {
+ this.myProxy = proxy;
+ })
+ .onReceive((data) => {
+ this.message = JSON.stringify(data);
+ })
+ .onResult((data) => {
+ this.message = JSON.stringify(data);
+ })
+ .onRelease((code) => {
+ this.message = "release code: " + code;
+ })
+ .offset({ x: 0, y: 30 })
+ .size({ width: 300, height: 300 })
+ .border({ width: 5, color: 0x317AF7, radius: 10, style: BorderStyle.Dotted })
+
+ Button("sendData")
+ .type(ButtonType.Capsule)
+ .offset({ x: 0, y: 60 })
+ .width('80%')
+ .type(ButtonType.Capsule)
+ .margin({
+ top: 20
+ })
+ .onClick(() => {
+ this.myProxy?.send({
+ "data": 123456,
+ "message": "data from component"
+ })
+ })
+ }
+ .width('100%')
+ }
+ .height('100%')
+ }
+}
\ No newline at end of file
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/module.json b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/module.json
new file mode 100644
index 0000000000000000000000000000000000000000..6c07d9d8839ac9716809c6e06c21805d52c138fe
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/module.json
@@ -0,0 +1,38 @@
+{
+ "module": {
+ "name": "entry",
+ "type": "entry",
+ "description": "$string:module_desc",
+ "mainElement": "EntryAbility",
+ "deviceTypes": [
+ "phone",
+ "tablet",
+ "2in1"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false,
+ "pages": "$profile:main_pages",
+ "abilities": [
+ {
+ "name": "EntryAbility",
+ "srcEntry": "./ets/entryability/EntryAbility.ets",
+ "description": "$string:EntryAbility_desc",
+ "icon": "$media:icon",
+ "label": "$string:EntryAbility_label",
+ "startWindowIcon": "$media:startIcon",
+ "startWindowBackground": "$color:start_window_background",
+ "exported": true,
+ "skills": [
+ {
+ "entities": [
+ "entity.system.home"
+ ],
+ "actions": [
+ "action.system.home"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/resources/base/element/color.json b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/resources/base/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#FFFFFF"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/resources/base/element/string.json b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..f94595515a99e0c828807e243494f57f09251930
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/resources/base/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "label"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/resources/base/media/icon.png b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/resources/base/media/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/resources/base/media/icon.png differ
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/resources/base/media/startIcon.png b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/resources/base/media/startIcon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/resources/base/media/startIcon.png differ
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/resources/base/profile/main_pages.json b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/resources/base/profile/main_pages.json
new file mode 100644
index 0000000000000000000000000000000000000000..1898d94f58d6128ab712be2c68acc7c98e9ab9ce
--- /dev/null
+++ b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/entry/src/main/resources/base/profile/main_pages.json
@@ -0,0 +1,5 @@
+{
+ "src": [
+ "pages/Index"
+ ]
+}
diff --git a/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/signature/openharmony_sx.p7b b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/signature/openharmony_sx.p7b
new file mode 100644
index 0000000000000000000000000000000000000000..21fc995207a3c10b5c583dcaecdfde565cb9410a
Binary files /dev/null and b/test/moduletest/ui_extension_ability_test/ui_extension_user_bundle/signature/openharmony_sx.p7b differ