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 "window_system_effect.h"
25 #include "surface_draw.h"
26 
27 namespace OHOS {
28 namespace Rosen {
29 namespace {
30 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "Pair"};
31 const std::string SPLIT_SCREEN_EVENT_NAME = "common.event.SPLIT_SCREEN";
32 const std::map<SplitEventMsgType, std::string> splitEventDataMap {
33     {SplitEventMsgType::MSG_SHOW_PRIMARY,                                           "Primary"},
34     {SplitEventMsgType::MSG_SHOW_SECONDARY,                                       "Secondary"},
35     {SplitEventMsgType::MSG_SHOW_DIVIDER,       "common.event.SPLIT_SCREEN.data.show.divider"},
36     {SplitEventMsgType::MSG_DESTROY_DIVIDER, "common.event.SPLIT_SCREEN.data.destroy.divider"}
37 };
38 }
39 
~WindowPair()40 WindowPair::~WindowPair()
41 {
42     WLOGD("~WindowPair");
43     Clear();
44 }
45 
SendSplitScreenCommonEvent(SplitEventMsgType msgType,int32_t missionId)46 void WindowPair::SendSplitScreenCommonEvent(SplitEventMsgType msgType, int32_t missionId)
47 {
48     std::string data = splitEventDataMap.at(msgType);
49     std::string identity = IPCSkeleton::ResetCallingIdentity();
50     AAFwk::Want want;
51     want.SetAction(SPLIT_SCREEN_EVENT_NAME);
52     want.SetParam("windowMode", data);
53     want.SetParam("missionId", missionId);
54     EventFwk::CommonEventData commonEventData;
55     commonEventData.SetWant(want);
56     EventFwk::CommonEventManager::PublishCommonEvent(commonEventData);
57     // set ipc identity to raw
58     IPCSkeleton::SetCallingIdentity(identity);
59     WLOGD("Send split screen event: %{public}s", data.c_str());
60 }
61 
NotifyShowRecent(sptr<WindowNode> node)62 void WindowPair::NotifyShowRecent(sptr<WindowNode> node)
63 {
64     if (node == nullptr) {
65         return;
66     }
67     auto msgType = (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) ?
68         SplitEventMsgType::MSG_SHOW_PRIMARY : SplitEventMsgType::MSG_SHOW_SECONDARY;
69     SendSplitScreenCommonEvent(msgType, node->abilityInfo_.missionId_);
70 }
71 
NotifyCreateOrDestroyDivider(sptr<WindowNode> node,bool isDestroy)72 void WindowPair::NotifyCreateOrDestroyDivider(sptr<WindowNode> node, bool isDestroy)
73 {
74     if (node == nullptr) {
75         return;
76     }
77     auto msgType = isDestroy ? SplitEventMsgType::MSG_DESTROY_DIVIDER : SplitEventMsgType::MSG_SHOW_DIVIDER;
78     SendSplitScreenCommonEvent(msgType, node->abilityInfo_.missionId_);
79 }
80 
Find(sptr<WindowNode> & node)81 sptr<WindowNode> WindowPair::Find(sptr<WindowNode>& node)
82 {
83     if (node == nullptr) {
84         return nullptr;
85     }
86     if (primary_ != nullptr && primary_->GetWindowId() == node->GetWindowId()) {
87         return primary_;
88     } else if (secondary_ != nullptr && secondary_->GetWindowId() == node->GetWindowId()) {
89         return secondary_;
90     } else if (divider_ != nullptr && divider_->GetWindowId() == node->GetWindowId()) {
91         return divider_;
92     }
93     return nullptr;
94 }
95 
IsPaired() const96 bool WindowPair::IsPaired() const
97 {
98     if (primary_ == nullptr || secondary_ == nullptr) {
99         return false;
100     }
101     if (primary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY &&
102         secondary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY &&
103         divider_ != nullptr) {
104         return true;
105     }
106     return false;
107 }
108 
IsAbnormalStatus() const109 bool WindowPair::IsAbnormalStatus() const
110 {
111     if (status_ == WindowPairStatus::SINGLE_SPLIT || status_ == WindowPairStatus::PRIMARY_AND_DIVIDER ||
112         status_ == WindowPairStatus::SECONDARY_AND_DIVIDER) {
113         return true;
114     } else {
115         return false;
116     }
117 }
118 
SetSplitRatio(float ratio)119 void WindowPair::SetSplitRatio(float ratio)
120 {
121     ratio_ = ratio;
122 }
123 
GetSplitRatio() const124 float WindowPair::GetSplitRatio() const
125 {
126     return ratio_;
127 }
128 
GetPairStatus() const129 WindowPairStatus WindowPair::GetPairStatus() const
130 {
131     return status_;
132 }
133 
GetDividerWindow() const134 sptr<WindowNode> WindowPair::GetDividerWindow() const
135 {
136     return divider_;
137 }
138 
IsForbidDockSliceMove() const139 bool WindowPair::IsForbidDockSliceMove() const
140 {
141     if (status_ != WindowPairStatus::PAIRED_DONE) {
142         return false;
143     }
144     uint32_t flag = static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_FORBID_SPLIT_MOVE);
145     if (primary_ != nullptr && !(primary_->GetWindowFlags() & flag) && secondary_ != nullptr &&
146         !(secondary_->GetWindowFlags() & flag)) {
147         return false;
148     }
149     return true;
150 }
151 
IsDockSliceInExitSplitModeArea(const std::vector<int32_t> & exitSplitPoints)152 bool WindowPair::IsDockSliceInExitSplitModeArea(const std::vector<int32_t>& exitSplitPoints)
153 {
154     if (!IsPaired()) {
155         return false;
156     }
157     int32_t dividerOrigin;
158     Rect rect = divider_->GetWindowRect();
159     if (rect.width_ < rect.height_) {
160         dividerOrigin = rect.posX_;
161     } else {
162         dividerOrigin = rect.posY_; // vertical display
163     }
164     if (dividerOrigin < exitSplitPoints[0] || dividerOrigin > exitSplitPoints[1]) {
165         return true;
166     }
167     return false;
168 }
169 
ExitSplitMode()170 void WindowPair::ExitSplitMode()
171 {
172     if (!IsPaired()) {
173         return;
174     }
175     Rect dividerRect = divider_->GetWindowRect();
176     sptr<WindowNode> hideNode, recoveryNode;
177     bool isVertical = (dividerRect.height_ < dividerRect.width_) ? true : false;
178     if ((isVertical && (primary_->GetWindowRect().height_ < secondary_->GetWindowRect().height_)) ||
179         (!isVertical && (primary_->GetWindowRect().width_ < secondary_->GetWindowRect().width_))) {
180         hideNode = primary_;
181         recoveryNode = secondary_;
182     } else {
183         hideNode = secondary_;
184         recoveryNode = primary_;
185     }
186     if (recoveryNode != nullptr) {
187         recoveryNode->SetSnapshot(nullptr);
188     }
189     MinimizeApp::AddNeedMinimizeApp(hideNode, MinimizeReason::SPLIT_QUIT);
190     MinimizeApp::ExecuteMinimizeTargetReasons(MinimizeReason::SPLIT_QUIT);
191     WLOGI("Exit Split Mode, Minimize Window %{public}u", hideNode->GetWindowId());
192 }
193 
Clear()194 void WindowPair::Clear()
195 {
196     WLOGI("Clear window pair.");
197     DumpPairInfo();
198     auto splitMode = (WindowModeSupport::WINDOW_MODE_SUPPORT_SPLIT_PRIMARY |
199                       WindowModeSupport::WINDOW_MODE_SUPPORT_SPLIT_SECONDARY);
200     if (primary_ != nullptr && primary_->GetWindowProperty() != nullptr &&
201         primary_->GetWindowToken() != nullptr) {
202         if (primary_->GetWindowModeSupportType() == splitMode) {
203             MinimizeApp::AddNeedMinimizeApp(primary_, MinimizeReason::SPLIT_QUIT);
204             MinimizeApp::ExecuteMinimizeTargetReasons(MinimizeReason::SPLIT_QUIT);
205         } else {
206             if (WindowHelper::IsFullScreenWindow(primary_->GetWindowProperty()->GetLastWindowMode()) &&
207                 WindowHelper::IsSplitWindowMode(primary_->GetWindowProperty()->GetWindowMode()) &&
208                 primary_->GetWindowType() != WindowType::WINDOW_TYPE_LAUNCHER_RECENT) {
209                 primary_->SetWindowSizeChangeReason(WindowSizeChangeReason::SPLIT_TO_FULL);
210             }
211             primary_->GetWindowProperty()->ResumeLastWindowMode();
212             // when change mode, need to reset shadow and radius
213             WindowSystemEffect::SetWindowEffect(primary_);
214             primary_->GetWindowToken()->UpdateWindowMode(primary_->GetWindowMode());
215         }
216     }
217     if (secondary_ != nullptr && secondary_->GetWindowProperty() != nullptr &&
218         secondary_->GetWindowToken() != nullptr) {
219         if (secondary_->GetWindowModeSupportType() == splitMode) {
220             MinimizeApp::AddNeedMinimizeApp(secondary_, MinimizeReason::SPLIT_QUIT);
221             MinimizeApp::ExecuteMinimizeTargetReasons(MinimizeReason::SPLIT_QUIT);
222         } else {
223             if (WindowHelper::IsFullScreenWindow(secondary_->GetWindowProperty()->GetLastWindowMode()) &&
224                 WindowHelper::IsSplitWindowMode(secondary_->GetWindowProperty()->GetWindowMode()) &&
225                 secondary_->GetWindowType() != WindowType::WINDOW_TYPE_LAUNCHER_RECENT) {
226                 secondary_->SetWindowSizeChangeReason(WindowSizeChangeReason::SPLIT_TO_FULL);
227             }
228             secondary_->GetWindowProperty()->ResumeLastWindowMode();
229             // when change mode, need to reset shadow and radius
230             WindowSystemEffect::SetWindowEffect(secondary_);
231             secondary_->GetWindowToken()->UpdateWindowMode(secondary_->GetWindowMode());
232         }
233     }
234 
235     primary_ = nullptr;
236     secondary_ = nullptr;
237     if (divider_ != nullptr) {
238         NotifyCreateOrDestroyDivider(divider_, true);
239         divider_ = nullptr;
240     }
241     status_ = WindowPairStatus::EMPTY;
242 }
243 
IsSplitRelated(sptr<WindowNode> & node) const244 bool WindowPair::IsSplitRelated(sptr<WindowNode>& node) const
245 {
246     if (node == nullptr) {
247         return false;
248     }
249     return WindowHelper::IsSplitWindowMode((node->GetWindowMode())) ||
250         (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE);
251 }
252 
CheckOrderedPairZorder(sptr<WindowNode> & node,bool & hasPrimaryDialog,bool & hasSecondaryDialog,bool & isPrimaryAbove)253 void WindowPair::CheckOrderedPairZorder(
254     sptr<WindowNode>& node, bool& hasPrimaryDialog, bool& hasSecondaryDialog, bool& isPrimaryAbove)
255 {
256     if (primary_ != nullptr) {
257         for (auto& child : primary_->children_) {
258             if (child->GetWindowType() == WindowType::WINDOW_TYPE_DIALOG) {
259                 // secondary divider primary
260                 hasPrimaryDialog = true;
261                 isPrimaryAbove = true;
262                 break;
263             }
264         }
265     }
266     if (secondary_ != nullptr) {
267         for (auto& child : secondary_->children_) {
268             if (child->GetWindowType() == WindowType::WINDOW_TYPE_DIALOG) {
269                 // primary divider secondary
270                 hasSecondaryDialog = true;
271                 isPrimaryAbove = false;
272                 break;
273             }
274         }
275     }
276     if (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY ||
277         node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) {
278         // primary secondary divider
279         isPrimaryAbove = false;
280     } else if (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) {
281         // secondary primary divider
282         isPrimaryAbove = true;
283     }
284 
285     return;
286 }
287 
CreateOrderedPair(sptr<WindowNode> & bottom,sptr<WindowNode> & mid,sptr<WindowNode> & top)288 std::vector<sptr<WindowNode>> WindowPair::CreateOrderedPair(
289     sptr<WindowNode>& bottom, sptr<WindowNode>& mid, sptr<WindowNode>& top)
290 {
291     std::vector<sptr<WindowNode>> orderedPair;
292 
293     if (bottom != nullptr) {
294         orderedPair.push_back(bottom);
295     }
296     if (mid != nullptr) {
297         orderedPair.push_back(mid);
298     }
299     if (top != nullptr) {
300         orderedPair.push_back(top);
301     }
302 
303     return orderedPair;
304 }
305 
GetOrderedPair(sptr<WindowNode> & node)306 std::vector<sptr<WindowNode>> WindowPair::GetOrderedPair(sptr<WindowNode>& node)
307 {
308     WLOGI("Get paired node in Z order");
309     std::vector<sptr<WindowNode>> orderedPair;
310     bool hasPrimaryDialog_ = false;
311     bool hasSecondaryDialog_ = false;
312     bool isPrimaryAbove_ = false;
313 
314     if (node == nullptr || Find(node) == nullptr) {
315         return orderedPair;
316     }
317 
318     CheckOrderedPairZorder(node, hasPrimaryDialog_, hasSecondaryDialog_, isPrimaryAbove_);
319 
320     if (hasPrimaryDialog_ && hasSecondaryDialog_) {
321         return CreateOrderedPair(divider_, primary_, secondary_);
322     }
323     if (hasPrimaryDialog_ || hasSecondaryDialog_) {
324         if (isPrimaryAbove_) {
325             return CreateOrderedPair(secondary_, divider_, primary_);
326         } else {
327             return CreateOrderedPair(primary_, divider_, secondary_);
328         }
329     } else {
330         if (isPrimaryAbove_) {
331             return CreateOrderedPair(secondary_, primary_, divider_);
332         } else {
333             return CreateOrderedPair(primary_, secondary_, divider_);
334         }
335     }
336 }
337 
GetPairedWindows()338 std::vector<sptr<WindowNode>> WindowPair::GetPairedWindows()
339 {
340     WLOGD("Get primary and secondary of window pair");
341     std::vector<sptr<WindowNode>> pairWindows;
342     if (status_ == WindowPairStatus::PAIRED_DONE && primary_ != nullptr && secondary_ != nullptr) {
343         pairWindows = {primary_, secondary_};
344     }
345     return pairWindows;
346 }
347 
StatusSupprtedWhenRecentUpdate(sptr<WindowNode> & node)348 bool WindowPair::StatusSupprtedWhenRecentUpdate(sptr<WindowNode>& node)
349 {
350     WindowMode recentMode_ = node->GetWindowMode();
351     if (recentMode_ == WindowMode::WINDOW_MODE_SPLIT_PRIMARY &&
352        (status_ == WindowPairStatus::SINGLE_SECONDARY || status_ == WindowPairStatus::SECONDARY_AND_DIVIDER)) {
353         return true;
354     } else if (recentMode_ == WindowMode::WINDOW_MODE_SPLIT_SECONDARY &&
355         (status_ == WindowPairStatus::SINGLE_PRIMARY || status_ == WindowPairStatus::PRIMARY_AND_DIVIDER)) {
356         return true;
357     }
358     return false;
359 }
360 
UpdateIfSplitRelated(sptr<WindowNode> & node)361 void WindowPair::UpdateIfSplitRelated(sptr<WindowNode>& node)
362 {
363     if (node == nullptr) {
364         return;
365     }
366     if (Find(node) == nullptr && !IsSplitRelated(node)) {
367         WLOGFD("Window id: %{public}u is not split related and paired.", node->GetWindowId());
368         return;
369     }
370     if ((node->GetWindowType() == WindowType::WINDOW_TYPE_PLACEHOLDER) &&
371         ((primary_ != nullptr && primary_->GetWindowMode() == node->GetWindowMode()) ||
372         (secondary_ != nullptr && secondary_->GetWindowMode() == node->GetWindowMode()))) {
373         WindowInnerManager::GetInstance().DestroyInnerWindow(displayId_, WindowType::WINDOW_TYPE_PLACEHOLDER);
374         return;
375     }
376     WLOGI("Current status: %{public}u, window id: %{public}u mode: %{public}u",
377         status_, node->GetWindowId(), node->GetWindowMode());
378     // when status not support to start recent, clear split node and return
379     if (node->GetWindowType() == WindowType::WINDOW_TYPE_LAUNCHER_RECENT && node->IsSplitMode() &&
380         !StatusSupprtedWhenRecentUpdate(node)) {
381         Clear();
382         return;
383     }
384     if (status_ == WindowPairStatus::EMPTY) {
385         Insert(node);
386         if (!isAllSplitAppWindowsRestoring_) {
387             WindowMode holderMode = node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY ?
388                 WindowMode::WINDOW_MODE_SPLIT_SECONDARY : WindowMode::WINDOW_MODE_SPLIT_PRIMARY;
389             WindowInnerManager::GetInstance().CreateInnerWindow("place_holder", displayId_, DEFAULT_PLACE_HOLDER_RECT,
390                 WindowType::WINDOW_TYPE_PLACEHOLDER, holderMode);
391             // notity systemui to create divider window
392             NotifyShowRecent(node);
393         }
394     } else {
395         if (Find(node) == nullptr) {
396             // add new split related node to pair
397             Insert(node);
398         } else {
399             // handle paired nodes change
400             HandlePairedNodesChange();
401         }
402     }
403 }
404 
UpdateWindowPairStatus()405 void WindowPair::UpdateWindowPairStatus()
406 {
407     WLOGI("Update window pair status.");
408     WindowPairStatus prevStatus = status_;
409     if (primary_ != nullptr && secondary_ != nullptr && divider_ != nullptr) {
410         status_ = WindowPairStatus::PAIRED_DONE;
411     } else if (primary_ != nullptr && secondary_ != nullptr && divider_ == nullptr) {
412         status_ = WindowPairStatus::PRIMARY_AND_SECONDARY;
413     } else if (primary_ != nullptr && secondary_ == nullptr && divider_ == nullptr) {
414         status_ = WindowPairStatus::SINGLE_PRIMARY;
415     } else if (primary_ != nullptr && secondary_ == nullptr && divider_ != nullptr) {
416         status_ = WindowPairStatus::PRIMARY_AND_DIVIDER;
417     } else if (primary_ == nullptr && secondary_ != nullptr && divider_ == nullptr) {
418         status_ = WindowPairStatus::SINGLE_SECONDARY;
419     } else if (primary_ == nullptr && secondary_ != nullptr && divider_ != nullptr) {
420         status_ = WindowPairStatus::SECONDARY_AND_DIVIDER;
421     } else if (primary_ == nullptr && secondary_ == nullptr && divider_ != nullptr) {
422         status_ = WindowPairStatus::SINGLE_SPLIT;
423     } else {
424         status_ = WindowPairStatus::EMPTY;
425     }
426     if ((prevStatus == WindowPairStatus::SINGLE_PRIMARY ||
427         prevStatus == WindowPairStatus::SINGLE_SECONDARY || prevStatus == WindowPairStatus::EMPTY) &&
428         status_ == WindowPairStatus::PRIMARY_AND_SECONDARY) {
429         // notify systemui to create divider
430         NotifyCreateOrDestroyDivider(primary_, false);
431     } else if ((prevStatus == WindowPairStatus::PAIRED_DONE || prevStatus == WindowPairStatus::PRIMARY_AND_SECONDARY) &&
432         (status_ != WindowPairStatus::PAIRED_DONE && status_ != WindowPairStatus::PRIMARY_AND_SECONDARY)) {
433         Clear();
434     }
435     DumpPairInfo();
436 }
437 
SwitchPosition()438 void WindowPair::SwitchPosition()
439 {
440     if (primary_ == nullptr || secondary_ == nullptr) {
441         return;
442     }
443     WLOGI("Switch the pair pos, pri: %{public}u pri-mode: %{public}u, sec: %{public}u sec-mode: %{public}u,",
444         primary_->GetWindowId(), primary_->GetWindowMode(), secondary_->GetWindowId(), secondary_->GetWindowMode());
445     if (primary_->GetWindowMode() == secondary_->GetWindowMode() &&
446         primary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) {
447         primary_->SetWindowMode(WindowMode::WINDOW_MODE_SPLIT_SECONDARY);
448         // when change mode, need to reset shadow and radius
449         WindowSystemEffect::SetWindowEffect(primary_);
450         if (primary_->GetWindowToken() != nullptr) {
451             primary_->GetWindowToken()->UpdateWindowMode(WindowMode::WINDOW_MODE_SPLIT_SECONDARY);
452         }
453         std::swap(primary_, secondary_);
454     } else if (primary_->GetWindowMode() == secondary_->GetWindowMode() &&
455         primary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
456         secondary_->SetWindowMode(WindowMode::WINDOW_MODE_SPLIT_PRIMARY);
457         // when change mode, need to reset shadow and radius
458         WindowSystemEffect::SetWindowEffect(secondary_);
459         if (secondary_->GetWindowToken() != nullptr) {
460             secondary_->GetWindowToken()->UpdateWindowMode(WindowMode::WINDOW_MODE_SPLIT_PRIMARY);
461         }
462         std::swap(primary_, secondary_);
463     }
464 }
465 
HandlePairedNodesChange()466 void WindowPair::HandlePairedNodesChange()
467 {
468     WLOGI("Update pair node.");
469     if (primary_ != nullptr && !primary_->IsSplitMode()) {
470         primary_ = nullptr;
471     }
472     if (secondary_ != nullptr && !secondary_->IsSplitMode()) {
473         secondary_ = nullptr;
474     }
475     // paired node mode change
476     if (primary_ != nullptr && secondary_ == nullptr &&
477         primary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
478         std::swap(primary_, secondary_);
479     } else if (primary_ == nullptr && secondary_ != nullptr &&
480         secondary_->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) {
481         std::swap(primary_, secondary_);
482     } else if (primary_ != nullptr && secondary_ != nullptr &&
483         primary_->GetWindowMode() == secondary_->GetWindowMode()) {
484         // switch position
485         SwitchPosition();
486     }
487     UpdateWindowPairStatus();
488     if (IsAbnormalStatus()) {
489         Clear();
490     }
491 }
492 
Insert(sptr<WindowNode> & node)493 void WindowPair::Insert(sptr<WindowNode>& node)
494 {
495     if (node == nullptr) {
496         return;
497     }
498     WLOGI("Insert a window to pair id: %{public}u", node->GetWindowId());
499     sptr<WindowNode> pairedNode;
500     if (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) {
501         pairedNode = primary_;
502         primary_ = node;
503     } else if (node->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
504         pairedNode = secondary_;
505         secondary_ = node;
506     } else if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) {
507         pairedNode = divider_;
508         divider_ = node;
509     }
510     // minimize invalid paired window
511     if (pairedNode != nullptr && pairedNode->abilityToken_ != nullptr) {
512         MinimizeApp::AddNeedMinimizeApp(pairedNode, MinimizeReason::SPLIT_REPLACE);
513     }
514     UpdateWindowPairStatus();
515     if (IsAbnormalStatus()) {
516         Clear();
517     }
518 }
519 
DumpPairInfo()520 void WindowPair::DumpPairInfo()
521 {
522     if (primary_ != nullptr) {
523         WLOGI("[DumpPairInfo] primary id: %{public}u mode: %{public}u", primary_->GetWindowId(),
524             primary_->GetWindowMode());
525     }
526     if (secondary_ != nullptr) {
527         WLOGI("[DumpPairInfo] secondary id: %{public}u mode: %{public}u", secondary_->GetWindowId(),
528             secondary_->GetWindowMode());
529     }
530     if (divider_ != nullptr) {
531         WLOGI("[DumpPairInfo] divider id: %{public}u mode: %{public}u", divider_->GetWindowId(),
532             divider_->GetWindowMode());
533     }
534     WLOGI("[DumpPairInfo] pair status %{public}u", status_);
535 }
536 
HandleRemoveWindow(sptr<WindowNode> & node)537 void WindowPair::HandleRemoveWindow(sptr<WindowNode>& node)
538 {
539     if (node == nullptr) {
540         return;
541     }
542     if (Find(node) == nullptr && node->IsSplitMode()) {
543         WLOGI("Resume unpaired split related window id: %{public}u", node->GetWindowId());
544         if (node->GetWindowProperty() != nullptr && node->GetWindowToken() != nullptr) {
545             node->GetWindowProperty()->ResumeLastWindowMode();
546             // when change mode, need to reset shadow and radius
547             WindowSystemEffect::SetWindowEffect(node);
548             node->GetWindowToken()->UpdateWindowMode(node->GetWindowMode());
549         }
550         // target node is not in window pair, need resume mode when remove
551         return;
552     } else if (Find(node) != nullptr) {
553         WLOGI("Pairing window id: %{public}u is remove, clear window pair", node->GetWindowId());
554         Clear();
555     }
556 }
557 
RotateDividerWindow(const Rect & rect)558 void WindowPair::RotateDividerWindow(const Rect& rect)
559 {
560     dividerRect_ = rect;
561     // rotate divider when display orientation changed
562     if (divider_ == nullptr) {
563         WLOGE("Rotate divider failed because divider is null");
564         return;
565     }
566     WLOGFD("Rotate divider when display rotate rect:[%{public}d, %{public}d, %{public}u, %{public}u]",
567         rect.posX_, rect.posY_, rect.width_, rect.height_);
568 }
569 
SetDividerRect(const Rect & rect)570 void WindowPair::SetDividerRect(const Rect& rect)
571 {
572     dividerRect_ = rect;
573 }
574 
TakePairSnapshot()575 bool WindowPair::TakePairSnapshot()
576 {
577     if (status_ == WindowPairStatus::PAIRED_DONE && primary_ != nullptr && secondary_ != nullptr) {
578         WLOGD("Take pair snapshot id:[%{public}u, %{public}u]", primary_->GetWindowId(), secondary_->GetWindowId());
579         std::shared_ptr<Media::PixelMap> pixelMap;
580         // get pixelmap time out 2000ms
581         if (SurfaceDraw::GetSurfaceSnapshot(primary_->surfaceNode_, pixelMap, SNAPSHOT_TIMEOUT_MS)) {
582             primary_->SetSnapshot(pixelMap);
583         }
584         // get pixelmap time out 2000ms
585         if (SurfaceDraw::GetSurfaceSnapshot(secondary_->surfaceNode_, pixelMap, SNAPSHOT_TIMEOUT_MS)) {
586             secondary_->SetSnapshot(pixelMap);
587         }
588         return true;
589     }
590     return false;
591 }
592 
ClearPairSnapshot()593 void WindowPair::ClearPairSnapshot()
594 {
595     WLOGD("Clear window pair snapshot");
596     if (primary_ != nullptr) {
597         primary_->SetSnapshot(nullptr);
598     }
599     if (secondary_ != nullptr) {
600         secondary_->SetSnapshot(nullptr);
601     }
602 }
603 
GetSplitRatioPoint(float ratio,const Rect & displayRect)604 int32_t WindowPair::GetSplitRatioPoint(float ratio, const Rect& displayRect)
605 {
606     if (displayRect.width_ > displayRect.height_) {
607         return displayRect.posX_ +
608             static_cast<uint32_t>((displayRect.width_ - dividerRect_.width_) * ratio);
609     } else {
610         return displayRect.posY_ +
611             static_cast<uint32_t>((displayRect.height_ - dividerRect_.height_) * ratio);
612     }
613 }
614 
CalculateSplitRatioPoints(const Rect & displayRect)615 void WindowPair::CalculateSplitRatioPoints(const Rect& displayRect)
616 {
617     exitSplitPoints_.clear();
618     splitRatioPoints_.clear();
619     exitSplitPoints_.push_back(GetSplitRatioPoint(splitRatioConfig_.exitSplitStartRatio, displayRect));
620     exitSplitPoints_.push_back(GetSplitRatioPoint(splitRatioConfig_.exitSplitEndRatio, displayRect));
621     for (const auto& ratio : splitRatioConfig_.splitRatios) {
622         splitRatioPoints_.push_back(GetSplitRatioPoint(ratio, displayRect));
623     }
624 }
625 
SetSplitRatioConfig(const SplitRatioConfig & splitRatioConfig)626 void WindowPair::SetSplitRatioConfig(const SplitRatioConfig& splitRatioConfig)
627 {
628     splitRatioConfig_ = splitRatioConfig;
629 }
630 
GetExitSplitPoints()631 std::vector<int32_t> WindowPair::GetExitSplitPoints()
632 {
633     return exitSplitPoints_;
634 }
635 
GetSplitRatioPoints()636 std::vector<int32_t> WindowPair::GetSplitRatioPoints()
637 {
638     return splitRatioPoints_;
639 }
640 
IsDuringSplit()641 bool WindowPair::IsDuringSplit()
642 {
643     if (status_ == WindowPairStatus::EMPTY) {
644         return false;
645     }
646 
647     if (status_ != WindowPairStatus::PAIRED_DONE || primary_ == nullptr || secondary_ == nullptr) {
648         WLOGFD("missing pairWindows or split status is %{public}u not done", status_);
649         return true;
650     }
651 
652     if (primary_->GetWindowType() == WindowType::WINDOW_TYPE_LAUNCHER_RECENT ||
653         secondary_->GetWindowType() == WindowType::WINDOW_TYPE_LAUNCHER_RECENT) {
654         WLOGFD("split is done, but there is recent");
655         return true;
656     }
657 
658     return false;
659 }
660 } // namespace Rosen
661 } // namespace OHOS