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 27namespace OHOS { 28namespace Rosen { 29namespace { 30constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "Pair"}; 31const std::string SPLIT_SCREEN_EVENT_NAME = "common.event.SPLIT_SCREEN"; 32const 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 40WindowPair::~WindowPair() 41{ 42 WLOGD("~WindowPair"); 43 Clear(); 44} 45 46void 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 62void 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 72void 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 81sptr<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 96bool 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 109bool 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 119void WindowPair::SetSplitRatio(float ratio) 120{ 121 ratio_ = ratio; 122} 123 124float WindowPair::GetSplitRatio() const 125{ 126 return ratio_; 127} 128 129WindowPairStatus WindowPair::GetPairStatus() const 130{ 131 return status_; 132} 133 134sptr<WindowNode> WindowPair::GetDividerWindow() const 135{ 136 return divider_; 137} 138 139bool 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 152bool 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 170void 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 194void WindowPair::Clear() 195{ 196 WLOGI("Clear window pair."); 197 DumpPairInfo(); 198 auto splitModeInfo = (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_->GetModeSupportInfo() == splitModeInfo) { 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_->GetModeSupportInfo() == splitModeInfo) { 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 244bool 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 253void 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 288std::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 306std::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 338std::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 348bool 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 361void 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 405void 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 438void 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 466void 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 493void 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 520void 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 537void 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 558void 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 570void WindowPair::SetDividerRect(const Rect& rect) 571{ 572 dividerRect_ = rect; 573} 574 575bool 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 593void 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 604int32_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 615void 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 626void WindowPair::SetSplitRatioConfig(const SplitRatioConfig& splitRatioConfig) 627{ 628 splitRatioConfig_ = splitRatioConfig; 629} 630 631std::vector<int32_t> WindowPair::GetExitSplitPoints() 632{ 633 return exitSplitPoints_; 634} 635 636std::vector<int32_t> WindowPair::GetSplitRatioPoints() 637{ 638 return splitRatioPoints_; 639} 640 641bool 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