* 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 "root_scene.h"
#include <bundlemgr/launcher_service.h>
#include <event_handler.h>
#include <input_manager.h>
#include <int_wrapper.h>
#include <iremote_stub.h>
#include <transaction/rs_interfaces.h>
#include <ui_content.h>
#include <ui/rs_node.h>
#include <viewport_config.h>
#include "ability_context.h"
#include "app_mgr_client.h"
#include "display_manager.h"
#include "extension/extension_business_info.h"
#include "fold_screen_state_internel.h"
#include "input_transfer_station.h"
#include "rs_adapter.h"
#include "screen_session_manager_client.h"
#include "singleton.h"
#include "singleton_container.h"
#include "intention_event_manager.h"
#include "window_manager_hilog.h"
#include "load_intention_event.h"
namespace OHOS {
namespace Rosen {
namespace {
constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, HILOG_DOMAIN_WINDOW, "RootScene" };
const std::string INPUT_AND_VSYNC_THREAD = "InputAndVsyncThread";
constexpr int32_t API_VERSION_18 = 18;
class BundleStatusCallback : public IRemoteStub<AppExecFwk::IBundleStatusCallback> {
public:
explicit BundleStatusCallback(RootScene* rootScene) : rootScene_(rootScene) {}
virtual ~BundleStatusCallback() = default;
void OnBundleStateChanged(const uint8_t installType,
const int32_t resultCode, const std::string& resultMsg, const std::string& bundleName) override {}
void OnBundleAdded(const std::string& bundleName, const int userId) override
{
rootScene_->OnBundleUpdated(bundleName);
}
void OnBundleUpdated(const std::string& bundleName, const int userId) override
{
rootScene_->OnBundleUpdated(bundleName);
}
void OnBundleRemoved(const std::string& bundleName, const int userId) override {}
private:
RootScene* rootScene_;
};
}
sptr<RootScene> RootScene::staticRootScene_;
std::function<void(const std::shared_ptr<AppExecFwk::Configuration>&)> RootScene::configurationUpdatedCallback_;
RootScene::RootScene()
{
launcherService_ = new AppExecFwk::LauncherService();
if (!launcherService_->RegisterCallback(new BundleStatusCallback(this))) {
WLOGFE("Failed to register bundle status callback.");
}
NodeId nodeId = 0;
vsyncStation_ = std::make_shared<VsyncStation>(nodeId);
handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
}
RootScene::~RootScene()
{
TLOGI(WmsLogTag::WMS_MAIN, "destroyed");
RemoveRootScene(DEFAULT_DISPLAY_ID);
uiContent_ = nullptr;
}
void RootScene::LoadContent(const std::string& contentUrl, napi_env env, napi_value storage,
AbilityRuntime::Context* context)
{
if (context == nullptr) {
WLOGFE("context is nullptr!");
return;
}
uiContent_ = Ace::UIContent::Create(context, reinterpret_cast<NativeEngine*>(env));
if (uiContent_ == nullptr) {
WLOGFE("uiContent_ is nullptr!");
return;
}
context_ = context->weak_from_this();
uiContent_->Initialize(this, contentUrl, storage);
uiContent_->Foreground();
uiContent_->SetFrameLayoutFinishCallback(std::move(frameLayoutFinishCb_));
uiContent_->AddFocusActiveChangeCallback(notifyWatchFocusActiveChangeCallback_);
wptr<Window> weakWindow(this);
AddRootScene(DEFAULT_DISPLAY_ID, weakWindow);
RegisterInputEventListener();
}
void RootScene::SetDisplayOrientation(int32_t orientation)
{
orientation_ = orientation;
}
void RootScene::UpdateViewportConfig(const Rect& rect, WindowSizeChangeReason reason)
{
if (updateRootSceneRectCallback_ != nullptr) {
updateRootSceneRectCallback_(rect);
}
if (uiContent_ == nullptr) {
TLOGD(WmsLogTag::DEFAULT, "uiContent_ is nullptr!");
return;
}
Ace::ViewportConfig config;
config.SetSize(rect.width_, rect.height_);
config.SetPosition(rect.posX_, rect.posY_);
config.SetDensity(density_);
config.SetOrientation(orientation_);
config.SetDisplayId(GetDisplayId());
uiContent_->UpdateViewportConfig(config, reason);
}
void RootScene::UpdateConfiguration(const std::shared_ptr<AppExecFwk::Configuration>& configuration)
{
TLOGD(WmsLogTag::WMS_ATTRIBUTE, "root map size: %{public}u", static_cast<uint32_t>(rootSceneMap_.size()));
for (const auto& sceneMap : rootSceneMap_) {
if (sceneMap.second == nullptr) {
TLOGE(WmsLogTag::WMS_ATTRIBUTE, "root window is null, display=%{public}" PRIu64, sceneMap.first);
continue;
}
auto window = sceneMap.second.promote();
if (window == nullptr) {
TLOGE(WmsLogTag::WMS_ATTRIBUTE, "root win is null, display=%{public}" PRIu64, sceneMap.first);
continue;
}
auto uiContent = window->GetUIContent();
if (uiContent == nullptr) {
TLOGE(WmsLogTag::WMS_ATTRIBUTE, "uiContent is null, root win=%{public}u, display=%{public}" PRIu64,
window->GetWindowId(), window->GetDisplayId());
continue;
}
TLOGD(WmsLogTag::WMS_ATTRIBUTE, "root win=%{public}u, display=%{public}" PRIu64,
window->GetWindowId(), window->GetDisplayId());
uiContent->UpdateConfiguration(configuration);
if (configuration == nullptr) {
TLOGE(WmsLogTag::WMS_ATTRIBUTE, "config is null, root win=%{public}u, display=%{public}" PRIu64,
window->GetWindowId(), window->GetDisplayId());
continue;
}
std::string colorMode = configuration->GetItem(AAFwk::GlobalConfigurationKey::SYSTEM_COLORMODE);
bool isDark = (colorMode == AppExecFwk::ConfigurationInner::COLOR_MODE_DARK);
bool ret = RSInterfaces::GetInstance().SetGlobalDarkColorMode(isDark);
if (ret == false) {
TLOGE(WmsLogTag::WMS_ATTRIBUTE, "SetGlobalDarkColorMode fail, colorMode : %{public}s", colorMode.c_str());
}
}
}
void RootScene::UpdateConfigurationForSpecified(const std::shared_ptr<AppExecFwk::Configuration>& configuration,
const std::shared_ptr<Global::Resource::ResourceManager>& resourceManager)
{
if (uiContent_ == nullptr) {
TLOGE(WmsLogTag::WMS_ATTRIBUTE, "uiContent null, root win=%{public}u, display=%{public}" PRIu64,
GetWindowId(), GetDisplayId());
return;
}
uiContent_->UpdateConfiguration(configuration, resourceManager);
if (configuration == nullptr) {
TLOGE(WmsLogTag::WMS_ATTRIBUTE, "config is null, root win=%{public}u, display=%{public}" PRIu64,
GetWindowId(), GetDisplayId());
return;
}
TLOGD(WmsLogTag::WMS_ATTRIBUTE, "root win=%{public}u, display=%{public}" PRIu64,
GetWindowId(), GetDisplayId());
std::string colorMode = configuration->GetItem(AAFwk::GlobalConfigurationKey::SYSTEM_COLORMODE);
bool isDark = (colorMode == AppExecFwk::ConfigurationInner::COLOR_MODE_DARK);
if (!RSInterfaces::GetInstance().SetGlobalDarkColorMode(isDark)) {
TLOGE(WmsLogTag::WMS_ATTRIBUTE, "set dark color mode failed, winId: %{public}u, colorMode: %{public}s",
GetWindowId(), colorMode.c_str());
}
}
void RootScene::UpdateConfigurationForAll(const std::shared_ptr<AppExecFwk::Configuration>& configuration,
const std::vector<std::shared_ptr<AbilityRuntime::Context>>& ignoreWindowContexts)
{
if (staticRootScene_) {
if (std::count(ignoreWindowContexts.begin(), ignoreWindowContexts.end(), staticRootScene_->GetContext()) == 0) {
TLOGD(WmsLogTag::WMS_ATTRIBUTE, "root win=%{public}u, display=%{public}" PRIu64,
staticRootScene_->GetWindowId(), staticRootScene_->GetDisplayId());
staticRootScene_->UpdateConfiguration(configuration);
if (configurationUpdatedCallback_) {
configurationUpdatedCallback_(configuration);
}
} else {
TLOGI(WmsLogTag::WMS_ATTRIBUTE, "skip root win=%{public}u, display=%{public}" PRIu64,
staticRootScene_->GetWindowId(), staticRootScene_->GetDisplayId());
}
} else {
TLOGE(WmsLogTag::WMS_ATTRIBUTE, "root is null");
}
}
void RootScene::UpdateConfigurationSync(const std::shared_ptr<AppExecFwk::Configuration>& configuration)
{
TLOGD(WmsLogTag::WMS_ATTRIBUTE, "root map size: %{public}u", static_cast<uint32_t>(rootSceneMap_.size()));
for (const auto& sceneMap : rootSceneMap_) {
if (sceneMap.second == nullptr) {
TLOGE(WmsLogTag::WMS_ATTRIBUTE, "root window is null, display=%{public}" PRIu64, sceneMap.first);
continue;
}
auto window = sceneMap.second.promote();
if (window == nullptr) {
TLOGE(WmsLogTag::WMS_ATTRIBUTE, "root win is null, display=%{public}" PRIu64, sceneMap.first);
continue;
}
auto uiContent = window->GetUIContent();
if (uiContent == nullptr) {
TLOGE(WmsLogTag::WMS_ATTRIBUTE, "uiContent is null, root win=%{public}u, display=%{public}" PRIu64,
window->GetWindowId(), window->GetDisplayId());
continue;
}
TLOGD(WmsLogTag::WMS_ATTRIBUTE, "root win=%{public}u, display=%{public}" PRIu64,
window->GetWindowId(), window->GetDisplayId());
uiContent->UpdateConfigurationSyncForAll(configuration);
}
}
void RootScene::UpdateConfigurationSyncForAll(const std::shared_ptr<AppExecFwk::Configuration>& configuration)
{
if (staticRootScene_ != nullptr) {
TLOGD(WmsLogTag::WMS_ATTRIBUTE, "root win=%{public}u, display=%{public}" PRIu64,
staticRootScene_->GetWindowId(), staticRootScene_->GetDisplayId());
staticRootScene_->UpdateConfigurationSync(configuration);
} else {
TLOGE(WmsLogTag::WMS_ATTRIBUTE, "root is null");
}
}
void RootScene::RegisterInputEventListener()
{
auto mainEventRunner = AppExecFwk::EventRunner::GetMainEventRunner();
if (mainEventRunner) {
WLOGFD("MainEventRunner is available");
eventHandler_ = std::make_shared<AppExecFwk::EventHandler>(mainEventRunner);
} else {
WLOGFD("MainEventRunner is not available");
eventHandler_ = AppExecFwk::EventHandler::Current();
if (!eventHandler_) {
eventHandler_ =
std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::Create(INPUT_AND_VSYNC_THREAD));
}
}
if (staticRootScene_ != nullptr && LoadIntentionEvent() &&
!EnableInputEventListener(uiContent_.get(), eventHandler_, this)) {
WLOGFE("EnableInputEventListener fail");
}
InputTransferStation::GetInstance().MarkRegisterToMMI();
}
void RootScene::RequestVsync(const std::shared_ptr<VsyncCallback>& vsyncCallback)
{
vsyncStation_->RequestVsync(vsyncCallback);
}
int64_t RootScene::GetVSyncPeriod()
{
return vsyncStation_->GetVSyncPeriod();
}
void RootScene::FlushFrameRate(uint32_t rate, int32_t animatorExpectedFrameRate, uint32_t rateType)
{
vsyncStation_->FlushFrameRate(GetRSUIContext(), rate, animatorExpectedFrameRate, rateType);
}
bool RootScene::IsLastFrameLayoutFinished()
{
int32_t requestTimes = vsyncStation_->GetRequestVsyncTimes();
TLOGD(WmsLogTag::WMS_LAYOUT, "vsync request times: %{public}d", requestTimes);
return requestTimes <= 0;
}
void RootScene::OnFlushUIParams()
{
vsyncStation_->DecreaseRequestVsyncTimes();
}
void RootScene::OnBundleUpdated(const std::string& bundleName)
{
WLOGFD("bundle %{public}s updated", bundleName.c_str());
if (uiContent_) {
uiContent_->UpdateResource();
}
}
void RootScene::SetOnConfigurationUpdatedCallback(
const std::function<void(const std::shared_ptr<AppExecFwk::Configuration>&)>& callback)
{
configurationUpdatedCallback_ = callback;
}
void RootScene::SetFrameLayoutFinishCallback(std::function<void()>&& callback)
{
frameLayoutFinishCb_ = callback;
if (uiContent_) {
uiContent_->SetFrameLayoutFinishCallback(std::move(frameLayoutFinishCb_));
}
TLOGI(WmsLogTag::WMS_LAYOUT, "end");
}
void RootScene::SetUiDvsyncSwitch(bool dvsyncSwitch)
{
vsyncStation_->SetUiDvsyncSwitch(dvsyncSwitch);
}
void RootScene::SetTouchEvent(int32_t touchType)
{
vsyncStation_->SetTouchEvent(touchType);
}
WMError RootScene::GetAvoidAreaByType(AvoidAreaType type, AvoidArea& avoidArea, const Rect& rect, int32_t apiVersion)
{
if (getSessionAvoidAreaByTypeCallback_ == nullptr) {
TLOGE(WmsLogTag::WMS_IMMS, "getSessionAvoidAreaByTypeCallback is nullptr");
return WMError::WM_ERROR_NULLPTR;
}
if (apiVersion != API_VERSION_INVALID && apiVersion < API_VERSION_18) {
TLOGI(WmsLogTag::WMS_IMMS, "root scene UIExtension type %{public}u api %{public}d not supported",
type, apiVersion);
return WMError::WM_DO_NOTHING;
}
avoidArea = getSessionAvoidAreaByTypeCallback_(type, false);
TLOGI(WmsLogTag::WMS_IMMS, "root scene type %{public}u area %{public}s", type, avoidArea.ToString().c_str());
return WMError::WM_OK;
}
WMError RootScene::GetAvoidAreaByTypeIgnoringVisibility(AvoidAreaType type, AvoidArea& avoidArea, const Rect& rect)
{
if (type == AvoidAreaType::TYPE_KEYBOARD) {
return WMError::WM_ERROR_ILLEGAL_PARAM;
}
if (getSessionAvoidAreaByTypeCallback_ == nullptr) {
TLOGE(WmsLogTag::WMS_IMMS, "getSessionAvoidAreaByTypeCallback is nullptr");
return WMError::WM_ERROR_NULLPTR;
}
avoidArea = getSessionAvoidAreaByTypeCallback_(type, true);
TLOGI(WmsLogTag::WMS_IMMS, "root scene type %{public}u area %{public}s", type, avoidArea.ToString().c_str());
return WMError::WM_OK;
}
void RootScene::RegisterGetSessionAvoidAreaByTypeCallback(GetSessionAvoidAreaByTypeCallback&& callback)
{
getSessionAvoidAreaByTypeCallback_ = std::move(callback);
}
uint32_t RootScene::GetStatusBarHeight() const
{
uint32_t height = 0;
if (getStatusBarHeightCallback_ == nullptr) {
TLOGE(WmsLogTag::WMS_IMMS, "getStatusBarHeightCallback_ is nullptr");
return height;
}
height = getStatusBarHeightCallback_();
TLOGI(WmsLogTag::WMS_IMMS, "root scene height %{public}u", height);
return height;
}
void RootScene::RegisterGetStatusBarHeightCallback(GetStatusBarHeightCallback&& callback)
{
getStatusBarHeightCallback_ = std::move(callback);
}
void RootScene::RegisterUpdateRootSceneRectCallback(UpdateRootSceneRectCallback&& callback)
{
updateRootSceneRectCallback_ = std::move(callback);
}
void RootScene::RegisterUpdateRootSceneAvoidAreaCallback(UpdateRootSceneAvoidAreaCallback&& callback)
{
updateRootSceneAvoidAreaCallback_ = std::move(callback);
}
WMError RootScene::RegisterAvoidAreaChangeListener(const sptr<IAvoidAreaChangedListener>& listener)
{
if (listener == nullptr) {
TLOGE(WmsLogTag::WMS_IMMS, "listener is null");
return WMError::WM_ERROR_NULLPTR;
}
bool firstInserted = false;
{
std::lock_guard<std::mutex> lock(mutex_);
if (avoidAreaChangeListeners_.find(listener) == avoidAreaChangeListeners_.end()) {
TLOGI(WmsLogTag::WMS_IMMS, "register success");
avoidAreaChangeListeners_.insert(listener);
firstInserted = true;
}
}
if (firstInserted) {
updateRootSceneAvoidAreaCallback_();
}
return WMError::WM_OK;
}
WMError RootScene::UnregisterAvoidAreaChangeListener(const sptr<IAvoidAreaChangedListener>& listener)
{
if (listener == nullptr) {
TLOGE(WmsLogTag::WMS_IMMS, "listener is null");
return WMError::WM_ERROR_NULLPTR;
}
TLOGI(WmsLogTag::WMS_IMMS, "unregister success");
std::lock_guard<std::mutex> lock(mutex_);
avoidAreaChangeListeners_.erase(listener);
return WMError::WM_OK;
}
void RootScene::NotifyAvoidAreaChangeForRoot(const sptr<AvoidArea>& avoidArea, AvoidAreaType type,
const sptr<OccupiedAreaChangeInfo>& info)
{
AvoidArea area = {};
if (avoidArea != nullptr) {
area= *avoidArea;
TLOGD(WmsLogTag::WMS_IMMS, "type %{public}d area %{public}s.", type, avoidArea->ToString().c_str());
}
std::lock_guard<std::mutex> lock(mutex_);
for (auto& listener : avoidAreaChangeListeners_) {
if (listener != nullptr) {
listener->OnAvoidAreaChanged(area, type, info);
}
}
}
WMError RootScene::RegisterOccupiedAreaChangeListener(const sptr<IOccupiedAreaChangeListener>& listener)
{
if (listener == nullptr) {
TLOGE(WmsLogTag::WMS_KEYBOARD, "listener is null");
return WMError::WM_ERROR_NULLPTR;
}
std::lock_guard<std::mutex> lock(occupiedAreaMutex_);
if (occupiedAreaChangeListeners_.find(listener) == occupiedAreaChangeListeners_.end()) {
TLOGI(WmsLogTag::WMS_KEYBOARD, "register success");
occupiedAreaChangeListeners_.insert(listener);
}
return WMError::WM_OK;
}
WMError RootScene::UnregisterOccupiedAreaChangeListener(const sptr<IOccupiedAreaChangeListener>& listener)
{
if (listener == nullptr) {
TLOGE(WmsLogTag::WMS_KEYBOARD, "listener is null");
return WMError::WM_ERROR_NULLPTR;
}
TLOGI(WmsLogTag::WMS_KEYBOARD, "unregister success");
std::lock_guard<std::mutex> lock(occupiedAreaMutex_);
occupiedAreaChangeListeners_.erase(listener);
return WMError::WM_OK;
}
void RootScene::RegisterNotifyWatchFocusActiveChangeCallback(NotifyWatchFocusActiveChangeCallback&& callback)
{
notifyWatchFocusActiveChangeCallback_ = std::move(callback);
}
std::shared_ptr<Rosen::RSNode> RootScene::GetRSNodeByStringID(const std::string& stringId)
{
TLOGI(WmsLogTag::WMS_LAYOUT, "id: %{public}s", stringId.c_str());
if (uiContent_ == nullptr) {
TLOGE(WmsLogTag::WMS_LAYOUT, "uiContent is null, winId: %{public}d", GetWindowId());
return nullptr;
}
TLOGI(WmsLogTag::WMS_LAYOUT, "end");
return uiContent_->GetRSNodeByStringID(stringId);
}
void RootScene::SetTopWindowBoundaryByID(const std::string& stringId)
{
TLOGI(WmsLogTag::WMS_LAYOUT, "id: %{public}s", stringId.c_str());
if (uiContent_ == nullptr) {
TLOGE(WmsLogTag::WMS_LAYOUT, "uiContent is null, winId: %{public}d", GetWindowId());
return;
}
TLOGI(WmsLogTag::WMS_LAYOUT, "end");
uiContent_->SetTopWindowBoundaryByID(stringId);
}
void RootScene::GetExtensionConfig(AAFwk::WantParams& want) const
{
int32_t rootHostWindowType = static_cast<int32_t>(WindowType::WINDOW_TYPE_SCENE_BOARD);
want.SetParam(Extension::ROOT_HOST_WINDOW_TYPE_FIELD, AAFwk::Integer::Box(rootHostWindowType));
}
UIContentResult RootScene::GetUIContentByDisplayId(DisplayId displayId)
{
auto iter = rootSceneMap_.find(displayId);
if (iter == rootSceneMap_.end()) {
TLOGE(WmsLogTag::WMS_FOCUS, "Can not find rootScene, displayId: %{public}" PRIu64, displayId);
return std::make_pair(GetUIContent(), false);
}
if (iter->second != nullptr) {
auto window = iter->second.promote();
if (window != nullptr) {
return std::make_pair(window->GetUIContent(), true);
}
}
return std::make_pair(nullptr, true);
}
void RootScene::AddRootScene(DisplayId displayId, wptr<Window> window)
{
auto iter = rootSceneMap_.find(displayId);
if (iter == rootSceneMap_.end()) {
rootSceneMap_.emplace(displayId, window);
TLOGI(WmsLogTag::WMS_FOCUS, "insert rootScene, displayId: %{public}" PRIu64, displayId);
} else {
iter->second = window;
TLOGI(WmsLogTag::WMS_FOCUS, "update rootScene, displayId: %{public}" PRIu64, displayId);
}
}
void RootScene::RemoveRootScene(DisplayId displayId)
{
TLOGI(WmsLogTag::WMS_FOCUS, "displayId: %{public}" PRIu64, displayId);
auto iter = rootSceneMap_.find(displayId);
if (iter == rootSceneMap_.end()) {
TLOGE(WmsLogTag::WMS_FOCUS, "Can not find rootScene, displayId: %{public}" PRIu64, displayId);
return;
}
rootSceneMap_.erase(displayId);
}
std::shared_ptr<RSUIDirector> RootScene::GetRSUIDirector() const
{
RETURN_IF_RS_CLIENT_MULTI_INSTANCE_DISABLED(nullptr);
sptr<Display> display;
if (displayId_ == DISPLAY_ID_INVALID) {
display = DisplayManager::GetInstance().GetDefaultDisplay();
TLOGE(WmsLogTag::WMS_SCB, "displayId is invalid, use default display");
} else {
display = DisplayManager::GetInstance().GetDisplayById(displayId_);
}
if (!display) {
TLOGE(WmsLogTag::WMS_SCB, "display is null, displayId: %{public}" PRIu64, displayId_);
return nullptr;
}
auto screenId = display->GetScreenId();
auto rsUIDirector = ScreenSessionManagerClient::GetInstance().GetRSUIDirector(screenId);
TLOGD(WmsLogTag::WMS_SCB, "%{public}s, screenId: %{public}" PRIu64 ", windowId: %{public}d",
RSAdapterUtil::RSUIDirectorToStr(rsUIDirector).c_str(), screenId, GetWindowId());
return rsUIDirector;
}
std::shared_ptr<RSUIContext> RootScene::GetRSUIContext() const
{
RETURN_IF_RS_CLIENT_MULTI_INSTANCE_DISABLED(nullptr);
auto rsUIDirector = GetRSUIDirector();
auto rsUIContext = rsUIDirector ? rsUIDirector->GetRSUIContext() : nullptr;
TLOGD(WmsLogTag::WMS_SCB, "%{public}s, windowId: %{public}d",
RSAdapterUtil::RSUIContextToStr(rsUIContext).c_str(), GetWindowId());
return rsUIContext;
}
}
}