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 "window_pair.h"
17
18 #include <ability_manager_client.h>
19 #include "common_event_manager.h"
20 #include "minimize_app.h"
21 #include "window_inner_manager.h"
22 #include "window_manager_hilog.h"
23 #include "window_helper.h"
24 #include "surface_draw.h"
25
26 namespace OHOS {
27 namespace Rosen {
28 namespace {
29 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "WindowPair"};
30 const std::string SPLIT_SCREEN_EVENT_NAME = "common.event.SPLIT_SCREEN";
31 const std::map<SplitEventMsgType, std::string> splitEventDataMap {
32 {SplitEventMsgType::MSG_SHOW_PRIMARY, "Primary"},
33 {SplitEventMsgType::MSG_SHOW_SECONDARY, "Secondary"},
34 {SplitEventMsgType::MSG_SHOW_DIVIDER, "common.event.SPLIT_SCREEN.data.show.divider"},
35 {SplitEventMsgType::MSG_DESTROY_DIVIDER, "common.event.SPLIT_SCREEN.data.destroy.divider"}
36 };
37 }
38
~WindowPair()39 WindowPair::~WindowPair()
40 {
41 WLOGD("~WindowPair");
42 Clear();
43 }
44
SendSplitScreenCommonEvent(SplitEventMsgType msgType,int32_t missionId)45 void WindowPair::SendSplitScreenCommonEvent(SplitEventMsgType msgType, int32_t missionId)
46 {
47 std::string data = splitEventDataMap.at(msgType);
48 std::string identity = IPCSkeleton::ResetCallingIdentity();
49 AAFwk::Want want;
50 want.SetAction(SPLIT_SCREEN_EVENT_NAME);
51 want.SetParam("windowMode", data);
52 want.SetParam("missionId", missionId);
53 EventFwk::CommonEventData commonEventData;
54 commonEventData.SetWant(want);
55 EventFwk::CommonEventManager::PublishCommonEvent(commonEventData);
56 // set ipc identity to raw
57 IPCSkeleton::SetCallingIdentity(identity);
58 WLOGD("Send split screen event: %{public}s", data.c_str());
59 }
60
NotifyShowRecent(sptr<WindowNode> node)61 void WindowPair::NotifyShowRecent(sptr<WindowNode> node)
62 {
63 if (node == nullptr) {
64 return;
65 }
66 auto msgType = (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) ?
67 SplitEventMsgType::MSG_SHOW_PRIMARY : SplitEventMsgType::MSG_SHOW_SECONDARY;
68 SendSplitScreenCommonEvent(msgType, node->abilityInfo_.missionId_);
69 }
70
NotifyCreateOrDestroyDivider(sptr<WindowNode> node,bool isDestroy)71 void WindowPair::NotifyCreateOrDestroyDivider(sptr<WindowNode> node, bool isDestroy)
72 {
73 if (node == nullptr) {
74 return;
75 }
76 auto msgType = isDestroy ? SplitEventMsgType::MSG_DESTROY_DIVIDER : SplitEventMsgType::MSG_SHOW_DIVIDER;
77 SendSplitScreenCommonEvent(msgType, node->abilityInfo_.missionId_);
78 }
79
Find(sptr<WindowNode> & node)80 sptr<WindowNode> WindowPair::Find(sptr<WindowNode>& node)
81 {
82 if (node == nullptr) {
83 return nullptr;
84 }
85 if (primary_ != nullptr && primary_->GetWindowId() == node->GetWindowId()) {
86 return primary_;
87 } else if (secondary_ != nullptr && secondary_->GetWindowId() == node->GetWindowId()) {
88 return secondary_;
89 } else if (divider_ != nullptr && divider_->GetWindowId() == node->GetWindowId()) {
90 return divider_;
91 }
92 return nullptr;
93 }
94
IsPaired() const95 bool WindowPair::IsPaired() const
96 {
97 if (primary_ == nullptr || secondary_ == nullptr) {
98 return false;
99 }
100 if (primary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY &&
101 secondary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY &&
102 divider_ != nullptr) {
103 return true;
104 }
105 return false;
106 }
107
SetSplitRatio(float ratio)108 void WindowPair::SetSplitRatio(float ratio)
109 {
110 ratio_ = ratio;
111 }
112
GetSplitRatio() const113 float WindowPair::GetSplitRatio() const
114 {
115 return ratio_;
116 }
117
GetPairStatus() const118 WindowPairStatus WindowPair::GetPairStatus() const
119 {
120 return status_;
121 }
122
GetDividerWindow() const123 sptr<WindowNode> WindowPair::GetDividerWindow() const
124 {
125 return divider_;
126 }
127
IsForbidDockSliceMove() const128 bool WindowPair::IsForbidDockSliceMove() const
129 {
130 if (status_ != WindowPairStatus::STATUS_PAIRED_DONE) {
131 return false;
132 }
133 uint32_t flag = static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_FORBID_SPLIT_MOVE);
134 if (primary_ != nullptr && !(primary_->GetWindowFlags() & flag) && secondary_ != nullptr &&
135 !(secondary_->GetWindowFlags() & flag)) {
136 return false;
137 }
138 return true;
139 }
140
IsDockSliceInExitSplitModeArea(const std::vector<int32_t> & exitSplitPoints)141 bool WindowPair::IsDockSliceInExitSplitModeArea(const std::vector<int32_t>& exitSplitPoints)
142 {
143 if (!IsPaired()) {
144 return false;
145 }
146 int32_t dividerOrigin;
147 Rect rect = divider_->GetWindowRect();
148 if (rect.width_ < rect.height_) {
149 dividerOrigin = rect.posX_;
150 } else {
151 dividerOrigin = rect.posY_; // vertical display
152 }
153 if (dividerOrigin < exitSplitPoints[0] || dividerOrigin > exitSplitPoints[1]) {
154 return true;
155 }
156 return false;
157 }
158
ExitSplitMode()159 void WindowPair::ExitSplitMode()
160 {
161 if (!IsPaired()) {
162 return;
163 }
164 Rect dividerRect = divider_->GetWindowRect();
165 sptr<WindowNode> hideNode, recoveryNode;
166 bool isVertical = (dividerRect.height_ < dividerRect.width_) ? true : false;
167 if ((isVertical && (primary_->GetWindowRect().height_ < secondary_->GetWindowRect().height_)) ||
168 (!isVertical && (primary_->GetWindowRect().width_ < secondary_->GetWindowRect().width_))) {
169 hideNode = primary_;
170 recoveryNode = secondary_;
171 } else {
172 hideNode = secondary_;
173 recoveryNode = primary_;
174 }
175 if (recoveryNode != nullptr) {
176 recoveryNode->SetSnapshot(nullptr);
177 }
178 MinimizeApp::AddNeedMinimizeApp(hideNode, MinimizeReason::SPLIT_QUIT);
179 MinimizeApp::ExecuteMinimizeTargetReasons(MinimizeReason::SPLIT_QUIT);
180 WLOGFI("Exit Split Mode, Minimize Window %{public}u", hideNode->GetWindowId());
181 }
182
Clear()183 void WindowPair::Clear()
184 {
185 WLOGI("Clear window pair.");
186 DumpPairInfo();
187 auto splitModeInfo = (WindowModeSupport::WINDOW_MODE_SUPPORT_SPLIT_PRIMARY |
188 WindowModeSupport::WINDOW_MODE_SUPPORT_SPLIT_SECONDARY);
189 if (primary_ != nullptr && primary_->GetWindowProperty() != nullptr &&
190 primary_->GetWindowToken() != nullptr) {
191 if (primary_->GetModeSupportInfo() == splitModeInfo) {
192 MinimizeApp::AddNeedMinimizeApp(primary_, MinimizeReason::SPLIT_QUIT);
193 MinimizeApp::ExecuteMinimizeTargetReasons(MinimizeReason::SPLIT_QUIT);
194 } else {
195 primary_->GetWindowProperty()->ResumeLastWindowMode();
196 primary_->GetWindowToken()->UpdateWindowMode(primary_->GetWindowMode());
197 }
198 }
199 if (secondary_ != nullptr && secondary_->GetWindowProperty() != nullptr &&
200 secondary_->GetWindowToken() != nullptr) {
201 if (secondary_->GetModeSupportInfo() == splitModeInfo) {
202 MinimizeApp::AddNeedMinimizeApp(secondary_, MinimizeReason::SPLIT_QUIT);
203 MinimizeApp::ExecuteMinimizeTargetReasons(MinimizeReason::SPLIT_QUIT);
204 } else {
205 secondary_->GetWindowProperty()->ResumeLastWindowMode();
206 secondary_->GetWindowToken()->UpdateWindowMode(secondary_->GetWindowMode());
207 }
208 }
209
210 primary_ = nullptr;
211 secondary_ = nullptr;
212 if (divider_ != nullptr) {
213 NotifyCreateOrDestroyDivider(divider_, true);
214 divider_ = nullptr;
215 }
216 status_ = WindowPairStatus::STATUS_EMPTY;
217 }
218
IsSplitRelated(sptr<WindowNode> & node) const219 bool WindowPair::IsSplitRelated(sptr<WindowNode>& node) const
220 {
221 if (node == nullptr) {
222 return false;
223 }
224 return WindowHelper::IsSplitWindowMode((node->GetWindowMode())) ||
225 (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE);
226 }
227
GetOrderedPair(sptr<WindowNode> & node)228 std::vector<sptr<WindowNode>> WindowPair::GetOrderedPair(sptr<WindowNode>& node)
229 {
230 WLOGI("Get paired node in Z order");
231 std::vector<sptr<WindowNode>> orderedPair;
232 if (node == nullptr || Find(node) == nullptr) {
233 return orderedPair;
234 }
235 if (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY ||
236 node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) {
237 // primary secondary
238 if (primary_ != nullptr && WindowHelper::IsAppWindow(primary_->GetWindowType())) {
239 orderedPair.push_back(primary_);
240 }
241 if (secondary_ != nullptr && WindowHelper::IsAppWindow(secondary_->GetWindowType())) {
242 orderedPair.push_back(secondary_);
243 }
244 } else if (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) {
245 // secondary primary divider
246 if (secondary_ != nullptr && WindowHelper::IsAppWindow(secondary_->GetWindowType())) {
247 orderedPair.push_back(secondary_);
248 }
249 if (primary_ != nullptr && WindowHelper::IsAppWindow(primary_->GetWindowType())) {
250 orderedPair.push_back(primary_);
251 }
252 }
253 if (divider_ != nullptr) {
254 orderedPair.push_back(divider_);
255 }
256 return orderedPair;
257 }
258
GetPairedWindows()259 std::vector<sptr<WindowNode>> WindowPair::GetPairedWindows()
260 {
261 WLOGD("Get primary and secondary of window pair");
262 std::vector<sptr<WindowNode>> pairWindows;
263 if (status_ == WindowPairStatus::STATUS_PAIRED_DONE && primary_ != nullptr && secondary_ != nullptr) {
264 pairWindows = {primary_, secondary_};
265 }
266 return pairWindows;
267 }
268
UpdateIfSplitRelated(sptr<WindowNode> & node)269 void WindowPair::UpdateIfSplitRelated(sptr<WindowNode>& node)
270 {
271 if (node == nullptr) {
272 return;
273 }
274 if (Find(node) == nullptr && !IsSplitRelated(node)) {
275 WLOGI("Window id: %{public}u is not split related and paired.", node->GetWindowId());
276 return;
277 }
278 if ((node->GetWindowType() == WindowType::WINDOW_TYPE_PLACEHOLDER) &&
279 ((primary_ != nullptr && primary_->GetWindowMode() == node->GetWindowMode()) ||
280 (secondary_ != nullptr && secondary_->GetWindowMode() == node->GetWindowMode()))) {
281 WindowInnerManager::GetInstance().DestroyInnerWindow(displayId_, WindowType::WINDOW_TYPE_PLACEHOLDER);
282 return;
283 }
284 WLOGI("Current status: %{public}u, window id: %{public}u mode: %{public}u",
285 status_, node->GetWindowId(), node->GetWindowMode());
286 if (status_ == WindowPairStatus::STATUS_EMPTY) {
287 Insert(node);
288 if (!isAllSplitAppWindowsRestoring_) {
289 WindowMode holderMode = node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY ?
290 WindowMode::WINDOW_MODE_SPLIT_SECONDARY : WindowMode::WINDOW_MODE_SPLIT_PRIMARY;
291 WindowInnerManager::GetInstance().CreateInnerWindow("place_holder", displayId_, DEFAULT_PLACE_HOLDER_RECT,
292 WindowType::WINDOW_TYPE_PLACEHOLDER, holderMode);
293 // notity systemui to create divider window
294 NotifyShowRecent(node);
295 }
296 } else {
297 if (Find(node) == nullptr) {
298 // add new split related node to pair
299 Insert(node);
300 } else {
301 // handle paired nodes change
302 HandlePairedNodesChange();
303 }
304 }
305 }
306
UpdateWindowPairStatus()307 void WindowPair::UpdateWindowPairStatus()
308 {
309 WLOGI("Update window pair status.");
310 WindowPairStatus prevStatus = status_;
311 if (primary_ != nullptr && secondary_ != nullptr && divider_ != nullptr) {
312 status_ = WindowPairStatus::STATUS_PAIRED_DONE;
313 } else if (primary_ != nullptr && secondary_ != nullptr && divider_ == nullptr) {
314 status_ = WindowPairStatus::STATUS_PAIRING;
315 } else if (primary_ != nullptr && secondary_ == nullptr) {
316 status_ = WindowPairStatus::STATUS_SINGLE_PRIMARY;
317 } else if (primary_ == nullptr && secondary_ != nullptr) {
318 status_ = WindowPairStatus::STATUS_SINGLE_SECONDARY;
319 } else {
320 status_ = WindowPairStatus::STATUS_EMPTY;
321 }
322 if ((prevStatus == WindowPairStatus::STATUS_SINGLE_PRIMARY ||
323 prevStatus == WindowPairStatus::STATUS_SINGLE_SECONDARY || prevStatus == WindowPairStatus::STATUS_EMPTY) &&
324 status_ == WindowPairStatus::STATUS_PAIRING) {
325 // notify systemui to create divider
326 NotifyCreateOrDestroyDivider(primary_, false);
327 } else if ((prevStatus == WindowPairStatus::STATUS_PAIRED_DONE || prevStatus == WindowPairStatus::STATUS_PAIRING) &&
328 (status_ != WindowPairStatus::STATUS_PAIRED_DONE && status_ != WindowPairStatus::STATUS_PAIRING)) {
329 // clear pair
330 Clear();
331 }
332 DumpPairInfo();
333 }
334
SwitchPosition()335 void WindowPair::SwitchPosition()
336 {
337 if (primary_ == nullptr || secondary_ == nullptr) {
338 return;
339 }
340 WLOGFI("Switch the pair pos, pri: %{public}u pri-mode: %{public}u, sec: %{public}u sec-mode: %{public}u,",
341 primary_->GetWindowId(), primary_->GetWindowMode(), secondary_->GetWindowId(), secondary_->GetWindowMode());
342 if (primary_->GetWindowMode() == secondary_->GetWindowMode() &&
343 primary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) {
344 primary_->SetWindowMode(WindowMode::WINDOW_MODE_SPLIT_SECONDARY);
345 if (primary_->GetWindowToken() != nullptr) {
346 primary_->GetWindowToken()->UpdateWindowMode(WindowMode::WINDOW_MODE_SPLIT_SECONDARY);
347 }
348 std::swap(primary_, secondary_);
349 } else if (primary_->GetWindowMode() == secondary_->GetWindowMode() &&
350 primary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
351 secondary_->SetWindowMode(WindowMode::WINDOW_MODE_SPLIT_PRIMARY);
352 if (secondary_->GetWindowToken() != nullptr) {
353 secondary_->GetWindowToken()->UpdateWindowMode(WindowMode::WINDOW_MODE_SPLIT_PRIMARY);
354 }
355 std::swap(primary_, secondary_);
356 }
357 }
358
HandlePairedNodesChange()359 void WindowPair::HandlePairedNodesChange()
360 {
361 WLOGI("Update pair node.");
362 if (primary_ != nullptr && !primary_->IsSplitMode()) {
363 primary_ = nullptr;
364 }
365 if (secondary_ != nullptr && !secondary_->IsSplitMode()) {
366 secondary_ = nullptr;
367 }
368 // paired node mode change
369 if (primary_ != nullptr && secondary_ == nullptr &&
370 primary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
371 std::swap(primary_, secondary_);
372 } else if (primary_ == nullptr && secondary_ != nullptr &&
373 secondary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) {
374 std::swap(primary_, secondary_);
375 } else if (primary_ != nullptr && secondary_ != nullptr &&
376 primary_->GetWindowMode() == secondary_->GetWindowMode()) {
377 // switch position
378 SwitchPosition();
379 }
380 UpdateWindowPairStatus();
381 }
382
Insert(sptr<WindowNode> & node)383 void WindowPair::Insert(sptr<WindowNode>& node)
384 {
385 if (node == nullptr) {
386 return;
387 }
388 WLOGI("Insert a window to pair id: %{public}u", node->GetWindowId());
389 sptr<WindowNode> pairedNode;
390 if (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) {
391 pairedNode = primary_;
392 primary_ = node;
393 } else if (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
394 pairedNode = secondary_;
395 secondary_ = node;
396 } else if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) {
397 pairedNode = divider_;
398 divider_ = node;
399 }
400 // minimize invalid paired window
401 if (pairedNode != nullptr && pairedNode->abilityToken_ != nullptr) {
402 MinimizeApp::AddNeedMinimizeApp(pairedNode, MinimizeReason::SPLIT_REPLACE);
403 }
404 UpdateWindowPairStatus();
405 }
406
DumpPairInfo()407 void WindowPair::DumpPairInfo()
408 {
409 if (primary_ != nullptr) {
410 WLOGI("[DumpPairInfo] primary id: %{public}u mode: %{public}u", primary_->GetWindowId(),
411 primary_->GetWindowMode());
412 }
413 if (secondary_ != nullptr) {
414 WLOGI("[DumpPairInfo] secondary id: %{public}u mode: %{public}u", secondary_->GetWindowId(),
415 secondary_->GetWindowMode());
416 }
417 if (divider_ != nullptr) {
418 WLOGI("[DumpPairInfo] divider id: %{public}u mode: %{public}u", divider_->GetWindowId(),
419 divider_->GetWindowMode());
420 }
421 WLOGI("[DumpPairInfo] pair status %{public}u", status_);
422 }
423
HandleRemoveWindow(sptr<WindowNode> & node)424 void WindowPair::HandleRemoveWindow(sptr<WindowNode>& node)
425 {
426 if (node == nullptr) {
427 return;
428 }
429 if (Find(node) == nullptr && node->IsSplitMode()) {
430 WLOGI("Resume unpaired split related window id: %{public}u", node->GetWindowId());
431 if (node->GetWindowProperty() != nullptr && node->GetWindowToken() != nullptr) {
432 node->GetWindowProperty()->ResumeLastWindowMode();
433 node->GetWindowToken()->UpdateWindowMode(node->GetWindowMode());
434 }
435 // target node is not in window pair, need resume mode when remove
436 return;
437 } else if (Find(node) != nullptr) {
438 WLOGI("Pairing window id: %{public}u is remove, clear window pair", node->GetWindowId());
439 Clear();
440 }
441 }
442
RotateDividerWindow(const Rect & rect)443 void WindowPair::RotateDividerWindow(const Rect& rect)
444 {
445 dividerRect_ = rect;
446 // rotate divider when display orientation changed
447 if (divider_ == nullptr) {
448 WLOGE("Rotate divider failed because divider is null");
449 return;
450 }
451 WLOGFD("Rotate divider when display rotate rect:[%{public}d, %{public}d, %{public}u, %{public}u]",
452 rect.posX_, rect.posY_, rect.width_, rect.height_);
453 // update divider dialog window
454 WindowInnerManager::GetInstance().UpdateInnerWindow(displayId_, WindowType::WINDOW_TYPE_DOCK_SLICE,
455 rect.width_, rect.height_);
456 }
457
SetDividerRect(const Rect & rect)458 void WindowPair::SetDividerRect(const Rect& rect)
459 {
460 dividerRect_ = rect;
461 }
462
TakePairSnapshot()463 bool WindowPair::TakePairSnapshot()
464 {
465 if (status_ == WindowPairStatus::STATUS_PAIRED_DONE && primary_ != nullptr && secondary_ != nullptr) {
466 WLOGD("Take pair snapshot id:[%{public}u, %{public}u]", primary_->GetWindowId(), secondary_->GetWindowId());
467 std::shared_ptr<Media::PixelMap> pixelMap;
468 // get pixelmap time out 2000ms
469 if (SurfaceDraw::GetSurfaceSnapshot(primary_->surfaceNode_, pixelMap, 2000)) {
470 primary_->SetSnapshot(pixelMap);
471 }
472 // get pixelmap time out 2000ms
473 if (SurfaceDraw::GetSurfaceSnapshot(secondary_->surfaceNode_, pixelMap, 2000)) {
474 secondary_->SetSnapshot(pixelMap);
475 }
476 return true;
477 }
478 return false;
479 }
480
ClearPairSnapshot()481 void WindowPair::ClearPairSnapshot()
482 {
483 WLOGD("Clear window pair snapshot");
484 if (primary_ != nullptr) {
485 primary_->SetSnapshot(nullptr);
486 }
487 if (secondary_ != nullptr) {
488 secondary_->SetSnapshot(nullptr);
489 }
490 }
491 } // namespace Rosen
492 } // namespace OHOS