1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "starting_window.h"
17 #include <ability_manager_client.h>
18 #include <common/rs_common_def.h>
19 #include <display_manager_service_inner.h>
20 #include <hitrace_meter.h>
21 #include <transaction/rs_transaction.h>
22 
23 #include "display_group_info.h"
24 #include "remote_animation.h"
25 #include "window_helper.h"
26 #include "window_inner_manager.h"
27 #include "window_manager_hilog.h"
28 #include "window_manager_service.h"
29 #include "window_manager_service_utils.h"
30 #include "window_system_effect.h"
31 
32 namespace OHOS {
33 namespace Rosen {
34 namespace {
35 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "StartingWindow"};
36 }
37 
38 const std::map<OHOS::AppExecFwk::DisplayOrientation, Orientation> ABILITY_TO_WMS_ORIENTATION_MAP {
39     {OHOS::AppExecFwk::DisplayOrientation::UNSPECIFIED, Orientation::UNSPECIFIED},
40     {OHOS::AppExecFwk::DisplayOrientation::LANDSCAPE, Orientation::HORIZONTAL},
41     {OHOS::AppExecFwk::DisplayOrientation::PORTRAIT, Orientation::VERTICAL},
42     {OHOS::AppExecFwk::DisplayOrientation::FOLLOWRECENT, Orientation::LOCKED},
43     {OHOS::AppExecFwk::DisplayOrientation::LANDSCAPE_INVERTED, Orientation::REVERSE_HORIZONTAL},
44     {OHOS::AppExecFwk::DisplayOrientation::PORTRAIT_INVERTED, Orientation::REVERSE_VERTICAL},
45     {OHOS::AppExecFwk::DisplayOrientation::AUTO_ROTATION, Orientation::SENSOR},
46     {OHOS::AppExecFwk::DisplayOrientation::AUTO_ROTATION_LANDSCAPE, Orientation::SENSOR_HORIZONTAL},
47     {OHOS::AppExecFwk::DisplayOrientation::AUTO_ROTATION_PORTRAIT, Orientation::SENSOR_VERTICAL},
48     {OHOS::AppExecFwk::DisplayOrientation::AUTO_ROTATION_RESTRICTED, Orientation::AUTO_ROTATION_RESTRICTED},
49     {OHOS::AppExecFwk::DisplayOrientation::AUTO_ROTATION_LANDSCAPE_RESTRICTED,
50         Orientation::AUTO_ROTATION_LANDSCAPE_RESTRICTED},
51     {OHOS::AppExecFwk::DisplayOrientation::AUTO_ROTATION_PORTRAIT_RESTRICTED,
52         Orientation::AUTO_ROTATION_PORTRAIT_RESTRICTED},
53     {OHOS::AppExecFwk::DisplayOrientation::LOCKED, Orientation::LOCKED},
54 };
55 
56 std::recursive_mutex StartingWindow::mutex_;
57 WindowMode StartingWindow::defaultMode_ = WindowMode::WINDOW_MODE_FULLSCREEN;
58 bool StartingWindow::transAnimateEnable_ = true;
59 std::string StartingWindow::uiType_ = "";
60 AnimationConfig StartingWindow::animationConfig_;
61 
CreateWindowNode(const sptr<WindowTransitionInfo> & info,uint32_t winId)62 sptr<WindowNode> StartingWindow::CreateWindowNode(const sptr<WindowTransitionInfo>& info, uint32_t winId)
63 {
64     sptr<WindowProperty> property = InitializeWindowProperty(info, winId);
65     if (property == nullptr) {
66         return nullptr;
67     }
68 
69     sptr<WindowNode> node = new(std::nothrow) WindowNode(property);
70     if (node == nullptr) {
71         return nullptr;
72     }
73 
74     node->stateMachine_.SetWindowId(winId);
75     node->abilityToken_ = info->GetAbilityToken();
76     node->SetWindowSizeLimits(info->GetWindowSizeLimits());
77     node->abilityInfo_.missionId_ = info->GetMissionId();
78     node->abilityInfo_.bundleName_ = info->GetBundleName();
79     node->abilityInfo_.abilityName_ = info->GetAbilityName();
80     uint32_t windowModeSupportType = WindowHelper::ConvertSupportModesToSupportType(info->GetWindowSupportModes());
81     node->SetWindowModeSupportType(windowModeSupportType);
82 
83     if (CreateLeashAndStartingSurfaceNode(node) != WMError::WM_OK) {
84         return nullptr;
85     }
86     node->stateMachine_.TransitionTo(WindowNodeState::STARTING_CREATED);
87     return node;
88 }
89 
InitializeWindowProperty(const sptr<WindowTransitionInfo> & info,uint32_t winId)90 sptr<WindowProperty> StartingWindow::InitializeWindowProperty(const sptr<WindowTransitionInfo>& info, uint32_t winId)
91 {
92     sptr<WindowProperty> property = new(std::nothrow) WindowProperty();
93     if (property == nullptr || info == nullptr) {
94         return nullptr;
95     }
96 
97     property->SetRequestRect(info->GetWindowRect());
98     if (WindowHelper::IsValidWindowMode(info->GetWindowMode())) {
99         property->SetWindowMode(info->GetWindowMode());
100     } else {
101         property->SetWindowMode(defaultMode_);
102     }
103 
104     AppExecFwk::DisplayOrientation displayOrientation = info->GetOrientation();
105     if (ABILITY_TO_WMS_ORIENTATION_MAP.count(displayOrientation) == 0) {
106         WLOGFE("id:%{public}u Do not support this Orientation type", winId);
107         return nullptr;
108     }
109     Orientation orientation = ABILITY_TO_WMS_ORIENTATION_MAP.at(displayOrientation);
110     if (orientation < Orientation::BEGIN || orientation > Orientation::END) {
111         WLOGFE("Set orientation from ability failed");
112         return nullptr;
113     }
114     property->SetRequestedOrientation(orientation);
115 
116     property->SetDisplayId(info->GetDisplayId());
117     property->SetWindowType(info->GetWindowType());
118 
119     ChangePropertyByApiVersion(info, orientation, property);
120     property->SetApiCompatibleVersion(info->GetApiCompatibleVersion());
121     if (info->GetShowFlagWhenLocked()) {
122         if (property->GetApiCompatibleVersion() < 9 || info->isSystemCalling_) { // 9: api version.
123             property->AddWindowFlag(WindowFlag::WINDOW_FLAG_SHOW_WHEN_LOCKED);
124         } else {
125             WLOGFW("Only API 9- or system calling support showing when locked.");
126         }
127     }
128     property->SetWindowId(winId);
129     return property;
130 }
131 
ChangePropertyByApiVersion(const sptr<WindowTransitionInfo> & info,const Orientation orientation,sptr<WindowProperty> & property)132 void StartingWindow::ChangePropertyByApiVersion(const sptr<WindowTransitionInfo>& info,
133     const Orientation orientation, sptr<WindowProperty>& property)
134 {
135     // 10 ArkUI new framework support after API10
136     if (info->GetApiCompatibleVersion() < 10) {
137         auto displayInfo = DisplayGroupInfo::GetInstance().GetDisplayInfo(info->GetDisplayId());
138         if (!(displayInfo && WmsUtils::IsExpectedRotatableWindow(orientation,
139             displayInfo->GetDisplayOrientation(), property->GetWindowMode(), property->GetWindowFlags(), false))) {
140             property->AddWindowFlag(WindowFlag::WINDOW_FLAG_NEED_AVOID);
141         }
142     } else {
143         if (WindowHelper::IsMainWindow(property->GetWindowType())) {
144             SystemBarProperty statusSystemBarProperty(true, 0x00FFFFFF, 0xFF000000);
145             SystemBarProperty navigationSystemBarProperty(true, 0x00FFFFFF, 0xFF000000);
146             property->SetSystemBarProperty(WindowType::WINDOW_TYPE_STATUS_BAR, statusSystemBarProperty);
147             property->SetSystemBarProperty(WindowType::WINDOW_TYPE_NAVIGATION_BAR, navigationSystemBarProperty);
148         }
149     }
150 }
151 
CreateLeashAndStartingSurfaceNode(sptr<WindowNode> & node)152 WMError StartingWindow::CreateLeashAndStartingSurfaceNode(sptr<WindowNode>& node)
153 {
154     struct RSSurfaceNodeConfig rsSurfaceNodeConfig;
155     rsSurfaceNodeConfig.SurfaceNodeName = "leashWindow" + std::to_string(node->GetWindowId());
156     node->leashWinSurfaceNode_ = RSSurfaceNode::Create(rsSurfaceNodeConfig, RSSurfaceNodeType::LEASH_WINDOW_NODE);
157     if (node->leashWinSurfaceNode_ == nullptr) {
158         WLOGFE("create leashWinSurfaceNode failed");
159         return WMError::WM_ERROR_NULLPTR;
160     }
161 
162     rsSurfaceNodeConfig.SurfaceNodeName = "startingWindow" + std::to_string(node->GetWindowId());
163     node->startingWinSurfaceNode_ = RSSurfaceNode::Create(rsSurfaceNodeConfig, RSSurfaceNodeType::STARTING_WINDOW_NODE);
164     if (node->startingWinSurfaceNode_ == nullptr) {
165         WLOGFE("create startingWinSurfaceNode failed");
166         node->leashWinSurfaceNode_ = nullptr;
167         return WMError::WM_ERROR_NULLPTR;
168     }
169     WLOGI("Create leashWinSurfaceNode and startingWinSurfaceNode success with id:%{public}u!", node->GetWindowId());
170     return WMError::WM_OK;
171 }
172 
DrawStartingWindow(sptr<WindowNode> & node,std::shared_ptr<Media::PixelMap> pixelMap,uint32_t bkgColor,bool isColdStart)173 WMError StartingWindow::DrawStartingWindow(sptr<WindowNode>& node,
174     std::shared_ptr<Media::PixelMap> pixelMap, uint32_t bkgColor, bool isColdStart)
175 {
176     if (node == nullptr) {
177         return WMError::WM_ERROR_NULLPTR;
178     }
179     // using snapshot to support hot start since node destroy when hide
180     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "wms:DrawStartingWindow(%u)", node->GetWindowId());
181     Rect rect = node->GetWindowRect();
182     if (RemoteAnimation::CheckRemoteAnimationEnabled(node->GetDisplayId()) && node->leashWinSurfaceNode_) {
183         // hides this node until RSProxyNode send valid context alpha/matrix
184         node->leashWinSurfaceNode_->ResetContextAlpha();
185     }
186     if (!isColdStart) {
187         return WMError::WM_OK;
188     }
189     if (node->startingWinSurfaceNode_ == nullptr) {
190         WLOGFE("no starting Window SurfaceNode!");
191         return WMError::WM_ERROR_NULLPTR;
192     }
193     // set window effect
194     WindowSystemEffect::SetWindowEffect(node);
195     if (pixelMap == nullptr) {
196         SurfaceDraw::DrawColor(node->startingWinSurfaceNode_, rect.width_, rect.height_, bkgColor);
197         return WMError::WM_OK;
198     }
199 
200     WLOGFD("draw background in sperate");
201     SurfaceDraw::DrawImageRect(node->startingWinSurfaceNode_, rect, pixelMap, bkgColor);
202     return WMError::WM_OK;
203 }
204 
SetStartingWindowAnimation(wptr<WindowNode> weak)205 WMError StartingWindow::SetStartingWindowAnimation(wptr<WindowNode> weak)
206 {
207     auto weakNode = weak.promote();
208     if (weakNode == nullptr || !weakNode->startingWinSurfaceNode_) {
209         WLOGFE("windowNode or startingWinSurfaceNode_ is nullptr");
210         return WMError::WM_ERROR_NULLPTR;
211     }
212     StartAsyncTraceArgs(HITRACE_TAG_WINDOW_MANAGER, static_cast<int32_t>(TraceTaskId::START_WINDOW_ANIMATION),
213         "StartingWindowAnimate(%u)", weakNode->GetWindowId());
214     weakNode->startingWinSurfaceNode_->SetAlpha(animationConfig_.startWinAnimationConfig_.opacityStart_);
215     auto execute = [weak]() {
216         auto weakNode = weak.promote();
217         if (weakNode == nullptr) {
218             WLOGFE("windowNode is nullptr");
219             return;
220         }
221         HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "StartingWindow:ExecuteAnimate(%d)",
222             weakNode->GetWindowId());
223         weakNode->startingWinSurfaceNode_->SetAlpha(animationConfig_.startWinAnimationConfig_.opacityEnd_);
224     };
225 
226     auto finish = [weak]() {
227         auto weakNode = weak.promote();
228         if (weakNode == nullptr || weakNode->leashWinSurfaceNode_ == nullptr) {
229             WLOGFE("windowNode or leashWinSurfaceNode_ is nullptr");
230             return;
231         }
232         HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "StartingWindow:AnimateFinish(%d)",
233             weakNode->GetWindowId());
234         WLOGFI("StartingWindow::Replace surfaceNode, id: %{public}u", weakNode->GetWindowId());
235         weakNode->leashWinSurfaceNode_->RemoveChild(weakNode->startingWinSurfaceNode_);
236         weakNode->startingWinSurfaceNode_ = nullptr;
237         RSTransaction::FlushImplicitTransaction();
238         FinishAsyncTraceArgs(HITRACE_TAG_WINDOW_MANAGER, static_cast<int32_t>(TraceTaskId::START_WINDOW_ANIMATION),
239             "StartingWindowAnimate(%u)", weakNode->GetWindowId());
240     };
241     RSNode::Animate(animationConfig_.startWinAnimationConfig_.timingProtocol_,
242         animationConfig_.startWinAnimationConfig_.timingCurve_, execute, finish);
243     RSTransaction::FlushImplicitTransaction();
244     FinishTrace(HITRACE_TAG_WINDOW_MANAGER);
245     return WMError::WM_OK;
246 }
247 
HandleClientWindowCreate(sptr<WindowNode> & node,sptr<IWindow> & window,uint32_t & windowId,const std::shared_ptr<RSSurfaceNode> & surfaceNode,sptr<WindowProperty> & property,int32_t pid,int32_t uid)248 void StartingWindow::HandleClientWindowCreate(sptr<WindowNode>& node, sptr<IWindow>& window,
249     uint32_t& windowId, const std::shared_ptr<RSSurfaceNode>& surfaceNode, sptr<WindowProperty>& property,
250     int32_t pid, int32_t uid)
251 {
252     if (node == nullptr) {
253         WLOGFE("node is nullptr");
254         return;
255     }
256     node->surfaceNode_ = surfaceNode;
257     node->SetWindowToken(window);
258     node->SetCallingPid(pid);
259     node->SetCallingUid(uid);
260     windowId = node->GetWindowId();
261     // test
262     node->stateMachine_.SetWindowId(windowId);
263     node->stateMachine_.SetWindowType(property->GetWindowType());
264     WLOGI("after set Id:%{public}u, requestRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
265         node->GetWindowId(), node->GetRequestRect().posX_, node->GetRequestRect().posY_,
266         node->GetRequestRect().width_, node->GetRequestRect().height_);
267     // Register FirstFrame Callback to rs, replace startwin
268     wptr<WindowNode> weak = node;
269     auto firstFrameCompleteCallback = [weak]() {
270         auto task = [weak]() {
271             FinishAsyncTraceArgs(HITRACE_TAG_WINDOW_MANAGER, static_cast<int32_t>(TraceTaskId::STARTING_WINDOW),
272                 "wms:async:ShowStartingWindow");
273             auto weakNode = weak.promote();
274             if (weakNode == nullptr || weakNode->leashWinSurfaceNode_ == nullptr) {
275                 WLOGFE("windowNode or leashWinSurfaceNode_ is nullptr");
276                 return;
277             }
278             WLOGI("StartingWindow::FirstFrameCallback come, id: %{public}u", weakNode->GetWindowId());
279             if (transAnimateEnable_) {
280                 SetStartingWindowAnimation(weakNode);
281             } else {
282                 weakNode->leashWinSurfaceNode_->RemoveChild(weakNode->startingWinSurfaceNode_);
283                 weakNode->startingWinSurfaceNode_ = nullptr;
284                 RSTransaction::FlushImplicitTransaction();
285                 WLOGFI("StartingWindow::Replace surfaceNode, id: %{public}u", weakNode->GetWindowId());
286             }
287             WindowInnerManager::GetInstance().CompleteFirstFrameDrawing(weakNode);
288             weakNode->firstFrameAvailable_ = true;
289         };
290         WindowManagerService::GetInstance().PostAsyncTask(task, "firstFrameCompleteCallback");
291     };
292     node->surfaceNode_->SetBufferAvailableCallback(firstFrameCompleteCallback);
293     RSTransaction::FlushImplicitTransaction();
294 }
295 
ReleaseStartWinSurfaceNode(sptr<WindowNode> & node)296 void StartingWindow::ReleaseStartWinSurfaceNode(sptr<WindowNode>& node)
297 {
298     std::lock_guard<std::recursive_mutex> lock(mutex_);
299     if (!node->leashWinSurfaceNode_) {
300         WLOGI("cannot release leashwindow since leash is null, id:%{public}u", node->GetWindowId());
301         return;
302     }
303     node->leashWinSurfaceNode_->RemoveChild(node->startingWinSurfaceNode_);
304     node->leashWinSurfaceNode_->RemoveChild(node->closeWinSurfaceNode_);
305     node->leashWinSurfaceNode_->RemoveChild(node->surfaceNode_);
306     node->leashWinSurfaceNode_ = nullptr;
307     node->startingWinSurfaceNode_ = nullptr;
308     node->closeWinSurfaceNode_ = nullptr;
309     WLOGI("Release startwindow surfaceNode end id: %{public}u, [leashWinSurface]: use_count: %{public}ld, \
310         [startWinSurface]: use_count: %{public}ld ", node->GetWindowId(),
311         node->leashWinSurfaceNode_.use_count(), node->startingWinSurfaceNode_.use_count());
312     RSTransaction::FlushImplicitTransaction();
313 }
314 
IsWindowFollowParent(WindowType type)315 bool StartingWindow::IsWindowFollowParent(WindowType type)
316 {
317     auto isPhone = uiType_ == UI_TYPE_PHONE;
318     if (!isPhone) {
319         return false;
320     }
321     return WindowHelper::IsWindowFollowParent(type);
322 }
323 
AddNodeOnRSTree(sptr<WindowNode> & node,bool isMultiDisplay)324 void StartingWindow::AddNodeOnRSTree(sptr<WindowNode>& node, bool isMultiDisplay)
325 {
326     auto updateRSTreeFunc = [&node, isMultiDisplay]() {
327         UpdateRSTree(node, isMultiDisplay);
328     };
329     wptr<WindowNode> weakNode = node;
330     auto finishCallBack = [weakNode]() {
331         auto weak = weakNode.promote();
332         if (weak == nullptr) {
333             return;
334         }
335         auto winRect = weak->GetWindowRect();
336         WLOGI("before setBounds windowRect: %{public}d, %{public}d, %{public}d, %{public}d",
337             winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
338         if (weak->leashWinSurfaceNode_) {
339             weak->leashWinSurfaceNode_->SetBounds(winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
340             weak->leashWinSurfaceNode_->SetAnimationFinished();
341         }
342         RSTransaction::FlushImplicitTransaction();
343     };
344     if (!RemoteAnimation::CheckAnimationController()) {
345         RSNode::Animate(animationConfig_.windowAnimationConfig_.animationTiming_.timingProtocol_,
346             animationConfig_.windowAnimationConfig_.animationTiming_.timingCurve_,
347             updateRSTreeFunc, finishCallBack);
348     } else {
349         // add or remove window without animation
350         updateRSTreeFunc();
351     }
352 }
353 
UpdateRSTree(sptr<WindowNode> & node,bool isMultiDisplay)354 void StartingWindow::UpdateRSTree(sptr<WindowNode>& node, bool isMultiDisplay)
355 {
356     auto& dms = DisplayManagerServiceInner::GetInstance();
357     DisplayId displayId = node->GetDisplayId();
358     if (!node->surfaceNode_) { // cold start
359         if (!WindowHelper::IsMainWindow(node->GetWindowType())) {
360             TLOGE(WmsLogTag::WMS_MAIN, "window id: %{public}d type: %{public}u is not Main Window!",
361                 node->GetWindowId(), static_cast<uint32_t>(node->GetWindowType()));
362         }
363         dms.UpdateRSTree(displayId, displayId, node->leashWinSurfaceNode_, true, isMultiDisplay);
364         node->leashWinSurfaceNode_->AddChild(node->startingWinSurfaceNode_, -1);
365         TLOGD(WmsLogTag::WMS_MAIN, "Add startingWinSurfaceNode_ to leashWinSurfaceNode_ end during cold start");
366         return;
367     }
368     // hot start
369     const auto& displayIdVec = node->GetShowingDisplays();
370     for (auto& shownDisplayId : displayIdVec) {
371         if (node->leashWinSurfaceNode_) { // to app
372             dms.UpdateRSTree(shownDisplayId, shownDisplayId, node->leashWinSurfaceNode_, true, isMultiDisplay);
373         } else { // to launcher
374             dms.UpdateRSTree(shownDisplayId, shownDisplayId, node->surfaceNode_, true, isMultiDisplay);
375         }
376         for (auto& child : node->children_) {
377             if (IsWindowFollowParent(child->GetWindowType())) {
378                 continue;
379             }
380             if (child->currentVisibility_) {
381                 dms.UpdateRSTree(shownDisplayId, shownDisplayId, child->surfaceNode_, true, isMultiDisplay);
382             }
383         }
384     }
385     TLOGD(WmsLogTag::WMS_MAIN, "Update RsTree with hot start");
386 }
387 
SetDefaultWindowMode(WindowMode defaultMode)388 void StartingWindow::SetDefaultWindowMode(WindowMode defaultMode)
389 {
390     defaultMode_ = defaultMode;
391 }
392 
SetAnimationConfig(AnimationConfig config)393 void StartingWindow::SetAnimationConfig(AnimationConfig config)
394 {
395     animationConfig_ = config;
396 }
397 } // Rosen
398 } // OHOS
399