1 /*
2  * Copyright (c) 2024 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 "multi_screen_manager.h"
17 
18 namespace OHOS::Rosen {
WM_IMPLEMENT_SINGLE_INSTANCE(MultiScreenManager)19 WM_IMPLEMENT_SINGLE_INSTANCE(MultiScreenManager)
20 
21 MultiScreenManager::MultiScreenManager()
22 {
23     TLOGI(WmsLogTag::DMS, "init multi screen manager");
24 }
25 
~MultiScreenManager()26 MultiScreenManager::~MultiScreenManager()
27 {
28     TLOGI(WmsLogTag::DMS, "destructor multi screen manager");
29 }
30 
FilterPhysicalAndVirtualScreen(const std::vector<ScreenId> & allScreenIds,std::vector<ScreenId> & physicalScreenIds,std::vector<ScreenId> & virtualScreenIds)31 void MultiScreenManager::FilterPhysicalAndVirtualScreen(const std::vector<ScreenId>& allScreenIds,
32     std::vector<ScreenId>& physicalScreenIds, std::vector<ScreenId>& virtualScreenIds)
33 {
34     TLOGI(WmsLogTag::DMS, "filter physical and virtual screen enter allScreen size: %{public}u",
35         static_cast<uint32_t>(allScreenIds.size()));
36     sptr<ScreenSession> defaultSession = ScreenSessionManager::GetInstance().GetDefaultScreenSession();
37     if (defaultSession == nullptr) {
38         TLOGE(WmsLogTag::DMS, "fail to get defaultSession");
39         return;
40     }
41     ScreenId defaultScreenId = defaultSession->GetScreenId();
42     for (ScreenId screenId : allScreenIds) {
43         auto screenSession = ScreenSessionManager::GetInstance().GetScreenSession(screenId);
44         if (screenSession == nullptr) {
45             continue;
46         }
47         if (screenSession->GetScreenId() == defaultScreenId) {
48             continue;
49         }
50         if (screenSession->GetMirrorScreenType() == MirrorScreenType::PHYSICAL_MIRROR) {
51             physicalScreenIds.emplace_back(screenId);
52         } else if (screenSession->GetMirrorScreenType() == MirrorScreenType::VIRTUAL_MIRROR) {
53             virtualScreenIds.emplace_back(screenId);
54         } else {
55             TLOGI(WmsLogTag::DMS, "mirror screen type error");
56         }
57     }
58     TLOGI(WmsLogTag::DMS, "filter physical and virtual screen end");
59 }
60 
VirtualScreenMirrorSwitch(const ScreenId mainScreenId,const std::vector<ScreenId> & screenIds,ScreenId & screenGroupId)61 DMError MultiScreenManager::VirtualScreenMirrorSwitch(const ScreenId mainScreenId,
62     const std::vector<ScreenId>& screenIds, ScreenId& screenGroupId)
63 {
64     TLOGI(WmsLogTag::DMS, "virtual screen mirror switch enter size: %{public}u",
65         static_cast<uint32_t>(screenIds.size()));
66     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "dms:VirtualScreenMirrorSwitch start");
67     auto mainScreen = ScreenSessionManager::GetInstance().GetScreenSession(mainScreenId);
68     if (mainScreen == nullptr) {
69         TLOGE(WmsLogTag::DMS, "screen session null fail mainScreenId: %{public}" PRIu64, mainScreenId);
70         return DMError::DM_ERROR_INVALID_PARAM;
71     }
72     DMError ret = ScreenSessionManager::GetInstance().SetMirror(mainScreenId, screenIds);
73     if (ret != DMError::DM_OK) {
74         TLOGE(WmsLogTag::DMS, "virtual screen mirror switch error: %{public}d", ret);
75         return ret;
76     }
77     if (ScreenSessionManager::GetInstance().GetAbstractScreenGroup(mainScreen->groupSmsId_) == nullptr) {
78         TLOGE(WmsLogTag::DMS, "get screen group failed main screenId: %{public}" PRIu64, mainScreenId);
79         return DMError::DM_ERROR_NULLPTR;
80     }
81     screenGroupId = mainScreen->groupSmsId_;
82     TLOGI(WmsLogTag::DMS, "virtual screen mirror switch end");
83     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "dms:VirtualScreenMirrorSwitch end");
84     return ret;
85 }
86 
PhysicalScreenMirrorSwitch(const std::vector<ScreenId> & screenIds)87 DMError MultiScreenManager::PhysicalScreenMirrorSwitch(const std::vector<ScreenId>& screenIds)
88 {
89     sptr<ScreenSession> defaultSession = ScreenSessionManager::GetInstance().GetDefaultScreenSession();
90     if (defaultSession == nullptr) {
91         TLOGE(WmsLogTag::DMS, "fail to get defaultSession");
92         return DMError::DM_ERROR_NULLPTR;
93     }
94     TLOGI(WmsLogTag::DMS, "enter physical screen switch to mirror screen size: %{public}u",
95         static_cast<uint32_t>(screenIds.size()));
96     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "dms:PhysicalScreenMirrorSwitch start");
97     NodeId nodeId = defaultSession->GetDisplayNode() == nullptr ? 0 : defaultSession->GetDisplayNode()->GetId();
98     for (ScreenId physicalScreenId : screenIds) {
99         auto screenSession = ScreenSessionManager::GetInstance().GetScreenSession(physicalScreenId);
100         if (screenSession == nullptr) {
101             continue;
102         }
103         TLOGI(WmsLogTag::DMS, "switch to mirror physical ScreenId: %{public}" PRIu64, physicalScreenId);
104         std::shared_ptr<RSDisplayNode> displayNode = screenSession->GetDisplayNode();
105         if (displayNode != nullptr) {
106             displayNode->RemoveFromTree();
107         }
108         screenSession->ReleaseDisplayNode();
109         RSDisplayNodeConfig config = { screenSession->screenId_, true, nodeId, true };
110         screenSession->CreateDisplayNode(config);
111     }
112     TLOGI(WmsLogTag::DMS, "physical screen switch to mirror end");
113     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "dms:PhysicalScreenMirrorSwitch end");
114     return DMError::DM_OK;
115 }
116 
PhysicalScreenUniqueSwitch(const std::vector<ScreenId> & screenIds)117 DMError MultiScreenManager::PhysicalScreenUniqueSwitch(const std::vector<ScreenId>& screenIds)
118 {
119     TLOGI(WmsLogTag::DMS, "enter physical screen unique switch screen size: %{public}u",
120         static_cast<uint32_t>(screenIds.size()));
121     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "dms:PhysicalScreenUniqueSwitch start");
122     for (ScreenId physicalScreenId : screenIds) {
123         auto screenSession = ScreenSessionManager::GetInstance().GetScreenSession(physicalScreenId);
124         if (screenSession == nullptr) {
125             continue;
126         }
127         TLOGI(WmsLogTag::DMS, "switch to unique physical ScreenId: %{public}" PRIu64, physicalScreenId);
128         std::shared_ptr<RSDisplayNode> displayNode = screenSession->GetDisplayNode();
129         if (displayNode != nullptr) {
130             displayNode->RemoveFromTree();
131         }
132         screenSession->ReleaseDisplayNode();
133         RSDisplayNodeConfig config = { screenSession->screenId_ };
134         screenSession->CreateDisplayNode(config);
135         ScreenSessionManager::GetInstance().OnVirtualScreenChange(physicalScreenId, ScreenEvent::CONNECTED);
136     }
137     TLOGI(WmsLogTag::DMS, "physical screen unique switch end");
138     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "dms:PhysicalScreenUniqueSwitch end");
139     return DMError::DM_OK;
140 }
141 
VirtualScreenUniqueSwitch(sptr<ScreenSession> screenSession,const std::vector<ScreenId> & screenIds)142 DMError MultiScreenManager::VirtualScreenUniqueSwitch(sptr<ScreenSession> screenSession,
143     const std::vector<ScreenId>& screenIds)
144 {
145     if (screenSession == nullptr) {
146         TLOGE(WmsLogTag::DMS, "screenSession is null");
147         return DMError::DM_ERROR_NULLPTR;
148     }
149     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "dms:VirtualScreenUniqueSwitch start");
150     TLOGI(WmsLogTag::DMS, "start virtual screen unique switch size: %{public}u",
151         static_cast<uint32_t>(screenIds.size()));
152     auto group = ScreenSessionManager::GetInstance().GetAbstractScreenGroup(screenSession->groupSmsId_);
153     if (group == nullptr) {
154         group = ScreenSessionManager::GetInstance().AddToGroupLocked(screenSession, true);
155         if (group == nullptr) {
156             TLOGE(WmsLogTag::DMS, "group is nullptr");
157             return DMError::DM_ERROR_NULLPTR;
158         }
159         ScreenSessionManager::GetInstance().NotifyScreenGroupChanged(screenSession->ConvertToScreenInfo(),
160             ScreenGroupChangeEvent::ADD_TO_GROUP);
161     }
162     Point point;
163     std::vector<Point> startPoints;
164     startPoints.insert(startPoints.begin(), screenIds.size(), point);
165     ScreenSessionManager::GetInstance().ChangeScreenGroup(group, screenIds, startPoints,
166         true, ScreenCombination::SCREEN_UNIQUE);
167 
168     for (ScreenId uniqueScreenId : screenIds) {
169         auto uniqueScreen = ScreenSessionManager::GetInstance().GetScreenSession(uniqueScreenId);
170         if (uniqueScreen != nullptr) {
171             uniqueScreen->SetScreenCombination(ScreenCombination::SCREEN_UNIQUE);
172             ScreenSessionManager::GetInstance().NotifyScreenChanged(uniqueScreen->ConvertToScreenInfo(),
173                 ScreenChangeEvent::SCREEN_SWITCH_CHANGE);
174         }
175         // virtual screen create callback to notify scb
176         ScreenSessionManager::GetInstance().OnVirtualScreenChange(uniqueScreenId, ScreenEvent::CONNECTED);
177     }
178     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "dms:VirtualScreenUniqueSwitch end");
179     TLOGI(WmsLogTag::DMS, "virtual screen switch to unique and notify scb end");
180     return DMError::DM_OK;
181 }
182 
UniqueSwitch(const std::vector<ScreenId> & screenIds)183 DMError MultiScreenManager::UniqueSwitch(const std::vector<ScreenId>& screenIds)
184 {
185     DMError switchStatus = DMError::DM_OK;
186     std::vector<ScreenId> virtualScreenIds;
187     std::vector<ScreenId> physicalScreenIds;
188     if (screenIds.empty()) {
189         TLOGI(WmsLogTag::DMS, "mirror to unique switch screen size empty");
190         return switchStatus;
191     }
192     TLOGI(WmsLogTag::DMS, "enter mirror to unique switch screen size: %{public}u",
193         static_cast<uint32_t>(screenIds.size()));
194     FilterPhysicalAndVirtualScreen(screenIds, physicalScreenIds, virtualScreenIds);
195 
196     if (!virtualScreenIds.empty()) {
197         switchStatus = ScreenSessionManager::GetInstance().VirtualScreenUniqueSwitch(virtualScreenIds);
198         TLOGI(WmsLogTag::DMS, "virtual screen switch to unique result: %{public}d", switchStatus);
199     }
200     if (!physicalScreenIds.empty()) {
201         switchStatus = PhysicalScreenUniqueSwitch(physicalScreenIds);
202         TLOGI(WmsLogTag::DMS, "physical screen switch to unique result: %{public}d", switchStatus);
203     }
204     TLOGI(WmsLogTag::DMS, "mirror switch to unique end");
205     return switchStatus;
206 }
207 
MirrorSwitch(const ScreenId mainScreenId,const std::vector<ScreenId> & screenIds,ScreenId & screenGroupId)208 DMError MultiScreenManager::MirrorSwitch(const ScreenId mainScreenId, const std::vector<ScreenId>& screenIds,
209     ScreenId& screenGroupId)
210 {
211     DMError switchStatus = DMError::DM_OK;
212     std::vector<ScreenId> virtualScreenIds;
213     std::vector<ScreenId> physicalScreenIds;
214     if (screenIds.empty()) {
215         TLOGI(WmsLogTag::DMS, "mirror switch screen size empty");
216         return switchStatus;
217     }
218     TLOGI(WmsLogTag::DMS, "enter mirror switch screen size: %{public}u", static_cast<uint32_t>(screenIds.size()));
219     FilterPhysicalAndVirtualScreen(screenIds, physicalScreenIds, virtualScreenIds);
220 
221     if (!virtualScreenIds.empty()) {
222         switchStatus = VirtualScreenMirrorSwitch(mainScreenId, virtualScreenIds, screenGroupId);
223         TLOGI(WmsLogTag::DMS, "virtual screen switch to mirror result: %{public}d", switchStatus);
224     }
225     if (!physicalScreenIds.empty()) {
226         screenGroupId = 1;
227         switchStatus = PhysicalScreenMirrorSwitch(physicalScreenIds);
228         TLOGI(WmsLogTag::DMS, "physical screen switch to mirror result: %{public}d", switchStatus);
229     }
230     TLOGI(WmsLogTag::DMS, "mirror switch end switchStatus: %{public}d", switchStatus);
231     return switchStatus;
232 }
233 } // namespace OHOS::Rosen