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 <unistd.h>
17 
18 #include "movingphoto_pattern.h"
19 #include "movingphoto_node.h"
20 #include "movingphoto_utils.h"
21 
22 #include "base/image/pixel_map.h"
23 #include "core/components_ng/pattern/image/image_pattern.h"
24 
25 namespace OHOS::Ace::NG {
26 namespace {
27 constexpr int32_t LONG_PRESS_DELAY = 300;
28 constexpr int32_t ANIMATION_DURATION_300 = 300;
29 constexpr int32_t ANIMATION_DURATION_400 = 400;
30 constexpr float NORMAL_SCALE = 1.0f;
31 constexpr float ZOOM_IN_SCALE = 1.1f;
32 constexpr double NORMAL_PLAY_SPEED = 1.0;
33 constexpr int32_t HALF = 2;
34 constexpr int64_t PERIOD_START = 0;
35 constexpr int32_t PREPARE_RETURN = 0;
36 constexpr int64_t VIDEO_PLAYTIME_START_POSITION = 0;
37 constexpr int64_t VIDEO_PLAYTIME_END_POSITION = 3000;
38 constexpr int32_t IMAGE_LOADING_COMPLETE = 0;
39 constexpr int32_t DURATION_FLAG = -1;
40 const std::string THUMBNAIL_MEDIUM_JOINT = "?&oper=thumbnail&width=-1&height=-1&path=";
41 const std::string COVER_POSITION = "cover_positon";
42 const std::string IMAGE_URI = "uri";
43 constexpr int32_t ANALYZER_DELAY_TIME = 100;
44 constexpr int32_t ANALYZER_CAPTURE_DELAY_TIME = 1000;
45 constexpr int32_t AVERAGE_VALUE = 2;
46 }
MovingPhotoPattern(const RefPtr<MovingPhotoController>& controller)47 MovingPhotoPattern::MovingPhotoPattern(const RefPtr<MovingPhotoController>& controller)
48     : instanceId_(Container::CurrentId()), controller_(controller)
49 {}
50 
OnModifyDone()51 void MovingPhotoPattern::OnModifyDone()
52 {
53     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto onModifydone start.");
54     Pattern::OnModifyDone();
55     UpdateImageNode();
56     UpdateVideoNode();
57     if (SystemProperties::GetExtSurfaceEnabled()) {
58         auto pipelineContext = PipelineContext::GetCurrentContext();
59         CHECK_NULL_VOID(pipelineContext);
60         auto host = GetHost();
61         CHECK_NULL_VOID(host);
62         pipelineContext->AddOnAreaChangeNode(host->GetId());
63     }
64     InitEvent();
65     UpdatePlayMode();
66     HandleImageAnalyzerMode();
67 }
68 
OnAttachToFrameNode()69 void MovingPhotoPattern::OnAttachToFrameNode()
70 {
71     auto host = GetHost();
72     CHECK_NULL_VOID(host);
73     auto renderContext = host->GetRenderContext();
74     CHECK_NULL_VOID(renderContext);
75     static RenderContext::ContextParam param = { RenderContext::ContextType::HARDWARE_SURFACE, "MediaPlayerSurface",
76                                                  RenderContext::PatternType::VIDEO };
77     renderContextForMediaPlayer_->InitContext(false, param);
78     renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
79     renderContextForMediaPlayer_->UpdateBackgroundColor(Color::TRANSPARENT);
80     renderContext->SetClipToBounds(true);
81 
82     auto pipelineContext = PipelineContext::GetCurrentContext();
83     CHECK_NULL_VOID(pipelineContext);
84     pipelineContext->AddWindowStateChangedCallback(host->GetId());
85 
86     CHECK_NULL_VOID(controller_);
87     ContainerScope scope(instanceId_);
88     auto context = PipelineContext::GetCurrentContext();
89     CHECK_NULL_VOID(context);
90     auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
91     controller_->SetStartPlaybackImpl([weak = WeakClaim(this), uiTaskExecutor]() {
92         uiTaskExecutor.PostTask(
93             [weak]() {
94                 auto pattern = weak.Upgrade();
95                 CHECK_NULL_VOID(pattern);
96                 ContainerScope scope(pattern->instanceId_);
97                 pattern->StartPlayback();
98             },
99             "ArkUIMovingPhotoStart");
100     });
101 
102     controller_->SetStopPlaybackImpl([weak = WeakClaim(this), uiTaskExecutor]() {
103         uiTaskExecutor.PostTask(
104             [weak]() {
105                 auto pattern = weak.Upgrade();
106                 CHECK_NULL_VOID(pattern);
107                 ContainerScope scope(pattern->instanceId_);
108                 pattern->StopPlayback();
109             },
110             "ArkUIMovingPhotoStop");
111     });
112 
113     RegisterVisibleAreaChange();
114 }
115 
OnDetachFromFrameNode(FrameNode* frameNode)116 void MovingPhotoPattern::OnDetachFromFrameNode(FrameNode* frameNode)
117 {
118     auto id = frameNode->GetId();
119     auto pipeline = AceType::DynamicCast<PipelineContext>(PipelineBase::GetCurrentContext());
120     CHECK_NULL_VOID(pipeline);
121     pipeline->RemoveWindowStateChangedCallback(id);
122     hasVisibleChangeRegistered_ = false;
123 }
124 
OnDetachFromMainTree()125 void MovingPhotoPattern::OnDetachFromMainTree()
126 {
127     auto host = GetHost();
128     CHECK_NULL_VOID(host);
129     if (host->GetNodeStatus() == NodeStatus::BUILDER_NODE_OFF_MAINTREE) {
130         Stop();
131     }
132 }
133 
OnRebuildFrame()134 void MovingPhotoPattern::OnRebuildFrame()
135 {
136     if (!renderSurface_ || !renderSurface_->IsSurfaceValid()) {
137         return;
138     }
139     auto host = GetHost();
140     CHECK_NULL_VOID(host);
141     auto movingPhotoNode = AceType::DynamicCast<MovingPhotoNode>(host);
142     CHECK_NULL_VOID(movingPhotoNode);
143     auto video = AceType::DynamicCast<FrameNode>(movingPhotoNode->GetVideo());
144     CHECK_NULL_VOID(video);
145     auto renderContext = video->GetRenderContext();
146     renderContext->AddChild(renderContextForMediaPlayer_, 0);
147 }
148 
InitEvent()149 void MovingPhotoPattern::InitEvent()
150 {
151     auto host = GetHost();
152     CHECK_NULL_VOID(host);
153     auto gestureHub = host->GetOrCreateGestureEventHub();
154     CHECK_NULL_VOID(gestureHub);
155     if (longPressEvent_) {
156         gestureHub->SetLongPressEvent(longPressEvent_, false, false, LONG_PRESS_DELAY);
157         return;
158     }
159     auto longPressCallback = [weak = WeakClaim(this)](GestureEvent& info) {
160         auto pattern = weak.Upgrade();
161         CHECK_NULL_VOID(pattern);
162         pattern->HandleLongPress(info);
163     };
164     longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressCallback));
165     gestureHub->SetLongPressEvent(longPressEvent_, false, false, LONG_PRESS_DELAY);
166 
167     if (touchEvent_) {
168         gestureHub->AddTouchEvent(touchEvent_);
169         return;
170     }
171     auto touchTask = [weak = WeakClaim(this)](TouchEventInfo& info) {
172         auto pattern = weak.Upgrade();
173         CHECK_NULL_VOID(pattern);
174         pattern->HandleTouchEvent(info);
175     };
176     touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
177     gestureHub->AddTouchEvent(touchEvent_);
178 }
179 
LongPressEventModify(bool status)180 void MovingPhotoPattern::LongPressEventModify(bool status)
181 {
182     auto host = GetHost();
183     CHECK_NULL_VOID(host);
184     auto gestureHub = host->GetOrCreateGestureEventHub();
185     CHECK_NULL_VOID(gestureHub);
186     if (status) {
187         auto longPressCallback = [weak = WeakClaim(this)](GestureEvent& info) {
188             auto pattern = weak.Upgrade();
189             CHECK_NULL_VOID(pattern);
190             pattern->HandleLongPress(info);
191         };
192         longPressEvent_ = MakeRefPtr<LongPressEvent>(std::move(longPressCallback));
193         gestureHub->SetLongPressEvent(longPressEvent_, false, false, LONG_PRESS_DELAY);
194     } else {
195         gestureHub->SetLongPressEvent(nullptr);
196         longPressEvent_ = nullptr;
197     }
198 }
199 
HandleLongPress(GestureEvent& info)200 void MovingPhotoPattern::HandleLongPress(GestureEvent& info)
201 {
202     isFastKeyUp_ = false;
203     if (currentPlayStatus_ == PlaybackStatus::STARTED || !isPrepared_ || isPlayByController_) {
204         return;
205     }
206     if (autoAndRepeatLevel_ == PlaybackMode::NONE && isEnableAnalyzer_) {
207         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "HandleLongPress isEnableAnalyzer_ return.");
208         return;
209     }
210     if (autoAndRepeatLevel_ != PlaybackMode::NONE) {
211         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "HandleLongPress auto&Repeat return.");
212         return;
213     }
214     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto HandleLongPress start.");
215     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
216         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
217         FireMediaPlayerError();
218         return;
219     }
220     if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
221         mediaPlayer_->PrepareAsync();
222     }
223     if (isSetAutoPlayPeriod_ && (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE ||
224         currentPlayStatus_ == PlaybackStatus::PAUSED)) {
225         isSetAutoPlayPeriod_ = false;
226         int32_t duration = DURATION_FLAG;
227         mediaPlayer_->GetDuration(duration);
228         SetAutoPlayPeriod(PERIOD_START, duration);
229     }
230     Start();
231 }
232 
HandleTouchEvent(TouchEventInfo& info)233 void MovingPhotoPattern::HandleTouchEvent(TouchEventInfo& info)
234 {
235     if (currentPlayStatus_ == PlaybackStatus::ERROR) {
236         ResetMediaPlayer();
237     }
238     if (autoAndRepeatLevel_ != PlaybackMode::NONE) {
239         TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "HandleTouchEvent auto&Repeat return.");
240         return;
241     }
242     if (!isPrepared_ || isPlayByController_) {
243         return;
244     }
245     if (autoAndRepeatLevel_ == PlaybackMode::NONE && isEnableAnalyzer_) {
246         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "HandleTouchEvent isEnableAnalyzer_ return.");
247         return;
248     }
249     auto touchList = info.GetChangedTouches();
250     CHECK_NULL_VOID(!touchList.empty());
251     auto touchInfo = touchList.front();
252     auto touchType = touchInfo.GetTouchType();
253     isFastKeyUp_ = false;
254     if (touchType == TouchType::UP || touchType == TouchType::CANCEL) {
255         if (currentPlayStatus_ == PlaybackStatus::STARTED) {
256             PausePlayback();
257         } else if (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE) {
258             currentPlayStatus_ = PlaybackStatus::NONE;
259             StopAnimation();
260         } else {
261             isFastKeyUp_ = true;
262         }
263     }
264 }
265 
UpdateImageNode()266 void MovingPhotoPattern::UpdateImageNode()
267 {
268     if (startAnimationFlag_) {
269         needUpdateImageNode_ = true;
270         return;
271     }
272     auto host = GetHost();
273     CHECK_NULL_VOID(host);
274     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
275     CHECK_NULL_VOID(movingPhoto);
276     auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
277     CHECK_NULL_VOID(image);
278     ACE_UPDATE_NODE_PAINT_PROPERTY(ImageRenderProperty, DynamicMode, DynamicRangeMode::HIGH, image);
279     ACE_UPDATE_NODE_RENDER_CONTEXT(DynamicRangeMode, DynamicRangeMode::HIGH, image);
280     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto set HDR.");
281     auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
282     CHECK_NULL_VOID(layoutProperty);
283     if (!layoutProperty->HasImageSourceInfo()) {
284         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "image info is null.");
285         auto posterLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
286         posterLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
287         image->MarkModifyDone();
288         return;
289     }
290     auto imageSourceInfo = layoutProperty->GetImageSourceInfo().value();
291     auto imageFit = layoutProperty->GetObjectFitValue(ImageFit::COVER);
292     if (!imageSourceInfo.IsValid()) {
293         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "image info is invalid.");
294         auto posterLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
295         posterLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
296         image->MarkModifyDone();
297         return;
298     }
299     if (image) {
300         image->SetDraggable(false);
301         auto imageLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
302         imageLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
303         imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
304         imageLayoutProperty->UpdateImageFit(imageFit);
305         image->MarkModifyDone();
306     }
307     RegisterImageEvent();
308 }
309 
RegisterImageEvent()310 void MovingPhotoPattern::RegisterImageEvent()
311 {
312     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MovingPhoto RegisterImageEvent start.");
313     auto host = GetHost();
314     CHECK_NULL_VOID(host);
315     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
316     CHECK_NULL_VOID(movingPhoto);
317     auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
318     CHECK_NULL_VOID(image);
319     auto imageHub = image->GetEventHub<ImageEventHub>();
320     CHECK_NULL_VOID(imageHub);
321     auto imageCompleteEventCallback = [weak = WeakClaim(this)](const LoadImageSuccessEvent& info) {
322         auto pattern = weak.Upgrade();
323         CHECK_NULL_VOID(pattern);
324         pattern->HandleImageCompleteEvent(info);
325     };
326     imageHub->SetOnComplete(imageCompleteEventCallback);
327 }
328 
HandleImageCompleteEvent(const LoadImageSuccessEvent& info)329 void MovingPhotoPattern::HandleImageCompleteEvent(const LoadImageSuccessEvent& info)
330 {
331     auto loadingStatus = info.GetLoadingStatus();
332     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "HandleImageCompleteEvent start:%{public}d.", loadingStatus);
333     if (loadingStatus == IMAGE_LOADING_COMPLETE) {
334         FireMediaPlayerImageComplete();
335     }
336 }
337 
UpdateVideoNode()338 void MovingPhotoPattern::UpdateVideoNode()
339 {
340     ContainerScope scope(instanceId_);
341     auto pipelineContext = PipelineContext::GetCurrentContext();
342     CHECK_NULL_VOID(pipelineContext);
343     auto uiTaskExecutor = SingleTaskExecutor::Make(pipelineContext->GetTaskExecutor(), TaskExecutor::TaskType::UI);
344     uiTaskExecutor.PostTask(
345         [weak = WeakClaim(this)]() {
346             auto movingPhotoPattern = weak.Upgrade();
347             CHECK_NULL_VOID(movingPhotoPattern);
348             ContainerScope scope(movingPhotoPattern->instanceId_);
349             movingPhotoPattern->PrepareMediaPlayer();
350             movingPhotoPattern->UpdateMediaPlayerSpeed();
351             movingPhotoPattern->UpdateMediaPlayerMuted();
352         },
353         "ArkUIMovingPhotoUpdateVideo");
354 }
355 
PrepareMediaPlayer()356 void MovingPhotoPattern::PrepareMediaPlayer()
357 {
358     auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
359     CHECK_NULL_VOID(layoutProperty);
360     if (!layoutProperty->HasMovingPhotoUri() || !layoutProperty->HasVideoSource()) {
361         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MovingPhoto source is null.");
362         return;
363     }
364     if (layoutProperty->GetMovingPhotoUri().value() == uri_ &&
365         layoutProperty->GetVideoSource().value() == fd_) {
366         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer source has not changed.");
367         return;
368     }
369     uri_ = layoutProperty->GetMovingPhotoUri().value();
370     fd_ = layoutProperty->GetVideoSource().value();
371     if (!mediaPlayer_) {
372         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null.");
373         FireMediaPlayerError();
374         return;
375     }
376     if (!mediaPlayer_->IsMediaPlayerValid()) {
377         mediaPlayer_->CreateMediaPlayer();
378     }
379     if (!mediaPlayer_->IsMediaPlayerValid()) {
380         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is invalid.");
381         FireMediaPlayerError();
382         return;
383     }
384     ContainerScope scope(instanceId_);
385     auto context = PipelineContext::GetCurrentContext();
386     CHECK_NULL_VOID(context);
387     auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
388     platformTask.PostTask(
389         [weak = WeakClaim(this)] {
390             auto movingPhotoPattern = weak.Upgrade();
391             CHECK_NULL_VOID(movingPhotoPattern);
392             movingPhotoPattern->ResetMediaPlayer();
393         },
394         "ArkUIMovingPhotoPrepare");
395 }
396 
ResetMediaPlayer()397 void MovingPhotoPattern::ResetMediaPlayer()
398 {
399     CHECK_NULL_VOID(mediaPlayer_);
400     isPrepared_ = false;
401     mediaPlayer_->ResetMediaPlayer();
402     RegisterMediaPlayerEvent();
403     if (!mediaPlayer_->SetSourceByFd(fd_)) {
404         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "set source for MediaPlayer failed.");
405         ContainerScope scope(instanceId_);
406         auto context = PipelineContext::GetCurrentContext();
407         CHECK_NULL_VOID(context);
408 
409         auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
410         uiTaskExecutor.PostTask(
411             [weak = WeakClaim(this)] {
412                 auto pattern = weak.Upgrade();
413                 CHECK_NULL_VOID(pattern);
414                 ContainerScope scope(pattern->instanceId_);
415                 pattern->FireMediaPlayerError();
416             },
417             "ArkUIMovingPhotoReset");
418         return;
419     }
420 }
421 
RegisterMediaPlayerEvent()422 void MovingPhotoPattern::RegisterMediaPlayerEvent()
423 {
424     if (fd_ == -1 || !mediaPlayer_) {
425         return;
426     }
427     ContainerScope scope(instanceId_);
428     auto context = PipelineContext::GetCurrentContext();
429     CHECK_NULL_VOID(context);
430     auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
431     auto movingPhotoPattern = WeakClaim(this);
432 
433     auto&& positionUpdatedEvent = [movingPhotoPattern, uiTaskExecutor](uint32_t currentPos) {
434         uiTaskExecutor.PostTask([movingPhotoPattern, currentPos] {
435             auto movingPhoto = movingPhotoPattern.Upgrade();
436             CHECK_NULL_VOID(movingPhoto);
437             ContainerScope scope(movingPhoto->instanceId_);
438             movingPhoto->OnPlayPositionChanged(currentPos);
439         }, "ArkUIMovingPhotoPositionChanged");
440     };
441 
442     auto&& stateChangedEvent = [movingPhotoPattern, uiTaskExecutor](PlaybackStatus status) {
443         uiTaskExecutor.PostTask([movingPhotoPattern, status] {
444             auto movingPhoto = movingPhotoPattern.Upgrade();
445             CHECK_NULL_VOID(movingPhoto);
446             ContainerScope scope(movingPhoto->instanceId_);
447             movingPhoto->OnMediaPlayerStatusChanged(status);
448         }, "ArkUIMovingPhotoStatusChanged");
449     };
450 
451     auto&& errorEvent = [movingPhotoPattern, uiTaskExecutor]() {
452         uiTaskExecutor.PostSyncTask([movingPhotoPattern] {
453             auto movingPhoto = movingPhotoPattern.Upgrade();
454             CHECK_NULL_VOID(movingPhoto);
455             ContainerScope scope(movingPhoto->instanceId_);
456             movingPhoto->FireMediaPlayerError();
457         }, "ArkUIMovingPhotoOnError");
458     };
459 
460     auto&& resolutionChangeEvent = [movingPhotoPattern, uiTaskExecutor]() {
461         uiTaskExecutor.PostTask([movingPhotoPattern] {
462             auto movingPhoto = movingPhotoPattern.Upgrade();
463             CHECK_NULL_VOID(movingPhoto);
464             ContainerScope scope(movingPhoto->instanceId_);
465             movingPhoto->OnResolutionChange();
466         }, "ArkUIMovingPhotoResolutionChanged");
467     };
468 
469     auto&& startRenderFrameEvent = [movingPhotoPattern, uiTaskExecutor]() {
470         uiTaskExecutor.PostTask([movingPhotoPattern] {
471             auto movingPhoto = movingPhotoPattern.Upgrade();
472             CHECK_NULL_VOID(movingPhoto);
473             ContainerScope scope(movingPhoto->instanceId_);
474             movingPhoto->OnStartRenderFrame();
475         }, "ArkUIMovingPhotoStartRender");
476     };
477 
478     mediaPlayer_->RegisterMediaPlayerEvent(
479         positionUpdatedEvent, stateChangedEvent, errorEvent, resolutionChangeEvent, startRenderFrameEvent);
480 }
481 
PrepareSurface()482 void MovingPhotoPattern::PrepareSurface()
483 {
484     if (!mediaPlayer_ || renderSurface_->IsSurfaceValid()) {
485         return;
486     }
487     if (!SystemProperties::GetExtSurfaceEnabled()) {
488         renderSurface_->SetRenderContext(renderContextForMediaPlayer_);
489     }
490     renderSurface_->InitSurface();
491     mediaPlayer_->SetRenderSurface(renderSurface_);
492     if (mediaPlayer_->SetSurface() != 0) {
493         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "prepare MediaPlayer failed.");
494     }
495 }
496 
UpdatePlayMode()497 void MovingPhotoPattern::UpdatePlayMode()
498 {
499     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto UpdatePlayMode.%{public}d", isChangePlayMode_);
500     if (isChangePlayMode_) {
501         if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
502             SetAutoPlayPeriod(autoPlayPeriodStartTime_, autoPlayPeriodEndTime_);
503         }
504         MediaResetToPlay();
505         isChangePlayMode_ = false;
506     }
507 }
508 
HandleImageAnalyzerMode()509 void MovingPhotoPattern::HandleImageAnalyzerMode()
510 {
511     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto HandleImageAnalyzerMode.");
512     if (isEnableAnalyzer_ && autoAndRepeatLevel_ == PlaybackMode::NONE) {
513         if (!imageAnalyzerManager_) {
514             EnableAnalyzer(isEnableAnalyzer_);
515         }
516         if (imageAnalyzerManager_ && !GetAnalyzerState()) {
517             StartImageAnalyzer();
518         }
519     }
520     if (!isEnableAnalyzer_ && IsSupportImageAnalyzer()) {
521         DestroyAnalyzerOverlay();
522         LongPressEventModify(true);
523     }
524 }
525 
MediaResetToPlay()526 void MovingPhotoPattern::MediaResetToPlay()
527 {
528     autoAndRepeatLevel_ = historyAutoAndRepeatLevel_;
529     if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
530         mediaPlayer_->PrepareAsync();
531     } else if (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE ||
532         currentPlayStatus_ == PlaybackStatus::PAUSED ||
533         currentPlayStatus_ == PlaybackStatus::PREPARED) {
534             SelectPlaybackMode(historyAutoAndRepeatLevel_);
535     }
536 }
537 
FireMediaPlayerImageComplete()538 void MovingPhotoPattern::FireMediaPlayerImageComplete()
539 {
540     auto eventHub = GetEventHub<MovingPhotoEventHub>();
541     CHECK_NULL_VOID(eventHub);
542     eventHub->FireCompleteEvent();
543 }
544 
FireMediaPlayerStart()545 void MovingPhotoPattern::FireMediaPlayerStart()
546 {
547     auto eventHub = GetEventHub<MovingPhotoEventHub>();
548     CHECK_NULL_VOID(eventHub);
549     eventHub->FireStartEvent();
550     if (isFastKeyUp_) {
551         isFastKeyUp_ = false;
552         PausePlayback();
553     }
554 }
555 
FireMediaPlayerStop()556 void MovingPhotoPattern::FireMediaPlayerStop()
557 {
558     auto eventHub = GetEventHub<MovingPhotoEventHub>();
559     CHECK_NULL_VOID(eventHub);
560     eventHub->FireStopEvent();
561 }
562 
FireMediaPlayerPause()563 void MovingPhotoPattern::FireMediaPlayerPause()
564 {
565     auto eventHub = GetEventHub<MovingPhotoEventHub>();
566     CHECK_NULL_VOID(eventHub);
567     eventHub->FirePauseEvent();
568 }
569 
FireMediaPlayerFinish()570 void MovingPhotoPattern::FireMediaPlayerFinish()
571 {
572     auto eventHub = GetEventHub<MovingPhotoEventHub>();
573     CHECK_NULL_VOID(eventHub);
574     eventHub->FireFinishEvent();
575 }
576 
FireMediaPlayerError()577 void MovingPhotoPattern::FireMediaPlayerError()
578 {
579     auto eventHub = GetEventHub<MovingPhotoEventHub>();
580     CHECK_NULL_VOID(eventHub);
581     eventHub->FireErrorEvent();
582 }
583 
OnResolutionChange()584 void MovingPhotoPattern::OnResolutionChange()
585 {
586     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
587         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
588         return;
589     }
590     auto host = GetHost();
591     CHECK_NULL_VOID(host);
592     SizeF videoSize =
593         SizeF(static_cast<float>(mediaPlayer_->GetVideoWidth()), static_cast<float>(mediaPlayer_->GetVideoHeight()));
594     auto movingPhotoLayoutProperty = host->GetLayoutProperty<MovingPhotoLayoutProperty>();
595     CHECK_NULL_VOID(movingPhotoLayoutProperty);
596     movingPhotoLayoutProperty->UpdateVideoSize(videoSize);
597     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
598 }
599 
OnStartRenderFrame()600 void MovingPhotoPattern::OnStartRenderFrame()
601 {
602     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer OnStartRenderFrame.");
603 }
604 
OnStartedStatusCallback()605 void MovingPhotoPattern::OnStartedStatusCallback()
606 {
607     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer OnStartedStatusCallback.");
608     ACE_FUNCTION_TRACE();
609     auto host = GetHost();
610     CHECK_NULL_VOID(host);
611     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
612     CHECK_NULL_VOID(movingPhoto);
613     auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
614     CHECK_NULL_VOID(image);
615     StartAnimation();
616 }
617 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)618 bool MovingPhotoPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
619 {
620     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer OnStartedStatusCallback.");
621     if (config.skipMeasure || dirty->SkipMeasureContent()) {
622         return false;
623     }
624     auto geometryNode = dirty->GetGeometryNode();
625     CHECK_NULL_RETURN(geometryNode, false);
626     auto movingPhotoNodeSize = geometryNode->GetContentSize();
627     auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
628     CHECK_NULL_RETURN(layoutProperty, false);
629     auto videoFrameSize = MeasureContentLayout(movingPhotoNodeSize, layoutProperty);
630     if (renderContextForMediaPlayer_) {
631         renderContextForMediaPlayer_->SetBounds((movingPhotoNodeSize.Width() - videoFrameSize.Width()) / HALF,
632             (movingPhotoNodeSize.Height() - videoFrameSize.Height()) / HALF, videoFrameSize.Width(),
633             videoFrameSize.Height());
634     }
635 
636     if (IsSupportImageAnalyzer() && isEnableAnalyzer_ && autoAndRepeatLevel_ == PlaybackMode::NONE) {
637         if (imageAnalyzerManager_ && !GetAnalyzerState()) {
638             StartImageAnalyzer();
639         } else {
640             Rect tmpRect;
641             auto padding = layoutProperty->CreatePaddingAndBorder();
642             auto imageFit = layoutProperty->GetObjectFitValue(ImageFit::COVER);
643             if (imageFit == ImageFit::COVER || imageFit == ImageFit::NONE) {
644                 tmpRect = Rect(padding.left.value_or(0), padding.top.value_or(0),
645                                movingPhotoNodeSize.Width(), movingPhotoNodeSize.Height());
646             } else {
647                 tmpRect = Rect(
648                     (movingPhotoNodeSize.Width() - videoFrameSize.Width()) / AVERAGE_VALUE + padding.left.value_or(0),
649                     (movingPhotoNodeSize.Height() - videoFrameSize.Height()) / AVERAGE_VALUE + padding.top.value_or(0),
650                     videoFrameSize.Width(), videoFrameSize.Height());
651             }
652             contentRect_ = tmpRect;
653             UpdateAnalyzerUIConfig(geometryNode);
654         }
655     }
656     if (IsSupportImageAnalyzer() && !isEnableAnalyzer_) {
657         DestroyAnalyzerOverlay();
658         LongPressEventModify(true);
659     }
660 
661     auto host = GetHost();
662     CHECK_NULL_RETURN(host, false);
663     host->MarkNeedSyncRenderTree();
664     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
665     CHECK_NULL_RETURN(movingPhoto, false);
666     auto video = AceType::DynamicCast<FrameNode>(movingPhoto->GetVideo());
667     CHECK_NULL_RETURN(video, false);
668     video->GetRenderContext()->SetClipToBounds(true);
669     return false;
670 }
671 
CalculateFitContain(const SizeF& rawSize, const SizeF& layoutSize)672 SizeF MovingPhotoPattern::CalculateFitContain(const SizeF& rawSize, const SizeF& layoutSize)
673 {
674     if (NearZero(rawSize.Height()) || NearZero(rawSize.Width()) || NearZero(layoutSize.Height())) {
675         return layoutSize;
676     }
677     double sourceRatio = rawSize.Width() / rawSize.Height();
678     double layoutRatio = layoutSize.Width() / layoutSize.Height();
679     if (sourceRatio < layoutRatio) {
680         float ratio = layoutSize.Height() / rawSize.Height();
681         return { rawSize.Width() * ratio, layoutSize.Height() };
682     } else {
683         float ratio = layoutSize.Width() / rawSize.Width();
684         return { layoutSize.Width(), rawSize.Height() * ratio };
685     }
686 }
687 
CalculateFitFill(const SizeF& layoutSize)688 SizeF MovingPhotoPattern::CalculateFitFill(const SizeF& layoutSize)
689 {
690     return layoutSize;
691 }
692 
CalculateFitCover(const SizeF& rawSize, const SizeF& layoutSize)693 SizeF MovingPhotoPattern::CalculateFitCover(const SizeF& rawSize, const SizeF& layoutSize)
694 {
695     if (NearZero(rawSize.Height()) || NearZero(rawSize.Width()) || NearZero(layoutSize.Height())) {
696         return layoutSize;
697     }
698     double sourceRatio = rawSize.Width() / rawSize.Height();
699     double layoutRatio = layoutSize.Width() / layoutSize.Height();
700     float ratio = 1.0;
701     if (sourceRatio < layoutRatio) {
702         ratio = static_cast<float>(layoutSize.Width() / rawSize.Width());
703     } else {
704         ratio = static_cast<float>(layoutSize.Height() / rawSize.Height());
705     }
706     return { rawSize.Width() * ratio, rawSize.Height() * ratio};
707 }
708 
CalculateFitNone(const SizeF& rawSize)709 SizeF MovingPhotoPattern::CalculateFitNone(const SizeF& rawSize)
710 {
711     return rawSize;
712 }
713 
CalculateFitScaleDown(const SizeF& rawSize, const SizeF& layoutSize)714 SizeF MovingPhotoPattern::CalculateFitScaleDown(const SizeF& rawSize, const SizeF& layoutSize)
715 {
716     if ((rawSize.Width() <= layoutSize.Width()) && (rawSize.Height() <= layoutSize.Height())) {
717         return CalculateFitNone(rawSize);
718     } else {
719         return CalculateFitContain(rawSize, layoutSize);
720     }
721 }
722 
CalculateFitAuto(const SizeF& rawSize, const SizeF& layoutSize)723 SizeF MovingPhotoPattern::CalculateFitAuto(const SizeF& rawSize, const SizeF& layoutSize)
724 {
725     if (NearZero(rawSize.Width()) || NearZero(rawSize.Height())) {
726         return layoutSize;
727     }
728     if ((rawSize.Width() <= layoutSize.Width()) && (rawSize.Height() <= layoutSize.Height())) {
729         double widthRatio = layoutSize.Width() / rawSize.Width();
730         double heightRatio = layoutSize.Height() / rawSize.Height();
731         float ratio = static_cast<float>(std::min(widthRatio, heightRatio));
732         return { rawSize.Width() * ratio, rawSize.Height() * ratio };
733     } else if ((rawSize.Width() > layoutSize.Width()) && (rawSize.Height() <= layoutSize.Height())) {
734         return CalculateFitContain(rawSize, layoutSize);
735     } else {
736         return CalculateFitCover(rawSize, layoutSize);
737     }
738 }
739 
GetRawImageSize()740 SizeF MovingPhotoPattern::GetRawImageSize()
741 {
742     auto host = GetHost();
743     CHECK_NULL_RETURN(host, SizeF(-1, -1));
744     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
745     CHECK_NULL_RETURN(movingPhoto, SizeF(-1, -1));
746     auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
747     CHECK_NULL_RETURN(image, SizeF(-1, -1));
748     auto imagePattern = image->GetPattern<ImagePattern>();
749     CHECK_NULL_RETURN(image, SizeF(-1, -1));
750     return imagePattern->GetRawImageSize();
751 }
752 
MeasureContentLayout(const SizeF& layoutSize, const RefPtr<MovingPhotoLayoutProperty>& layoutProperty)753 SizeF MovingPhotoPattern::MeasureContentLayout(const SizeF& layoutSize,
754     const RefPtr<MovingPhotoLayoutProperty>& layoutProperty)
755 {
756     if (!layoutProperty || !layoutProperty->HasVideoSize()) {
757         return layoutSize;
758     }
759 
760     auto rawImageSize = GetRawImageSize();
761     auto imageFit = layoutProperty->GetObjectFitValue(ImageFit::COVER);
762     SizeF contentSize = { 0.0, 0.0 };
763     switch (imageFit) {
764         case ImageFit::CONTAIN:
765             contentSize = CalculateFitContain(rawImageSize, layoutSize);
766             break;
767         case ImageFit::FILL:
768             contentSize = CalculateFitFill(layoutSize);
769             break;
770         case ImageFit::COVER:
771             contentSize = CalculateFitCover(rawImageSize, layoutSize);
772             break;
773         case ImageFit::NONE:
774             contentSize = CalculateFitNone(rawImageSize);
775             break;
776         case ImageFit::SCALE_DOWN:
777             contentSize = CalculateFitScaleDown(rawImageSize, layoutSize);
778             break;
779         default:
780             contentSize = CalculateFitAuto(rawImageSize, layoutSize);
781     }
782 
783     return contentSize;
784 }
785 
OnMediaPlayerStatusChanged(PlaybackStatus status)786 void MovingPhotoPattern::OnMediaPlayerStatusChanged(PlaybackStatus status)
787 {
788     currentPlayStatus_ = status;
789     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is %{public}d.", status);
790     switch (status) {
791         case PlaybackStatus::ERROR:
792             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is ERROR.");
793             FireMediaPlayerError();
794             break;
795         case PlaybackStatus::IDLE:
796             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is IDLE.");
797             break;
798         case PlaybackStatus::INITIALIZED:
799             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is INITIALIZED.");
800             OnMediaPlayerInitialized();
801             break;
802         case PlaybackStatus::PREPARED:
803             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is PREPARED.");
804             OnMediaPlayerPrepared();
805             break;
806         case PlaybackStatus::STARTED:
807             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is STARTED.");
808             OnStartedStatusCallback();
809             FireMediaPlayerStart();
810             break;
811         case PlaybackStatus::PAUSED:
812             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is PAUSED.");
813             FireMediaPlayerPause();
814             break;
815         case PlaybackStatus::STOPPED:
816             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is STOPPED.");
817             OnMediaPlayerStoped();
818             break;
819         case PlaybackStatus::PLAYBACK_COMPLETE:
820             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is PLAYBACK_COMPLETE.");
821             OnMediaPlayerCompletion();
822             break;
823         case PlaybackStatus::NONE:
824             TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "Player current status is NONE.");
825             break;
826         default:
827             TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "Invalid player status.");
828             break;
829     }
830 }
831 
OnMediaPlayerInitialized()832 void MovingPhotoPattern::OnMediaPlayerInitialized()
833 {
834     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer OnMediaPlayerInitialized.");
835     if (!isSetAutoPlayPeriod_ && autoAndRepeatLevel_ == PlaybackMode::AUTO) {
836         isSetAutoPlayPeriod_ = true;
837         SetAutoPlayPeriod(autoPlayPeriodStartTime_, autoPlayPeriodEndTime_);
838     }
839     PrepareSurface();
840     if (mediaPlayer_->PrepareAsync() != PREPARE_RETURN) {
841         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "prepare MediaPlayer failed.");
842     }
843 }
844 
OnMediaPlayerPrepared()845 void MovingPhotoPattern::OnMediaPlayerPrepared()
846 {
847     ContainerScope scope(instanceId_);
848     auto context = PipelineContext::GetCurrentContext();
849     CHECK_NULL_VOID(context);
850     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
851         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
852         return;
853     }
854     isPrepared_ = true;
855     Size videoSize = Size(mediaPlayer_->GetVideoWidth(), mediaPlayer_->GetVideoHeight());
856     auto host = GetHost();
857     CHECK_NULL_VOID(host);
858     auto videoLayoutProperty = host->GetLayoutProperty<MovingPhotoLayoutProperty>();
859     CHECK_NULL_VOID(videoLayoutProperty);
860     CHECK_NULL_VOID(mediaPlayer_);
861     videoLayoutProperty->UpdateVideoSize(
862         SizeF(static_cast<float>(videoSize.Width()), static_cast<float>(videoSize.Height())));
863     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
864     UpdateMediaPlayerSpeed();
865     UpdateMediaPlayerMuted();
866     VisiblePlayback();
867 }
868 
OnMediaPlayerStoped()869 void MovingPhotoPattern::OnMediaPlayerStoped()
870 {
871     isPlayByController_ = false;
872     FireMediaPlayerStop();
873 }
874 
OnMediaPlayerCompletion()875 void MovingPhotoPattern::OnMediaPlayerCompletion()
876 {
877     if (isPlayByController_ || autoAndRepeatLevel_ != PlaybackMode::NONE) {
878         isPlayByController_ = false;
879         StopAnimation();
880     }
881     FireMediaPlayerFinish();
882 }
883 
HideImageNode()884 void MovingPhotoPattern::HideImageNode()
885 {
886     auto host = GetHost();
887     CHECK_NULL_VOID(host);
888     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
889     CHECK_NULL_VOID(movingPhoto);
890     auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
891     CHECK_NULL_VOID(image);
892     auto imageLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
893     CHECK_NULL_VOID(imageLayoutProperty);
894     imageLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
895     image->MarkModifyDone();
896 }
897 
VisiblePlayback()898 void MovingPhotoPattern::VisiblePlayback()
899 {
900     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto VisiblePlayback.");
901     if (!isVisible_) {
902         return;
903     }
904     if (historyAutoAndRepeatLevel_ != PlaybackMode::NONE &&
905         autoAndRepeatLevel_ == PlaybackMode::NONE) {
906         SelectPlaybackMode(historyAutoAndRepeatLevel_);
907     } else {
908         SelectPlaybackMode(autoAndRepeatLevel_);
909     }
910 }
911 
SelectPlaybackMode(PlaybackMode mode)912 void MovingPhotoPattern::SelectPlaybackMode(PlaybackMode mode)
913 {
914     if (mode == PlaybackMode::REPEAT) {
915         StartRepeatPlay();
916     } else if (mode == PlaybackMode::AUTO) {
917         StartAutoPlay();
918     }
919 }
920 
StartPlayback()921 void MovingPhotoPattern::StartPlayback()
922 {
923     if (currentPlayStatus_ == PlaybackStatus::STARTED || !isPrepared_) {
924         return;
925     }
926     if (autoAndRepeatLevel_ != PlaybackMode::NONE) {
927         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "StartPlayback autoAndRepeatLevel_:%{public}d.",
928             autoAndRepeatLevel_);
929         return;
930     }
931     if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
932         mediaPlayer_->PrepareAsync();
933     }
934     isPlayByController_ = true;
935     isFastKeyUp_ = false;
936     if (isSetAutoPlayPeriod_ && (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE ||
937         currentPlayStatus_ == PlaybackStatus::PAUSED)) {
938         int32_t duration = DURATION_FLAG;
939         mediaPlayer_->GetDuration(duration);
940         TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "StartPlayback duration:%{public}d.",
941             duration);
942         SetAutoPlayPeriod(PERIOD_START, duration);
943     }
944     Start();
945 }
946 
StartAnimation()947 void MovingPhotoPattern::StartAnimation()
948 {
949     if (historyAutoAndRepeatLevel_ == PlaybackMode::REPEAT) {
950         if (!isFirstRepeatPlay_) {
951             return;
952         }
953         isFirstRepeatPlay_ = false;
954     }
955     auto host = GetHost();
956     CHECK_NULL_VOID(host);
957     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
958     CHECK_NULL_VOID(movingPhoto);
959     auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
960     CHECK_NULL_VOID(image);
961     auto imageRsContext = image->GetRenderContext();
962     CHECK_NULL_VOID(imageRsContext);
963     auto video = AceType::DynamicCast<FrameNode>(movingPhoto->GetVideo());
964     CHECK_NULL_VOID(video);
965     auto videoRsContext = video->GetRenderContext();
966     CHECK_NULL_VOID(videoRsContext);
967 
968     imageRsContext->UpdateOpacity(1.0);
969     imageRsContext->UpdateTransformScale({NORMAL_SCALE, NORMAL_SCALE});
970     videoRsContext->UpdateTransformScale({NORMAL_SCALE, NORMAL_SCALE});
971     auto movingPhotoPattern = WeakClaim(this);
972     AnimationOption animationOption;
973     animationOption.SetDuration(ANIMATION_DURATION_400);
974     animationOption.SetCurve(Curves::FRICTION);
975     animationOption.SetOnFinishEvent([movingPhotoPattern]() {
976         auto movingPhoto = movingPhotoPattern.Upgrade();
977         TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StartAnimation OnFinishEvent.");
978         CHECK_NULL_VOID(movingPhoto);
979         if (movingPhoto->currentPlayStatus_ == PlaybackStatus::PAUSED
980             || movingPhoto->currentPlayStatus_ == PlaybackStatus::STOPPED
981             || !movingPhoto->startAnimationFlag_) {
982             return;
983         }
984         movingPhoto->HideImageNode();
985     });
986     startAnimationFlag_ = true;
987     AnimationUtils::Animate(animationOption,
988         [imageRsContext, videoRsContext, repeatFlag = historyAutoAndRepeatLevel_]() {
989             imageRsContext->UpdateOpacity(0.0);
990             imageRsContext->UpdateTransformScale({ZOOM_IN_SCALE, ZOOM_IN_SCALE});
991             if (repeatFlag == PlaybackMode::REPEAT) {
992                 videoRsContext->UpdateTransformScale({NORMAL_SCALE, NORMAL_SCALE});
993             } else {
994                 videoRsContext->UpdateTransformScale({ZOOM_IN_SCALE, ZOOM_IN_SCALE});
995             }
996         }, animationOption.GetOnFinishEvent());
997 }
998 
StopPlayback()999 void MovingPhotoPattern::StopPlayback()
1000 {
1001     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StopPlayback");
1002     isFastKeyUp_ = false;
1003     isPlayByController_ = false;
1004     Pause();
1005     autoAndRepeatLevel_ = PlaybackMode::NONE;
1006     if (historyAutoAndRepeatLevel_ != PlaybackMode::REPEAT) {
1007         StopAnimation();
1008     }
1009 }
1010 
PausePlayback()1011 void MovingPhotoPattern::PausePlayback()
1012 {
1013     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto PausePlayback");
1014     isFastKeyUp_ = false;
1015     if (currentPlayStatus_ != PlaybackStatus::STARTED || !isPrepared_) {
1016         return;
1017     }
1018     if (autoAndRepeatLevel_ != PlaybackMode::NONE) {
1019         TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "PausePlayback autoAndRepeatLevel_:%{public}d.",
1020             autoAndRepeatLevel_);
1021         return;
1022     }
1023     isPlayByController_ = false;
1024     Pause();
1025     StopAnimation();
1026 }
1027 
StopAnimation()1028 void MovingPhotoPattern::StopAnimation()
1029 {
1030     startAnimationFlag_ = false;
1031     if (historyAutoAndRepeatLevel_ == PlaybackMode::REPEAT) {
1032         StopAnimationCallback();
1033         return;
1034     }
1035     auto host = GetHost();
1036     CHECK_NULL_VOID(host);
1037     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
1038     CHECK_NULL_VOID(movingPhoto);
1039     auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
1040     CHECK_NULL_VOID(image);
1041     auto imageLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
1042     CHECK_NULL_VOID(imageLayoutProperty);
1043     auto imageRsContext = image->GetRenderContext();
1044     CHECK_NULL_VOID(imageRsContext);
1045     auto video = AceType::DynamicCast<FrameNode>(movingPhoto->GetVideo());
1046     CHECK_NULL_VOID(video);
1047     auto videoRsContext = video->GetRenderContext();
1048     CHECK_NULL_VOID(videoRsContext);
1049     videoRsContext->UpdateTransformScale({ZOOM_IN_SCALE, ZOOM_IN_SCALE});
1050     video->MarkModifyDone();
1051 
1052     imageLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
1053     imageRsContext->UpdateOpacity(0.0);
1054     imageRsContext->UpdateTransformScale({ZOOM_IN_SCALE, ZOOM_IN_SCALE});
1055     image->MarkModifyDone();
1056     auto movingPhotoPattern = WeakClaim(this);
1057     AnimationOption option;
1058     option.SetDuration(ANIMATION_DURATION_300);
1059     option.SetCurve(Curves::FRICTION);
1060     option.SetOnFinishEvent([movingPhotoPattern]() {
1061         auto movingPhoto = movingPhotoPattern.Upgrade();
1062         CHECK_NULL_VOID(movingPhoto);
1063         movingPhoto->StopAnimationCallback();
1064     });
1065     AnimationUtils::Animate(option, [imageRsContext, videoRsContext]() {
1066             imageRsContext->UpdateOpacity(1.0);
1067             imageRsContext->UpdateTransformScale({NORMAL_SCALE, NORMAL_SCALE});
1068             videoRsContext->UpdateTransformScale({NORMAL_SCALE, NORMAL_SCALE});
1069         }, option.GetOnFinishEvent());
1070 }
1071 
StopAnimationCallback()1072 void MovingPhotoPattern::StopAnimationCallback()
1073 {
1074     Seek(0);
1075     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "StopAnimation OnFinishEvent:%{public}d.", autoAndRepeatLevel_);
1076     if (needUpdateImageNode_) {
1077         UpdateImageNode();
1078         needUpdateImageNode_ = false;
1079     }
1080     if (autoAndRepeatLevel_ == PlaybackMode::REPEAT) {
1081         StartRepeatPlay();
1082     } else if (autoAndRepeatLevel_ == PlaybackMode::AUTO) {
1083         autoAndRepeatLevel_ = PlaybackMode::NONE;
1084     }
1085     if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
1086         HandleImageAnalyzerMode();
1087     }
1088 }
1089 
AutoPlay(bool isAutoPlay)1090 void MovingPhotoPattern::AutoPlay(bool isAutoPlay)
1091 {
1092     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto AutoPlay: %{public}d.", isAutoPlay);
1093     if (isAutoPlay) {
1094         if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
1095             return;
1096         }
1097         isChangePlayMode_ = true;
1098         if (autoAndRepeatLevel_ != PlaybackMode::REPEAT) {
1099             historyAutoAndRepeatLevel_ = PlaybackMode::AUTO;
1100             autoAndRepeatLevel_ = PlaybackMode::AUTO;
1101             if (!isSetAutoPlayPeriod_ && (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE ||
1102                 currentPlayStatus_ == PlaybackStatus::PAUSED)) {
1103                 isSetAutoPlayPeriod_ = true;
1104                 SetAutoPlayPeriod(autoPlayPeriodStartTime_, autoPlayPeriodEndTime_);
1105             }
1106         }
1107     }
1108 }
1109 
StartAutoPlay()1110 void MovingPhotoPattern::StartAutoPlay()
1111 {
1112     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StartAutoPlay in.");
1113     isFastKeyUp_ = false;
1114     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1115         return;
1116     }
1117 
1118     if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
1119         mediaPlayer_->PrepareAsync();
1120     }
1121     Start();
1122 }
1123 
StartRepeatPlay()1124 void MovingPhotoPattern::StartRepeatPlay()
1125 {
1126     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StartRepeatPlay in.");
1127     isFastKeyUp_ = false;
1128     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1129         return;
1130     }
1131 
1132     if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
1133         mediaPlayer_->PrepareAsync();
1134     }
1135     if (!isFirstRepeatPlay_ && isSetAutoPlayPeriod_) {
1136         int32_t duration = DURATION_FLAG;
1137         mediaPlayer_->GetDuration(duration);
1138         SetAutoPlayPeriod(PERIOD_START, duration);
1139     }
1140     Start();
1141 }
1142 
RepeatPlay(bool isRepeatPlay)1143 void MovingPhotoPattern::RepeatPlay(bool isRepeatPlay)
1144 {
1145     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto RepeatPlay status: %{public}d.", isRepeatPlay);
1146     if (isRepeatPlay && historyAutoAndRepeatLevel_ != PlaybackMode::REPEAT) {
1147         isChangePlayMode_ = true;
1148         isFirstRepeatPlay_ = true;
1149     }
1150     if (!isRepeatPlay && historyAutoAndRepeatLevel_ == PlaybackMode::REPEAT) {
1151         isChangePlayMode_ = true;
1152         historyAutoAndRepeatLevel_ = PlaybackMode::NONE;
1153         Pause();
1154         StopAnimation();
1155     }
1156     if (isRepeatPlay) {
1157         historyAutoAndRepeatLevel_ = PlaybackMode::REPEAT;
1158         autoAndRepeatLevel_ = PlaybackMode::REPEAT;
1159     }
1160 }
1161 
AutoPlayPeriod(int64_t startTime, int64_t endTime)1162 void MovingPhotoPattern::AutoPlayPeriod(int64_t startTime, int64_t endTime)
1163 {
1164     if (startTime >= VIDEO_PLAYTIME_START_POSITION && startTime < endTime
1165             && endTime <= VIDEO_PLAYTIME_END_POSITION) {
1166         TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer set Period.");
1167         autoPlayPeriodStartTime_ = startTime;
1168         autoPlayPeriodEndTime_ = endTime;
1169     }
1170 }
1171 
SetAutoPlayPeriod(int64_t startTime, int64_t endTime)1172 void MovingPhotoPattern::SetAutoPlayPeriod(int64_t startTime, int64_t endTime)
1173 {
1174     if (startTime < VIDEO_PLAYTIME_START_POSITION || startTime >= endTime
1175             || endTime > VIDEO_PLAYTIME_END_POSITION) {
1176         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer SetAutoPlayPeriod error.");
1177         return;
1178     }
1179     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1180         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1181         return;
1182     }
1183 
1184     ContainerScope scope(instanceId_);
1185     auto context = PipelineContext::GetCurrentContext();
1186     CHECK_NULL_VOID(context);
1187 
1188     mediaPlayer_->SetPlayRange(startTime, endTime);
1189 }
1190 
HandleImageAnalyzerPlayCallBack()1191 void MovingPhotoPattern::HandleImageAnalyzerPlayCallBack()
1192 {
1193     TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "HandleImageAnalyzerPlayCallBack start.");
1194     isFastKeyUp_ = false;
1195     if (currentPlayStatus_ == PlaybackStatus::STARTED || !isPrepared_ || isPlayByController_) {
1196         return;
1197     }
1198     if (autoAndRepeatLevel_ != PlaybackMode::NONE) {
1199         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "HandleImageAnalyzerPlayCallBack auto&Repeat return.");
1200         return;
1201     }
1202     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1203         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1204         FireMediaPlayerError();
1205         return;
1206     }
1207     if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
1208         mediaPlayer_->PrepareAsync();
1209     }
1210     if (isSetAutoPlayPeriod_ && (currentPlayStatus_ == PlaybackStatus::PLAYBACK_COMPLETE ||
1211         currentPlayStatus_ == PlaybackStatus::PAUSED)) {
1212         int32_t duration = DURATION_FLAG;
1213         mediaPlayer_->GetDuration(duration);
1214         SetAutoPlayPeriod(PERIOD_START, duration);
1215     }
1216     Start();
1217 }
1218 
Start()1219 void MovingPhotoPattern::Start()
1220 {
1221     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1222         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1223         return;
1224     }
1225     if (currentPlayStatus_ == PlaybackStatus::STOPPED) {
1226         mediaPlayer_->PrepareAsync();
1227     }
1228     ContainerScope scope(instanceId_);
1229     auto context = PipelineContext::GetCurrentContext();
1230     CHECK_NULL_VOID(context);
1231 
1232     auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1233     platformTask.PostTask(
1234         [weak = WeakClaim(RawPtr(mediaPlayer_))] {
1235             auto mediaPlayer = weak.Upgrade();
1236             CHECK_NULL_VOID(mediaPlayer);
1237             mediaPlayer->Play();
1238         },
1239         "ArkUIMovingPhotoStartPlay");
1240 }
1241 
Pause()1242 void MovingPhotoPattern::Pause()
1243 {
1244     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1245         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1246         return;
1247     }
1248     ContainerScope scope(instanceId_);
1249     auto context = PipelineContext::GetCurrentContext();
1250     CHECK_NULL_VOID(context);
1251 
1252     auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1253     platformTask.PostTask(
1254         [weak = WeakClaim(RawPtr(mediaPlayer_))] {
1255             auto mediaPlayer = weak.Upgrade();
1256             CHECK_NULL_VOID(mediaPlayer);
1257             mediaPlayer->Pause();
1258         },
1259         "ArkUIMovingPhotoPausePlay");
1260 }
1261 
Stop()1262 void MovingPhotoPattern::Stop()
1263 {
1264     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1265         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1266         return;
1267     }
1268     ContainerScope scope(instanceId_);
1269     auto context = PipelineContext::GetCurrentContext();
1270     CHECK_NULL_VOID(context);
1271 
1272     auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1273     platformTask.PostTask(
1274         [weak = WeakClaim(RawPtr(mediaPlayer_))] {
1275             auto mediaPlayer = weak.Upgrade();
1276             CHECK_NULL_VOID(mediaPlayer);
1277             mediaPlayer->Stop();
1278         },
1279         "ArkUIMovingPhotoStopPlay");
1280 }
1281 
Seek(int32_t position)1282 void MovingPhotoPattern::Seek(int32_t position)
1283 {
1284     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1285         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1286         return;
1287     }
1288     ContainerScope scope(instanceId_);
1289     auto context = PipelineContext::GetCurrentContext();
1290     CHECK_NULL_VOID(context);
1291 
1292     auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1293     platformTask.PostTask(
1294         [weak = WeakClaim(RawPtr(mediaPlayer_)), pos = position] {
1295             auto mediaPlayer = weak.Upgrade();
1296             CHECK_NULL_VOID(mediaPlayer);
1297             mediaPlayer->Seek(pos, SeekMode::SEEK_PREVIOUS_SYNC);
1298         },
1299         "ArkUIMovingPhotoSeek");
1300 }
1301 
UpdateMediaPlayerSpeed()1302 void MovingPhotoPattern::UpdateMediaPlayerSpeed()
1303 {
1304     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1305         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1306         return;
1307     }
1308     ContainerScope scope(instanceId_);
1309     auto context = PipelineContext::GetCurrentContext();
1310     CHECK_NULL_VOID(context);
1311     auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1312     platformTask.PostTask(
1313         [weak = WeakClaim(RawPtr(mediaPlayer_))] {
1314             auto mediaPlayer = weak.Upgrade();
1315             CHECK_NULL_VOID(mediaPlayer);
1316             mediaPlayer->SetPlaybackSpeed(static_cast<float>(NORMAL_PLAY_SPEED));
1317         },
1318         "ArkUIMovingPhotoUpdateSpeed");
1319 }
1320 
UpdateMediaPlayerMuted()1321 void MovingPhotoPattern::UpdateMediaPlayerMuted()
1322 {
1323     if (!mediaPlayer_ || !mediaPlayer_->IsMediaPlayerValid()) {
1324         TAG_LOGW(AceLogTag::ACE_MOVING_PHOTO, "MediaPlayer is null or invalid.");
1325         return;
1326     }
1327     ContainerScope scope(instanceId_);
1328     float volume = isMuted_ ? 0.0f : 1.0f;
1329     auto context = PipelineContext::GetCurrentContext();
1330     CHECK_NULL_VOID(context);
1331     auto platformTask = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::BACKGROUND);
1332     platformTask.PostTask(
1333         [weak = WeakClaim(RawPtr(mediaPlayer_)), videoVolume = volume] {
1334             auto mediaPlayer = weak.Upgrade();
1335             CHECK_NULL_VOID(mediaPlayer);
1336             mediaPlayer->SetVolume(videoVolume, videoVolume);
1337         },
1338         "ArkUIMovingPhotoUpdateMuted");
1339 }
1340 
OnAreaChangedInner()1341 void MovingPhotoPattern::OnAreaChangedInner()
1342 {
1343     if (!SystemProperties::GetExtSurfaceEnabled()) {
1344         return;
1345     }
1346     auto host = GetHost();
1347     CHECK_NULL_VOID(host);
1348     auto geometryNode = host->GetGeometryNode();
1349     CHECK_NULL_VOID(geometryNode);
1350     auto videoNodeSize = geometryNode->GetContentSize();
1351     auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
1352     CHECK_NULL_VOID(layoutProperty);
1353     auto videoFrameSize = MeasureContentLayout(videoNodeSize, layoutProperty);
1354     auto transformRelativeOffset = host->GetTransformRelativeOffset();
1355 
1356     Rect rect = Rect(transformRelativeOffset.GetX() + (videoNodeSize.Width() - videoFrameSize.Width()) / HALF,
1357         transformRelativeOffset.GetY() + (videoNodeSize.Height() - videoFrameSize.Height()) / HALF,
1358         videoFrameSize.Width(), videoFrameSize.Height());
1359     if (renderSurface_ && (rect != lastBoundsRect_)) {
1360         renderSurface_->SetExtSurfaceBounds(rect.Left(), rect.Top(), rect.Width(), rect.Height());
1361         lastBoundsRect_ = rect;
1362     }
1363 }
1364 
OnVisibleChange(bool isVisible)1365 void MovingPhotoPattern::OnVisibleChange(bool isVisible)
1366 {
1367     CHECK_NULL_VOID(mediaPlayer_);
1368     if (!isVisible) {
1369         StopPlayback();
1370     }
1371 }
1372 
OnWindowHide()1373 void MovingPhotoPattern::OnWindowHide()
1374 {
1375     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto OnWindowHide.");
1376     if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
1377         PausePlayback();
1378     } else if (historyAutoAndRepeatLevel_ == PlaybackMode::REPEAT) {
1379         StopPlayback();
1380         return;
1381     }
1382     auto host = GetHost();
1383     CHECK_NULL_VOID(host);
1384     auto movingPhoto = AceType::DynamicCast<MovingPhotoNode>(host);
1385     CHECK_NULL_VOID(movingPhoto);
1386     auto image = AceType::DynamicCast<FrameNode>(movingPhoto->GetImage());
1387     CHECK_NULL_VOID(image);
1388     auto imageLayoutProperty = image->GetLayoutProperty<ImageLayoutProperty>();
1389     CHECK_NULL_VOID(imageLayoutProperty);
1390     imageLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
1391     auto rsContext = image->GetRenderContext();
1392     CHECK_NULL_VOID(rsContext);
1393     rsContext->UpdateOpacity(1.0);
1394     image->MarkModifyDone();
1395 }
1396 
OnWindowShow()1397 void MovingPhotoPattern::OnWindowShow()
1398 {
1399     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto OnWindowShow.");
1400     CHECK_NULL_VOID(mediaPlayer_);
1401     if (autoAndRepeatLevel_ == PlaybackMode::REPEAT && currentPlayStatus_ == PlaybackStatus::STOPPED) {
1402         mediaPlayer_->PrepareAsync();
1403     }
1404 }
1405 
RegisterVisibleAreaChange()1406 void MovingPhotoPattern::RegisterVisibleAreaChange()
1407 {
1408     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto RegisterVisibleAreaChange.");
1409     if (hasVisibleChangeRegistered_) {
1410         return;
1411     }
1412     auto pipeline = PipelineContext::GetCurrentContextSafely();
1413     CHECK_NULL_VOID(pipeline);
1414     auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
1415         auto pattern = weak.Upgrade();
1416         CHECK_NULL_VOID(pattern);
1417         pattern->isVisible_ = visible;
1418         pattern->VisibleAreaCallback(visible);
1419     };
1420     auto host = GetHost();
1421     CHECK_NULL_VOID(host);
1422     std::vector<double> ratioList = {1.0};
1423     pipeline->AddVisibleAreaChangeNode(host, ratioList, callback, false);
1424     hasVisibleChangeRegistered_ = true;
1425 }
1426 
VisibleAreaCallback(bool visible)1427 void MovingPhotoPattern::VisibleAreaCallback(bool visible)
1428 {
1429     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto VisibleAreaCallback:%{public}d.", visible);
1430     if (visible) {
1431         if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
1432             SetAutoPlayPeriod(autoPlayPeriodStartTime_, autoPlayPeriodEndTime_);
1433         }
1434         MediaResetToPlay();
1435     } else {
1436         if (historyAutoAndRepeatLevel_ == PlaybackMode::AUTO) {
1437             PausePlayback();
1438         } else if (historyAutoAndRepeatLevel_ == PlaybackMode::REPEAT) {
1439             StopPlayback();
1440         }
1441     }
1442 }
1443 
EnableAnalyzer(bool enable)1444 void MovingPhotoPattern::EnableAnalyzer(bool enable)
1445 {
1446     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto EnableAnalyzer:%{public}d.", enable);
1447     isEnableAnalyzer_ = enable;
1448     if (!isEnableAnalyzer_) {
1449         DestroyAnalyzerOverlay();
1450         LongPressEventModify(true);
1451         return;
1452     }
1453 
1454     CHECK_NULL_VOID(!imageAnalyzerManager_);
1455     auto host = GetHost();
1456     CHECK_NULL_VOID(host);
1457     imageAnalyzerManager_ = std::make_shared<ImageAnalyzerManager>(host, ImageAnalyzerHolder::MOVINGPHOTO);
1458 }
1459 
SetImageAIOptions(void* options)1460 void MovingPhotoPattern::SetImageAIOptions(void* options)
1461 {
1462     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto SetImageAIOptions");
1463     if (!imageAnalyzerManager_) {
1464         imageAnalyzerManager_ = std::make_shared<ImageAnalyzerManager>(GetHost(), ImageAnalyzerHolder::MOVINGPHOTO);
1465     }
1466     CHECK_NULL_VOID(imageAnalyzerManager_);
1467     imageAnalyzerManager_->SetImageAIOptions(options);
1468 }
1469 
IsSupportImageAnalyzer()1470 bool MovingPhotoPattern::IsSupportImageAnalyzer()
1471 {
1472     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto IsSupportImageAnalyzer");
1473     auto host = GetHost();
1474     CHECK_NULL_RETURN(host, false);
1475     auto layoutProperty = host->GetLayoutProperty<MovingPhotoLayoutProperty>();
1476     CHECK_NULL_RETURN(layoutProperty, false);
1477     CHECK_NULL_RETURN(imageAnalyzerManager_, false);
1478     return imageAnalyzerManager_->IsSupportImageAnalyzerFeature();
1479 }
1480 
ShouldUpdateImageAnalyzer()1481 bool MovingPhotoPattern::ShouldUpdateImageAnalyzer()
1482 {
1483     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto ShouldUpdateImageAnalyzer");
1484     auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
1485     CHECK_NULL_RETURN(layoutProperty, false);
1486     const auto& constraint = layoutProperty->GetCalcLayoutConstraint();
1487     if (!constraint || !constraint->selfIdealSize.has_value() || !constraint->selfIdealSize->IsValid()) {
1488         return false;
1489     }
1490     auto selfIdealSize = constraint->selfIdealSize;
1491     if (!selfIdealSize->PercentWidth() && !selfIdealSize->PercentHeight()) {
1492         return false;
1493     }
1494     auto imageFit = layoutProperty->GetObjectFit().value_or(ImageFit::COVER);
1495     if (imageFit != ImageFit::COVER && imageFit != ImageFit::NONE) {
1496         return false;
1497     }
1498     return true;
1499 }
1500 
StartImageAnalyzer()1501 void MovingPhotoPattern::StartImageAnalyzer()
1502 {
1503     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StartImageAnalyzer");
1504     if (!IsSupportImageAnalyzer() || !imageAnalyzerManager_) {
1505         return;
1506     }
1507 
1508     if (imageAnalyzerManager_->IsOverlayCreated()) {
1509         DestroyAnalyzerOverlay();
1510         LongPressEventModify(true);
1511     }
1512 
1513     ContainerScope scope(instanceId_);
1514     auto host = GetHost();
1515     CHECK_NULL_VOID(host);
1516     auto context = host->GetContext();
1517     CHECK_NULL_VOID(context);
1518     auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
1519     uiTaskExecutor.PostDelayedTask([weak = WeakClaim(this)] {
1520         auto pattern = weak.Upgrade();
1521         CHECK_NULL_VOID(pattern);
1522         pattern->CreateAnalyzerOverlay();
1523         }, ANALYZER_DELAY_TIME, "ArkUIMovingPhotoCreateAnalyzerOverlay");
1524     LongPressEventModify(false);
1525 }
1526 
CreateAnalyzerOverlay()1527 void MovingPhotoPattern::CreateAnalyzerOverlay()
1528 {
1529     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto CreateAnalyzerOverlay");
1530     CHECK_NULL_VOID(imageAnalyzerManager_);
1531     if (!IsSupportImageAnalyzer() || !imageAnalyzerManager_->IsOverlayCreated()) {
1532         return;
1533     }
1534     GetPixelMap();
1535     int64_t coverPosition = GetUriCoverPosition();
1536     auto onCanPlay = [weak = AceType::WeakClaim(this)](bool canPlay) {
1537         auto pattern = weak.Upgrade();
1538         CHECK_NULL_VOID(pattern);
1539         pattern->HandleAnalyzerPlayEvent(canPlay);
1540     };
1541     auto host = GetHost();
1542     CHECK_NULL_VOID(host);
1543     auto geometryNode = host->GetGeometryNode();
1544     CHECK_NULL_VOID(geometryNode);
1545     auto movingPhotoNodeSize = geometryNode->GetContentSize();
1546     MovingPhotoAnalyzerInfo info = {uri_, coverPosition,
1547                                     movingPhotoNodeSize.Width(),
1548                                     movingPhotoNodeSize.Height()};
1549     imageAnalyzerManager_->SetOnCanPlayCallback(std::move(onCanPlay));
1550     imageAnalyzerManager_->CreateMovingPhotoAnalyzerOverlay(pixelMap_, info);
1551 }
1552 
StartUpdateImageAnalyzer()1553 void MovingPhotoPattern::StartUpdateImageAnalyzer()
1554 {
1555     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto StartUpdateImageAnalyzer");
1556     CHECK_NULL_VOID(imageAnalyzerManager_);
1557     if (!imageAnalyzerManager_->IsOverlayCreated()) {
1558         return;
1559     }
1560 
1561     UpdateOverlayVisibility(VisibleType::GONE);
1562     ContainerScope scope(instanceId_);
1563     auto host = GetHost();
1564     CHECK_NULL_VOID(host);
1565     auto context = host->GetContext();
1566     CHECK_NULL_VOID(context);
1567     auto uiTaskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
1568     uiTaskExecutor.PostDelayedTask([weak = WeakClaim(this)] {
1569         auto pattern = weak.Upgrade();
1570         CHECK_NULL_VOID(pattern);
1571         if (!pattern->isContentSizeChanged_) {
1572             return;
1573         }
1574         pattern->UpdateAnalyzerOverlay();
1575         pattern->isContentSizeChanged_ = false;
1576         }, ANALYZER_CAPTURE_DELAY_TIME, "ArkUIMovingPhotoUpdateAnalyzerOverlay");
1577     isContentSizeChanged_ = true;
1578 }
1579 
UpdateAnalyzerOverlay()1580 void MovingPhotoPattern::UpdateAnalyzerOverlay()
1581 {
1582     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto UpdateAnalyzerOverlay");
1583     CHECK_NULL_VOID(imageAnalyzerManager_);
1584     if (!IsSupportImageAnalyzer() || !imageAnalyzerManager_->IsOverlayCreated()) {
1585         return;
1586     }
1587     GetPixelMap();
1588     int64_t coverPosition = GetUriCoverPosition();
1589     UpdateOverlayVisibility(VisibleType::VISIBLE);
1590     auto host = GetHost();
1591     CHECK_NULL_VOID(host);
1592     auto geometryNode = host->GetGeometryNode();
1593     CHECK_NULL_VOID(geometryNode);
1594     auto movingPhotoNodeSize = geometryNode->GetContentSize();
1595     MovingPhotoAnalyzerInfo info = {uri_, coverPosition,
1596                                     movingPhotoNodeSize.Width(),
1597                                     movingPhotoNodeSize.Height()};
1598     imageAnalyzerManager_->UpdateMovingPhotoAnalyzerOverlay(pixelMap_, info);
1599 }
1600 
UpdateAnalyzerUIConfig(const RefPtr<NG::GeometryNode>& geometryNode)1601 void MovingPhotoPattern::UpdateAnalyzerUIConfig(const RefPtr<NG::GeometryNode>& geometryNode)
1602 {
1603     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto UpdateAnalyzerUIConfig");
1604     if (IsSupportImageAnalyzer()) {
1605         auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
1606         CHECK_NULL_VOID(layoutProperty);
1607         auto padding  = layoutProperty->CreatePaddingAndBorder();
1608         OffsetF contentOffset = { contentRect_.Left() - padding.left.value_or(0),
1609                                   contentRect_.Top() - padding.top.value_or(0) };
1610         PixelMapInfo info = { contentRect_.GetSize().Width(), contentRect_.GetSize().Height(), contentOffset };
1611         CHECK_NULL_VOID(imageAnalyzerManager_);
1612         imageAnalyzerManager_->UpdateAnalyzerUIConfig(geometryNode, info);
1613     }
1614 }
1615 
DestroyAnalyzerOverlay()1616 void MovingPhotoPattern::DestroyAnalyzerOverlay()
1617 {
1618     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto DestroyAnalyzerOverlay");
1619     CHECK_NULL_VOID(imageAnalyzerManager_);
1620     imageAnalyzerManager_->DestroyAnalyzerOverlay();
1621 }
1622 
GetAnalyzerState()1623 bool MovingPhotoPattern::GetAnalyzerState()
1624 {
1625     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "movingphoto GetAnalyzerState");
1626     CHECK_NULL_RETURN(imageAnalyzerManager_, false);
1627     return imageAnalyzerManager_->IsOverlayCreated();
1628 }
1629 
UpdateOverlayVisibility(VisibleType type)1630 void MovingPhotoPattern::UpdateOverlayVisibility(VisibleType type)
1631 {
1632     auto host = GetHost();
1633     CHECK_NULL_VOID(host);
1634     auto overlayNode = host->GetOverlayNode();
1635     CHECK_NULL_VOID(overlayNode);
1636     auto prop = overlayNode->GetLayoutProperty();
1637     CHECK_NULL_VOID(prop);
1638     prop->UpdateVisibility(type);
1639 }
1640 
GetPixelMap()1641 void MovingPhotoPattern::GetPixelMap()
1642 {
1643     auto layoutProperty = GetLayoutProperty<MovingPhotoLayoutProperty>();
1644     CHECK_NULL_VOID(layoutProperty);
1645     if (!layoutProperty->HasMovingPhotoUri() || !layoutProperty->HasVideoSource()) {
1646         TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "GetPixelMap MovingPhoto source is null.");
1647         return;
1648     }
1649     auto pipeline = PipelineBase::GetCurrentContext();
1650     CHECK_NULL_VOID(pipeline);
1651     auto dataProvider = AceType::DynamicCast<DataProviderManagerStandard>(pipeline->GetDataProviderManager());
1652     CHECK_NULL_VOID(dataProvider);
1653     std::string imageSrc = dataProvider->GetMovingPhotoImagePath(uri_);
1654     std::string thumbnailUrl = uri_ + THUMBNAIL_MEDIUM_JOINT + imageSrc;
1655     void* pixelMapMediauniquePtr = dataProvider->GetDataProviderThumbnailResFromUri(thumbnailUrl);
1656     CHECK_NULL_VOID(pixelMapMediauniquePtr);
1657     auto pixelMap = PixelMap::CreatePixelMapFromDataAbility(pixelMapMediauniquePtr);
1658     CHECK_NULL_VOID(pixelMap);
1659     pixelMap_ = pixelMap;
1660 }
1661 
GetUriCoverPosition()1662 int64_t MovingPhotoPattern::GetUriCoverPosition()
1663 {
1664     auto pipeline = PipelineBase::GetCurrentContext();
1665     CHECK_NULL_RETURN(pipeline, -1);
1666     auto dataProvider = AceType::DynamicCast<DataProviderManagerStandard>(pipeline->GetDataProviderManager());
1667     CHECK_NULL_RETURN(dataProvider, -1);
1668     std::vector<std::string> columns = {COVER_POSITION};
1669     auto result = dataProvider->GetMovingPhotoCoverPosition(IMAGE_URI, uri_, columns);
1670     return result;
1671 }
1672 
HandleAnalyzerPlayEvent(bool canPlay)1673 void MovingPhotoPattern::HandleAnalyzerPlayEvent(bool canPlay)
1674 {
1675     TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "MovingPhoto HandleAnalyzerPlayEvent:%{public}d", canPlay);
1676     if (isAnalyzerPlaying_ && !canPlay) {
1677         Pause();
1678         StopAnimation();
1679     }
1680     isAnalyzerPlaying_ = canPlay;
1681     if (canPlay) {
1682         HandleImageAnalyzerPlayCallBack();
1683     }
1684 }
1685 
~MovingPhotoPattern()1686 MovingPhotoPattern::~MovingPhotoPattern()
1687 {
1688     if (IsSupportImageAnalyzer()) {
1689         TAG_LOGI(AceLogTag::ACE_MOVING_PHOTO, "~MovingPhotoPattern DestroyAnalyzerOverlay.");
1690         DestroyAnalyzerOverlay();
1691     }
1692     if (fd_ > 0) {
1693         close(fd_);
1694     }
1695 }
1696 } // namespace OHOS::Ace::NG