• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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