1 /*
2 * Copyright (c) 2023-2023 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 "picture_in_picture_controller.h"
17
18 #include <event_handler.h>
19 #include <refbase.h>
20 #include <power_mgr_client.h>
21 #include <transaction/rs_sync_transaction_controller.h>
22 #include "picture_in_picture_manager.h"
23 #include "picture_in_picture_option.h"
24 #include "window_manager_hilog.h"
25 #include "window_option.h"
26 #include "window.h"
27 #include "wm_common.h"
28 #include "singleton_container.h"
29 #include "datashare_predicates.h"
30 #include "datashare_result_set.h"
31 #include "datashare_helper.h"
32 #include "iservice_registry.h"
33 #include "result_set.h"
34 #include "system_ability_definition.h"
35 #include "uri.h"
36
37 namespace OHOS {
38 namespace Rosen {
39 namespace {
40 constexpr int32_t PIP_DESTROY_TIMEOUT = 600;
41 constexpr int32_t PIP_SUCCESS = 1;
42 constexpr int32_t FAILED = 0;
43 constexpr uint32_t PIP_LOW_PRIORITY = 0;
44 constexpr uint32_t PIP_HIGH_PRIORITY = 1;
45 const std::string PIP_CONTENT_PATH = "/system/etc/window/resources/pip_content.abc";
46 const std::string DESTROY_TIMEOUT_TASK = "PipDestroyTimeout";
47 const int DEFAULT_ASPECT_RATIO[] = {16, 9};
48 }
49
GetPipPriority(uint32_t pipTemplateType)50 uint32_t PictureInPictureController::GetPipPriority(uint32_t pipTemplateType)
51 {
52 if (pipTemplateType >= static_cast<uint32_t>(PiPTemplateType::END)) {
53 TLOGE(WmsLogTag::WMS_PIP, "param invalid, pipTemplateType is %{public}d", pipTemplateType);
54 return PIP_LOW_PRIORITY;
55 }
56 if (pipTemplateType == static_cast<uint32_t>(PiPTemplateType::VIDEO_PLAY) ||
57 pipTemplateType == static_cast<uint32_t>(PiPTemplateType::VIDEO_LIVE)) {
58 return PIP_LOW_PRIORITY;
59 } else {
60 return PIP_HIGH_PRIORITY;
61 }
62 }
63
PictureInPictureController(sptr<PipOption> pipOption, sptr<Window> mainWindow, uint32_t windowId, napi_env env)64 PictureInPictureController::PictureInPictureController(sptr<PipOption> pipOption, sptr<Window> mainWindow,
65 uint32_t windowId, napi_env env)
66 : weakRef_(this), pipOption_(pipOption), mainWindow_(mainWindow), mainWindowId_(windowId), env_(env)
67 {
68 this->handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
69 curState_ = PiPWindowState::STATE_UNDEFINED;
70 }
71
~PictureInPictureController()72 PictureInPictureController::~PictureInPictureController()
73 {
74 PictureInPictureManager::DetachAutoStartController(handleId_, weakRef_);
75 }
76
CreatePictureInPictureWindow(StartPipType startType)77 WMError PictureInPictureController::CreatePictureInPictureWindow(StartPipType startType)
78 {
79 if (pipOption_ == nullptr || pipOption_->GetContext() == nullptr) {
80 TLOGE(WmsLogTag::WMS_PIP, "Create pip failed, invalid pipOption");
81 return WMError::WM_ERROR_PIP_CREATE_FAILED;
82 }
83 mainWindowXComponentController_ = pipOption_->GetXComponentController();
84 if ((mainWindowXComponentController_ == nullptr && !IsTypeNodeEnabled()) || mainWindow_ == nullptr) {
85 TLOGE(WmsLogTag::WMS_PIP, "mainWindowXComponentController or mainWindow is nullptr");
86 return WMError::WM_ERROR_PIP_CREATE_FAILED;
87 }
88 TLOGI(WmsLogTag::WMS_PIP, "mainWindow:%{public}u, mainWindowState:%{public}u",
89 mainWindowId_, mainWindow_->GetWindowState());
90 mainWindowLifeCycleListener_ = sptr<PictureInPictureController::WindowLifeCycleListener>::MakeSptr();
91 mainWindow_->RegisterLifeCycleListener(mainWindowLifeCycleListener_);
92 if (startType != StartPipType::AUTO_START && mainWindow_->GetWindowState() != WindowState::STATE_SHOWN) {
93 TLOGE(WmsLogTag::WMS_PIP, "mainWindow is not shown. create failed.");
94 return WMError::WM_ERROR_PIP_CREATE_FAILED;
95 }
96 UpdateWinRectByComponent();
97 auto windowOption = sptr<WindowOption>::MakeSptr();
98 windowOption->SetWindowName(PIP_WINDOW_NAME);
99 windowOption->SetWindowType(WindowType::WINDOW_TYPE_PIP);
100 windowOption->SetWindowMode(WindowMode::WINDOW_MODE_PIP);
101 windowOption->SetWindowRect(windowRect_);
102 windowOption->SetKeepScreenOn(true);
103 windowOption->SetTouchable(false);
104 WMError errCode = WMError::WM_OK;
105 PiPTemplateInfo pipTemplateInfo;
106 pipTemplateInfo.pipTemplateType = pipOption_->GetPipTemplate();
107 pipTemplateInfo.controlGroup = pipOption_->GetControlGroup();
108 pipTemplateInfo.priority = GetPipPriority(pipOption_->GetPipTemplate());
109 pipTemplateInfo.pipControlStatusInfoList = pipOption_->GetControlStatus();
110 pipTemplateInfo.pipControlEnableInfoList = pipOption_->GetControlEnable();
111 auto context = static_cast<std::weak_ptr<AbilityRuntime::Context>*>(pipOption_->GetContext());
112 const std::shared_ptr<AbilityRuntime::Context>& abilityContext = context->lock();
113 SingletonContainer::Get<PiPReporter>().SetCurrentPackageName(abilityContext->GetApplicationInfo()->name);
114 sptr<Window> window = Window::CreatePiP(windowOption, pipTemplateInfo, context->lock(), errCode);
115 if (window == nullptr || errCode != WMError::WM_OK) {
116 TLOGW(WmsLogTag::WMS_PIP, "Window create failed, reason: %{public}d", errCode);
117 return WMError::WM_ERROR_PIP_CREATE_FAILED;
118 }
119 window_ = window;
120 window_->UpdatePiPRect(windowRect_, WindowSizeChangeReason::PIP_START);
121 PictureInPictureManager::PutPipControllerInfo(window_->GetWindowId(), this);
122 return WMError::WM_OK;
123 }
124
ShowPictureInPictureWindow(StartPipType startType)125 WMError PictureInPictureController::ShowPictureInPictureWindow(StartPipType startType)
126 {
127 TLOGI(WmsLogTag::WMS_PIP, "startType:%{public}u", startType);
128 if (pipOption_ == nullptr) {
129 TLOGE(WmsLogTag::WMS_PIP, "Get PictureInPicture option failed");
130 return WMError::WM_ERROR_PIP_CREATE_FAILED;
131 }
132 if (window_ == nullptr) {
133 TLOGE(WmsLogTag::WMS_PIP, "window is null when show pip");
134 SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
135 pipOption_->GetPipTemplate(), FAILED, "window is nullptr");
136 return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
137 }
138 for (auto& listener : pipLifeCycleListeners_) {
139 listener->OnPreparePictureInPictureStart();
140 }
141 window_->SetUIContentByAbc(PIP_CONTENT_PATH, env_, nullptr, nullptr);
142 WMError errCode = window_->Show(0, false);
143 if (errCode != WMError::WM_OK) {
144 TLOGE(WmsLogTag::WMS_PIP, "window show failed, err: %{public}u", errCode);
145 for (auto& listener : pipLifeCycleListeners_) {
146 listener->OnPictureInPictureOperationError(static_cast<int32_t>(errCode));
147 }
148 SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
149 pipOption_->GetPipTemplate(), FAILED, "window show failed");
150 return WMError::WM_ERROR_PIP_INTERNAL_ERROR;
151 }
152 uint32_t requestWidth = 0;
153 uint32_t requestHeight = 0;
154 pipOption_->GetContentSize(requestWidth, requestHeight);
155 WindowSizeChangeReason reason = WindowSizeChangeReason::PIP_SHOW;
156 if (startType == StartPipType::AUTO_START) {
157 reason = WindowSizeChangeReason::PIP_AUTO_START;
158 }
159 if (requestWidth > 0 && requestHeight > 0) {
160 Rect requestRect = {0, 0, requestWidth, requestHeight};
161 window_->UpdatePiPRect(requestRect, reason);
162 } else {
163 window_->UpdatePiPRect(windowRect_, reason);
164 }
165 PictureInPictureManager::SetActiveController(this);
166 SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
167 pipOption_->GetPipTemplate(), PIP_SUCCESS, "show pip success");
168 isStoppedFromClient_ = false;
169 return WMError::WM_OK;
170 }
171
StartPictureInPicture(StartPipType startType)172 WMError PictureInPictureController::StartPictureInPicture(StartPipType startType)
173 {
174 TLOGI(WmsLogTag::WMS_PIP, "called");
175 if (pipOption_ == nullptr || pipOption_->GetContext() == nullptr) {
176 TLOGE(WmsLogTag::WMS_PIP, "pipOption is null or Get PictureInPictureOption failed");
177 return WMError::WM_ERROR_PIP_CREATE_FAILED;
178 }
179 if (curState_ == PiPWindowState::STATE_STARTING || curState_ == PiPWindowState::STATE_STARTED) {
180 TLOGW(WmsLogTag::WMS_PIP, "pipWindow is starting, state: %{public}u, id: %{public}u, mainWindow: %{public}u",
181 curState_, (window_ == nullptr) ? INVALID_WINDOW_ID : window_->GetWindowId(), mainWindowId_);
182 SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
183 pipOption_->GetPipTemplate(), FAILED, "Pip window is starting");
184 return WMError::WM_ERROR_PIP_REPEAT_OPERATION;
185 }
186 if (!IsPullPiPAndHandleNavigation()) {
187 TLOGE(WmsLogTag::WMS_PIP, "Navigation operate failed");
188 return WMError::WM_ERROR_PIP_CREATE_FAILED;
189 }
190 curState_ = PiPWindowState::STATE_STARTING;
191 if (PictureInPictureManager::HasActiveController() && !PictureInPictureManager::IsActiveController(weakRef_)) {
192 // if current controller is not the active one, but belongs to the same mainWindow, reserve pipWindow
193 if (PictureInPictureManager::IsAttachedToSameWindow(mainWindowId_)) {
194 window_ = PictureInPictureManager::GetCurrentWindow();
195 if (window_ == nullptr) {
196 TLOGE(WmsLogTag::WMS_PIP, "Reuse pipWindow failed");
197 curState_ = PiPWindowState::STATE_UNDEFINED;
198 return WMError::WM_ERROR_PIP_CREATE_FAILED;
199 }
200 TLOGI(WmsLogTag::WMS_PIP, "Reuse pipWindow: %{public}u as attached to the same mainWindow: %{public}u",
201 window_->GetWindowId(), mainWindowId_);
202 PictureInPictureManager::DoClose(false, false);
203 mainWindowXComponentController_ = IsTypeNodeEnabled() ? nullptr : pipOption_->GetXComponentController();
204 UpdateWinRectByComponent();
205 UpdateContentSize(windowRect_.width_, windowRect_.height_);
206 PictureInPictureManager::PutPipControllerInfo(window_->GetWindowId(), this);
207 WMError err = ShowPictureInPictureWindow(startType);
208 if (err != WMError::WM_OK) {
209 curState_ = PiPWindowState::STATE_UNDEFINED;
210 } else {
211 curState_ = PiPWindowState::STATE_STARTED;
212 }
213 return err;
214 }
215 // otherwise, stop the previous one
216 PictureInPictureManager::DoClose(true, true);
217 }
218 return StartPictureInPictureInner(startType);
219 }
220
StartPictureInPictureInner(StartPipType startType)221 WMError PictureInPictureController::StartPictureInPictureInner(StartPipType startType)
222 {
223 WMError errCode = CreatePictureInPictureWindow(startType);
224 if (errCode != WMError::WM_OK) {
225 curState_ = PiPWindowState::STATE_UNDEFINED;
226 TLOGE(WmsLogTag::WMS_PIP, "Create pip window failed, err: %{public}u", errCode);
227 SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(startType),
228 pipOption_->GetPipTemplate(), FAILED, "Create pip window failed");
229 return errCode;
230 }
231 StartPipType type = startType;
232 if (IsTypeNodeEnabled() && startType != StartPipType::AUTO_START) {
233 type = StartPipType::AUTO_START;
234 }
235 errCode = ShowPictureInPictureWindow(type);
236 if (errCode != WMError::WM_OK) {
237 curState_ = PiPWindowState::STATE_UNDEFINED;
238 TLOGE(WmsLogTag::WMS_PIP, "Show pip window failed, err: %{public}u", errCode);
239 SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(type),
240 pipOption_->GetPipTemplate(), FAILED, "Show pip window failed");
241 return errCode;
242 }
243 curState_ = PiPWindowState::STATE_STARTED;
244 SingletonContainer::Get<PiPReporter>().ReportPiPStartWindow(static_cast<int32_t>(type),
245 pipOption_->GetPipTemplate(), PIP_SUCCESS, "start pip success");
246 return WMError::WM_OK;
247 }
248
StopPictureInPictureFromClient()249 WMError PictureInPictureController::StopPictureInPictureFromClient()
250 {
251 if (!window_) {
252 TLOGE(WmsLogTag::WMS_PIP, "window is null");
253 SingletonContainer::Get<PiPReporter>().ReportPiPStopWindow(static_cast<int32_t>(StopPipType::USER_STOP),
254 pipOption_->GetPipTemplate(), FAILED, "window is null");
255 return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
256 }
257 if (curState_ == PiPWindowState::STATE_STOPPING || curState_ == PiPWindowState::STATE_STOPPED ||
258 curState_ == PiPWindowState::STATE_RESTORING) {
259 TLOGE(WmsLogTag::WMS_PIP, "Repeat stop request, curState: %{public}u", curState_);
260 SingletonContainer::Get<PiPReporter>().ReportPiPStopWindow(static_cast<int32_t>(StopPipType::USER_STOP),
261 pipOption_->GetPipTemplate(), FAILED, "Repeat stop request");
262 return WMError::WM_ERROR_PIP_REPEAT_OPERATION;
263 }
264 isStoppedFromClient_ = true;
265 WMError res = window_->NotifyPrepareClosePiPWindow();
266 if (res != WMError::WM_OK) {
267 SingletonContainer::Get<PiPReporter>().ReportPiPStopWindow(static_cast<int32_t>(StopPipType::USER_STOP),
268 pipOption_->GetPipTemplate(), FAILED, "window destroy failed");
269 return WMError::WM_ERROR_PIP_DESTROY_FAILED;
270 }
271 curState_ = PiPWindowState::STATE_STOPPING;
272 return res;
273 }
274
StopPictureInPicture(bool destroyWindow, StopPipType stopPipType, bool withAnim)275 WMError PictureInPictureController::StopPictureInPicture(bool destroyWindow, StopPipType stopPipType, bool withAnim)
276 {
277 TLOGI(WmsLogTag::WMS_PIP, "destroyWindow: %{public}u anim: %{public}d", destroyWindow, withAnim);
278 if ((!isStoppedFromClient_ && curState_ == PiPWindowState::STATE_STOPPING) ||
279 curState_ == PiPWindowState::STATE_STOPPED) {
280 TLOGE(WmsLogTag::WMS_PIP, "Repeat stop request, curState: %{public}u", curState_);
281 SingletonContainer::Get<PiPReporter>().ReportPiPStopWindow(static_cast<int32_t>(stopPipType),
282 pipOption_->GetPipTemplate(), FAILED, "Repeat stop request");
283 return WMError::WM_ERROR_PIP_REPEAT_OPERATION;
284 }
285 if (window_ == nullptr) {
286 TLOGE(WmsLogTag::WMS_PIP, "window is nullptr when stop pip");
287 SingletonContainer::Get<PiPReporter>().ReportPiPStopWindow(static_cast<int32_t>(stopPipType),
288 pipOption_->GetPipTemplate(), FAILED, "window_ is nullptr");
289 return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
290 }
291 curState_ = PiPWindowState::STATE_STOPPING;
292 for (auto& listener : pipLifeCycleListeners_) {
293 listener->OnPreparePictureInPictureStop();
294 }
295 if (!destroyWindow) {
296 ResetExtController();
297 curState_ = PiPWindowState::STATE_STOPPED;
298 for (auto& listener : pipLifeCycleListeners_) {
299 listener->OnPictureInPictureStop();
300 }
301 PictureInPictureManager::RemoveActiveController(weakRef_);
302 PictureInPictureManager::RemovePipControllerInfo(window_->GetWindowId());
303 return WMError::WM_OK;
304 }
305 return StopPictureInPictureInner(stopPipType, withAnim);
306 }
307
StopPictureInPictureInner(StopPipType stopType, bool withAnim)308 WMError PictureInPictureController::StopPictureInPictureInner(StopPipType stopType, bool withAnim)
309 {
310 uint32_t templateType = 0;
311 if (pipOption_ != nullptr) {
312 templateType = pipOption_->GetPipTemplate();
313 }
314 if (window_ == nullptr) {
315 TLOGE(WmsLogTag::WMS_PIP, "window is nullptr in stop pip inner");
316 SingletonContainer::Get<PiPReporter>().ReportPiPStopWindow(static_cast<int32_t>(stopType),
317 templateType, FAILED, "pipController is null");
318 return WMError::WM_ERROR_PIP_INTERNAL_ERROR;
319 }
320 auto syncTransactionController = RSSyncTransactionController::GetInstance();
321 if (syncTransactionController) {
322 syncTransactionController->OpenSyncTransaction();
323 }
324 ResetExtController();
325 if (!withAnim) {
326 DestroyPictureInPictureWindow();
327 } else {
328 // handle destroy timeout
329 if (handler_ == nullptr) {
330 handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
331 }
332 auto timeoutTask = [weakThis = wptr(this)]() {
333 auto pipController = weakThis.promote();
334 if (pipController == nullptr) {
335 TLOGE(WmsLogTag::WMS_PIP, "execute destroy timeout task failed, pipController is null");
336 return;
337 }
338 if (pipController->curState_ == PiPWindowState::STATE_STOPPED) {
339 TLOGI(WmsLogTag::WMS_PIP, "pip window already destroyed");
340 return;
341 }
342 TLOGI(WmsLogTag::WMS_PIP, "DestroyPictureInPictureWindow timeout");
343 pipController->DestroyPictureInPictureWindow();
344 };
345 handler_->PostTask(std::move(timeoutTask), DESTROY_TIMEOUT_TASK, PIP_DESTROY_TIMEOUT);
346 }
347 if (syncTransactionController) {
348 syncTransactionController->CloseSyncTransaction();
349 }
350
351 SingletonContainer::Get<PiPReporter>().ReportPiPStopWindow(static_cast<int32_t>(stopType),
352 templateType, PIP_SUCCESS, "pip window stop success");
353 return WMError::WM_OK;
354 }
355
DestroyPictureInPictureWindow()356 WMError PictureInPictureController::DestroyPictureInPictureWindow()
357 {
358 TLOGI(WmsLogTag::WMS_PIP, "called");
359 handler_->RemoveTask(DESTROY_TIMEOUT_TASK);
360 if (window_ == nullptr) {
361 TLOGE(WmsLogTag::WMS_PIP, "window is nullptr when destroy pip");
362 return WMError::WM_ERROR_PIP_INTERNAL_ERROR;
363 }
364 WmErrorCode ret = WM_JS_TO_ERROR_CODE_MAP.at(window_->Destroy());
365 if (ret != WmErrorCode::WM_OK) {
366 curState_ = PiPWindowState::STATE_UNDEFINED;
367 TLOGE(WmsLogTag::WMS_PIP, "window destroy failed, err:%{public}u", ret);
368 for (auto& listener : pipLifeCycleListeners_) {
369 listener->OnPictureInPictureOperationError(static_cast<int32_t>(ret));
370 }
371 return WMError::WM_ERROR_PIP_DESTROY_FAILED;
372 }
373 PictureInPictureManager::RemoveActiveController(this);
374 PictureInPictureManager::RemovePipControllerInfo(window_->GetWindowId());
375 window_ = nullptr;
376
377 for (auto& listener : pipLifeCycleListeners_) {
378 listener->OnPictureInPictureStop();
379 }
380 curState_ = PiPWindowState::STATE_STOPPED;
381 std::string navId = pipOption_ == nullptr ? "" : pipOption_->GetNavigationId();
382 if (!navId.empty() && mainWindow_ && !IsTypeNodeEnabled()) {
383 auto navController = NavigationController::GetNavigationController(mainWindow_->GetUIContent(), navId);
384 if (navController) {
385 navController->DeletePIPMode(handleId_);
386 TLOGI(WmsLogTag::WMS_PIP, "Delete pip mode id: %{public}d", handleId_);
387 }
388 }
389 if (mainWindow_ != nullptr) {
390 mainWindow_->UnregisterLifeCycleListener(mainWindowLifeCycleListener_);
391 }
392 mainWindowLifeCycleListener_ = nullptr;
393 return WMError::WM_OK;
394 }
395
GetPipWindow() const396 sptr<Window> PictureInPictureController::GetPipWindow() const
397 {
398 return window_;
399 }
400
GetMainWindowId()401 uint32_t PictureInPictureController::GetMainWindowId()
402 {
403 return mainWindowId_;
404 }
405
SetPipWindow(sptr<Window> window)406 void PictureInPictureController::SetPipWindow(sptr<Window> window)
407 {
408 window_ = window;
409 }
410
SetAutoStartEnabled(bool enable)411 void PictureInPictureController::SetAutoStartEnabled(bool enable)
412 {
413 TLOGI(WmsLogTag::WMS_PIP, "enable: %{public}u, mainWindow: %{public}u", enable, mainWindowId_);
414 isAutoStartEnabled_ = enable;
415 if (mainWindow_ == nullptr) {
416 return;
417 }
418 mainWindow_->SetAutoStartPiP(enable);
419 if (isAutoStartEnabled_) {
420 // cache navigation here as we cannot get containerId while BG
421 if (!IsPullPiPAndHandleNavigation()) {
422 TLOGE(WmsLogTag::WMS_PIP, "Navigation operate failed");
423 return;
424 }
425 PictureInPictureManager::AttachAutoStartController(handleId_, weakRef_);
426 } else {
427 PictureInPictureManager::DetachAutoStartController(handleId_, weakRef_);
428 if (IsTypeNodeEnabled()) {
429 TLOGI(WmsLogTag::WMS_PIP, "typeNode enabled");
430 return;
431 }
432 if (!pipOption_) {
433 TLOGE(WmsLogTag::WMS_PIP, "pipOption is null");
434 return;
435 }
436 std::string navId = pipOption_->GetNavigationId();
437 if (!navId.empty()) {
438 auto navController = NavigationController::GetNavigationController(mainWindow_->GetUIContent(), navId);
439 if (navController) {
440 navController->DeletePIPMode(handleId_);
441 TLOGI(WmsLogTag::WMS_PIP, "Delete pip mode id: %{public}d", handleId_);
442 }
443 }
444 }
445 }
446
IsAutoStartEnabled(bool& enable) const447 void PictureInPictureController::IsAutoStartEnabled(bool& enable) const
448 {
449 enable = isAutoStartEnabled_;
450 }
451
GetControllerState()452 PiPWindowState PictureInPictureController::GetControllerState()
453 {
454 return curState_;
455 }
456
UpdateContentSize(int32_t width, int32_t height)457 void PictureInPictureController::UpdateContentSize(int32_t width, int32_t height)
458 {
459 if (width <= 0 || height <= 0) {
460 TLOGE(WmsLogTag::WMS_PIP, "invalid size");
461 return;
462 }
463 pipOption_->SetContentSize(static_cast<uint32_t>(width), static_cast<uint32_t>(height));
464 if (curState_ != PiPWindowState::STATE_STARTED) {
465 TLOGD(WmsLogTag::WMS_PIP, "UpdateContentSize is disabled when state: %{public}u", curState_);
466 return;
467 }
468 if (window_ == nullptr) {
469 TLOGE(WmsLogTag::WMS_PIP, "pipWindow not exist");
470 return;
471 }
472 if (mainWindowXComponentController_ && !IsTypeNodeEnabled()) {
473 float posX = 0;
474 float posY = 0;
475 float newWidth = 0;
476 float newHeight = 0;
477 mainWindowXComponentController_->GetGlobalPosition(posX, posY);
478 mainWindowXComponentController_->GetSize(newWidth, newHeight);
479 bool isSizeChange = IsContentSizeChanged(newWidth, newHeight, posX, posY);
480 if (isSizeChange) {
481 Rect r = {static_cast<int32_t>(posX), static_cast<int32_t>(posY),
482 static_cast<uint32_t>(newWidth), static_cast<uint32_t>(newHeight)};
483 window_->UpdatePiPRect(r, WindowSizeChangeReason::TRANSFORM);
484 }
485 }
486 TLOGI(WmsLogTag::WMS_PIP, "UpdateContentSize window: %{public}u width:%{public}u height:%{public}u",
487 window_->GetWindowId(), width, height);
488 Rect rect = {0, 0, width, height};
489 window_->UpdatePiPRect(rect, WindowSizeChangeReason::PIP_RATIO_CHANGE);
490 SingletonContainer::Get<PiPReporter>().ReportPiPRatio(width, height);
491 }
492
493
UpdatePiPControlStatus(PiPControlType controlType, PiPControlStatus status)494 void PictureInPictureController::UpdatePiPControlStatus(PiPControlType controlType, PiPControlStatus status)
495 {
496 TLOGI(WmsLogTag::WMS_PIP, "controlType:%{public}u, status:%{public}d", controlType, status);
497 if (static_cast<int32_t>(status) < -1) {
498 pipOption_->SetPiPControlEnabled(controlType, status);
499 } else {
500 pipOption_->SetPiPControlStatus(controlType, status);
501 }
502 if (window_ == nullptr) {
503 TLOGE(WmsLogTag::WMS_PIP, "pipWindow not exist");
504 return;
505 }
506 window_->UpdatePiPControlStatus(controlType, status);
507 }
508
IsContentSizeChanged(float width, float height, float posX, float posY)509 bool PictureInPictureController::IsContentSizeChanged(float width, float height, float posX, float posY)
510 {
511 return windowRect_.width_ != static_cast<uint32_t>(width) ||
512 windowRect_.height_ != static_cast<uint32_t>(height) ||
513 windowRect_.posX_ != static_cast<int32_t>(posX) || windowRect_.posY_ != static_cast<int32_t>(posY);
514 }
515
AfterDestroyed()516 void PictureInPictureController::WindowLifeCycleListener::AfterDestroyed()
517 {
518 TLOGI(WmsLogTag::WMS_PIP, "stop picture_in_picture when attached window destroy");
519 PictureInPictureManager::DoClose(true, true);
520 }
521
DoActionEvent(const std::string& actionName, int32_t status)522 void PictureInPictureController::DoActionEvent(const std::string& actionName, int32_t status)
523 {
524 TLOGI(WmsLogTag::WMS_PIP, "actionName: %{public}s", actionName.c_str());
525 SingletonContainer::Get<PiPReporter>().ReportPiPActionEvent(pipOption_->GetPipTemplate(), actionName);
526 for (auto& listener : pipActionObservers_) {
527 listener->OnActionEvent(actionName, status);
528 }
529 if (CONTROL_TYPE_MAP.find(actionName) != CONTROL_TYPE_MAP.end()) {
530 pipOption_->SetPiPControlStatus(CONTROL_TYPE_MAP[actionName], static_cast<PiPControlStatus>(status));
531 }
532 }
533
PreRestorePictureInPicture()534 void PictureInPictureController::PreRestorePictureInPicture()
535 {
536 TLOGI(WmsLogTag::WMS_PIP, "called");
537 curState_ = PiPWindowState::STATE_RESTORING;
538 for (auto& listener : pipLifeCycleListeners_) {
539 listener->OnRestoreUserInterface();
540 }
541 }
542
DoControlEvent(PiPControlType controlType, PiPControlStatus status)543 void PictureInPictureController::DoControlEvent(PiPControlType controlType, PiPControlStatus status)
544 {
545 TLOGI(WmsLogTag::WMS_PIP, "controlType:%{public}u, enabled:%{public}d", controlType, status);
546 if (pipOption_ == nullptr) {
547 TLOGE(WmsLogTag::WMS_PIP, "pipOption_ is nullptr");
548 return;
549 }
550 SingletonContainer::Get<PiPReporter>().ReportPiPControlEvent(pipOption_->GetPipTemplate(), controlType);
551 for (auto& listener : pipControlObservers_) {
552 listener->OnControlEvent(controlType, status);
553 }
554 pipOption_->SetPiPControlStatus(controlType, status);
555 }
556
RestorePictureInPictureWindow()557 void PictureInPictureController::RestorePictureInPictureWindow()
558 {
559 StopPictureInPicture(true, StopPipType::NULL_STOP, true);
560 SingletonContainer::Get<PiPReporter>().ReportPiPRestore();
561 TLOGI(WmsLogTag::WMS_PIP, "restore pip main window finished");
562 }
563
PrepareSource()564 void PictureInPictureController::PrepareSource()
565 {
566 TLOGI(WmsLogTag::WMS_PIP, "in");
567 if (IsTypeNodeEnabled()) {
568 TLOGI(WmsLogTag::WMS_PIP, "typeNode enabled");
569 return;
570 }
571 if (mainWindow_ == nullptr) {
572 TLOGE(WmsLogTag::WMS_PIP, "mainWindow is nullptr");
573 return;
574 }
575 std::string navId = pipOption_->GetNavigationId();
576 if (navId != "") {
577 auto navController = NavigationController::GetNavigationController(mainWindow_->GetUIContent(), navId);
578 if (navController) {
579 navController->PushInPIP(handleId_);
580 TLOGI(WmsLogTag::WMS_PIP, "Push in pip handleId: %{public}d", handleId_);
581 } else {
582 TLOGE(WmsLogTag::WMS_PIP, "navController is nullptr");
583 }
584 }
585 }
586
LocateSource()587 void PictureInPictureController::LocateSource()
588 {
589 TLOGI(WmsLogTag::WMS_PIP, "in");
590 if (window_ == nullptr) {
591 TLOGE(WmsLogTag::WMS_PIP, "window is nullptr");
592 return;
593 }
594 window_->SetTransparent(true);
595 UpdatePiPSourceRect();
596 }
597
UpdateWinRectByComponent()598 void PictureInPictureController::UpdateWinRectByComponent()
599 {
600 if (IsTypeNodeEnabled()) {
601 uint32_t contentWidth = 0;
602 uint32_t contentHeight = 0;
603 pipOption_->GetContentSize(contentWidth, contentHeight);
604 if (contentWidth == 0 || contentHeight == 0) {
605 contentWidth = DEFAULT_ASPECT_RATIO[0];
606 contentHeight = DEFAULT_ASPECT_RATIO[1];
607 }
608 windowRect_.posX_ = 0;
609 windowRect_.posY_ = 0;
610 windowRect_.width_ = contentWidth;
611 windowRect_.height_ = contentHeight;
612 return;
613 }
614 if (!mainWindowXComponentController_) {
615 TLOGE(WmsLogTag::WMS_PIP, "main window xComponent not set");
616 return;
617 }
618 float posX = 0;
619 float posY = 0;
620 float width = 0;
621 float height = 0;
622 mainWindowXComponentController_->GetGlobalPosition(posX, posY);
623 mainWindowXComponentController_->GetSize(width, height);
624 windowRect_.width_ = static_cast<uint32_t>(width);
625 windowRect_.height_ = static_cast<uint32_t>(height);
626 if (windowRect_.width_ == 0 || windowRect_.height_ == 0) {
627 uint32_t contentWidth = 0;
628 uint32_t contentHeight = 0;
629 pipOption_->GetContentSize(contentWidth, contentHeight);
630 windowRect_.width_ = contentWidth;
631 windowRect_.height_ = contentHeight;
632 }
633 windowRect_.posX_ = static_cast<int32_t>(posX);
634 windowRect_.posY_ = static_cast<int32_t>(posY);
635 TLOGD(WmsLogTag::WMS_PIP, "position width: %{public}u, height: %{public}u, posX: %{public}d, posY: %{public}d",
636 windowRect_.width_, windowRect_.height_, windowRect_.posX_, windowRect_.posY_);
637 }
638
UpdatePiPSourceRect() const639 void PictureInPictureController::UpdatePiPSourceRect() const
640 {
641 if (IsTypeNodeEnabled() && window_ != nullptr) {
642 Rect rect = {0, 0, 0, 0};
643 TLOGI(WmsLogTag::WMS_PIP, "use typeNode, unable to locate source rect");
644 window_->UpdatePiPRect(rect, WindowSizeChangeReason::PIP_RESTORE);
645 return;
646 }
647 if (mainWindowXComponentController_ == nullptr || window_ == nullptr) {
648 TLOGE(WmsLogTag::WMS_PIP, "xcomponent controller not valid");
649 return;
650 }
651 float posX = 0;
652 float posY = 0;
653 float width = 0;
654 float height = 0;
655 mainWindowXComponentController_->GetGlobalPosition(posX, posY);
656 mainWindowXComponentController_->GetSize(width, height);
657 Rect rect = { posX, posY, width, height };
658 TLOGI(WmsLogTag::WMS_PIP, "result rect: [%{public}d, %{public}d, %{public}u, %{public}u]",
659 rect.posX_, rect.posY_, rect.width_, rect.height_);
660 window_->UpdatePiPRect(rect, WindowSizeChangeReason::PIP_RESTORE);
661 }
662
ResetExtController()663 void PictureInPictureController::ResetExtController()
664 {
665 TLOGI(WmsLogTag::WMS_PIP, "called");
666 if (IsTypeNodeEnabled()) {
667 TLOGI(WmsLogTag::WMS_PIP, "skip resetExtController as nodeController enabled");
668 return;
669 }
670 if (mainWindowXComponentController_ == nullptr || pipXComponentController_ == nullptr) {
671 TLOGE(WmsLogTag::WMS_PIP, "error when resetExtController, one of the xComponentController is null");
672 return;
673 }
674 XComponentControllerErrorCode errorCode =
675 mainWindowXComponentController_->ResetExtController(pipXComponentController_);
676 if (errorCode != XComponentControllerErrorCode::XCOMPONENT_CONTROLLER_NO_ERROR) {
677 TLOGE(WmsLogTag::WMS_PIP, "swap xComponent failed, errorCode: %{public}u", errorCode);
678 }
679 }
680
SetXComponentController(std::shared_ptr<XComponentController> xComponentController)681 WMError PictureInPictureController::SetXComponentController(std::shared_ptr<XComponentController> xComponentController)
682 {
683 TLOGI(WmsLogTag::WMS_PIP, "called");
684 if (IsTypeNodeEnabled()) {
685 TLOGI(WmsLogTag::WMS_PIP, "skip as nodeController enabled");
686 return WMError::WM_OK;
687 }
688 pipXComponentController_ = xComponentController;
689 if (window_ == nullptr) {
690 TLOGE(WmsLogTag::WMS_PIP, "window is nullptr when set XComponentController");
691 return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
692 }
693 if (mainWindowXComponentController_ == nullptr || pipXComponentController_ == nullptr) {
694 TLOGE(WmsLogTag::WMS_PIP, "error when setXController, one of the xComponentController is null");
695 return WMError::WM_ERROR_PIP_STATE_ABNORMALLY;
696 }
697 XComponentControllerErrorCode errorCode =
698 mainWindowXComponentController_->SetExtController(pipXComponentController_);
699 if (errorCode != XComponentControllerErrorCode::XCOMPONENT_CONTROLLER_NO_ERROR) {
700 TLOGE(WmsLogTag::WMS_PIP, "swap xComponent failed, errorCode: %{public}u", errorCode);
701 return WMError::WM_ERROR_PIP_INTERNAL_ERROR;
702 }
703 OnPictureInPictureStart();
704 return WMError::WM_OK;
705 }
706
OnPictureInPictureStart()707 void PictureInPictureController::OnPictureInPictureStart()
708 {
709 for (auto& listener : pipLifeCycleListeners_) {
710 listener->OnPictureInPictureStart();
711 }
712 }
713
IsTypeNodeEnabled() const714 bool PictureInPictureController::IsTypeNodeEnabled() const
715 {
716 return pipOption_ != nullptr ? pipOption_->IsTypeNodeEnabled() : false;
717 }
718
RegisterPiPLifecycle(const sptr<IPiPLifeCycle>& listener)719 WMError PictureInPictureController::RegisterPiPLifecycle(const sptr<IPiPLifeCycle>& listener)
720 {
721 return RegisterListener(pipLifeCycleListeners_, listener);
722 }
723
RegisterPiPActionObserver(const sptr<IPiPActionObserver>& listener)724 WMError PictureInPictureController::RegisterPiPActionObserver(const sptr<IPiPActionObserver>& listener)
725 {
726 return RegisterListener(pipActionObservers_, listener);
727 }
728
RegisterPiPControlObserver(const sptr<IPiPControlObserver>& listener)729 WMError PictureInPictureController::RegisterPiPControlObserver(const sptr<IPiPControlObserver>& listener)
730 {
731 return RegisterListener(pipControlObservers_, listener);
732 }
733
UnregisterPiPLifecycle(const sptr<IPiPLifeCycle>& listener)734 WMError PictureInPictureController::UnregisterPiPLifecycle(const sptr<IPiPLifeCycle>& listener)
735 {
736 return UnregisterListener(pipLifeCycleListeners_, listener);
737 }
738
UnregisterPiPActionObserver(const sptr<IPiPActionObserver>& listener)739 WMError PictureInPictureController::UnregisterPiPActionObserver(const sptr<IPiPActionObserver>& listener)
740 {
741 return UnregisterListener(pipActionObservers_, listener);
742 }
743
UnregisterPiPControlObserver(const sptr<IPiPControlObserver>& listener)744 WMError PictureInPictureController::UnregisterPiPControlObserver(const sptr<IPiPControlObserver>& listener)
745 {
746 return UnregisterListener(pipControlObservers_, listener);
747 }
748
749 template<typename T>
RegisterListener(std::vector<sptr<T>>& holder, const sptr<T>& listener)750 WMError PictureInPictureController::RegisterListener(std::vector<sptr<T>>& holder, const sptr<T>& listener)
751 {
752 if (listener == nullptr) {
753 TLOGE(WmsLogTag::WMS_PIP, "listener is nullptr");
754 return WMError::WM_ERROR_NULLPTR;
755 }
756 if (std::find(holder.begin(), holder.end(), listener) != holder.end()) {
757 TLOGE(WmsLogTag::WMS_PIP, "Listener already registered");
758 return WMError::WM_OK;
759 }
760 holder.emplace_back(listener);
761 return WMError::WM_OK;
762 }
763
764 template<typename T>
UnregisterListener(std::vector<sptr<T>>& holder, const sptr<T>& listener)765 WMError PictureInPictureController::UnregisterListener(std::vector<sptr<T>>& holder, const sptr<T>& listener)
766 {
767 if (listener == nullptr) {
768 TLOGE(WmsLogTag::WMS_PIP, "listener could not be null");
769 return WMError::WM_ERROR_NULLPTR;
770 }
771 holder.erase(std::remove_if(holder.begin(), holder.end(),
772 [listener](const sptr<T>& registeredListener) {
773 return registeredListener == listener;
774 }), holder.end());
775 return WMError::WM_OK;
776 }
777
IsPullPiPAndHandleNavigation()778 bool PictureInPictureController::IsPullPiPAndHandleNavigation()
779 {
780 if (IsTypeNodeEnabled()) {
781 TLOGI(WmsLogTag::WMS_PIP, "App use typeNode");
782 return true;
783 }
784 if (pipOption_->GetNavigationId() == "") {
785 TLOGI(WmsLogTag::WMS_PIP, "App not use navigation");
786 return true;
787 }
788 if (mainWindow_ == nullptr) {
789 TLOGE(WmsLogTag::WMS_PIP, "Main window init error");
790 return false;
791 }
792 std::string navId = pipOption_->GetNavigationId();
793 auto navController = NavigationController::GetNavigationController(mainWindow_->GetUIContent(), navId);
794 if (navController) {
795 if (navController->IsNavDestinationInTopStack()) {
796 handleId_ = navController->GetTopHandle();
797 if (handleId_ != -1) {
798 TLOGD(WmsLogTag::WMS_PIP, "Top handle id : %{public}d", handleId_);
799 navController->SetInPIPMode(handleId_);
800 return true;
801 } else {
802 TLOGE(WmsLogTag::WMS_PIP, "Get top handle error");
803 return false;
804 }
805 } else {
806 TLOGE(WmsLogTag::WMS_PIP, "Top is not navDestination");
807 return false;
808 }
809 } else {
810 TLOGE(WmsLogTag::WMS_PIP, "Get navController error");
811 }
812 return false;
813 }
814
GetPiPNavigationId()815 std::string PictureInPictureController::GetPiPNavigationId()
816 {
817 return (pipOption_ != nullptr && !IsTypeNodeEnabled()) ? pipOption_->GetNavigationId() : "";
818 }
819
GetCustomNodeController()820 napi_ref PictureInPictureController::GetCustomNodeController()
821 {
822 return pipOption_ == nullptr ? nullptr : pipOption_->GetNodeControllerRef();
823 }
824
GetTypeNode() const825 napi_ref PictureInPictureController::GetTypeNode() const
826 {
827 return pipOption_ == nullptr ? nullptr : pipOption_->GetTypeNodeRef();
828 }
829 } // namespace Rosen
830 } // namespace OHOS