1 /*
2  * Copyright (c) 2021 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 "core/components/focus_animation/render_focus_animation.h"
17 
18 #include "base/log/event_report.h"
19 #include "core/components/scroll/render_single_child_scroll.h"
20 
21 namespace OHOS::Ace {
22 namespace {
23 
24 constexpr int32_t TOTAL_DURATION = 3000;
25 constexpr float SEMICIRCLE = 180.0f;
26 
27 } // namespace
28 
Update(const RefPtr<Component> & component)29 void RenderFocusAnimation::Update(const RefPtr<Component>& component)
30 {
31     if (animationParamsSet_) {
32         return;
33     }
34     auto focusAnimation = AceType::DynamicCast<FocusAnimationComponent>(component);
35     if (!focusAnimation) {
36         LOGE("RenderFocusAnimation update with nullptr");
37         EventReport::SendRenderException(RenderExcepType::RENDER_COMPONENT_ERR);
38         return;
39     }
40 
41     auto pipelineContext = GetContext().Upgrade();
42     if (!pipelineContext) {
43         LOGE("pipelineContext update with nullptr");
44         return;
45     }
46     auto theme = pipelineContext->GetThemeManager();
47     if (!theme) {
48         LOGE("calendar theme update with nullptr");
49         return;
50     }
51     focusTheme_ = theme->GetTheme<FocusAnimationTheme>();
52     layoutSize_.SetWidth(pipelineContext->GetRootWidth());
53     layoutSize_.SetHeight(pipelineContext->GetRootHeight());
54     if (SystemProperties::GetDeviceType() == DeviceType::TV) {
55         animator_ = CREATE_ANIMATOR(pipelineContext);
56         focusAnimation_ = AceType::MakeRefPtr<CurveAnimation<float>>(0.0f, SEMICIRCLE, Curves::LINEAR);
57         focusAnimation_->AddListener([weak = AceType::WeakClaim(this)](const float& value) {
58             auto client = weak.Upgrade();
59             if (client) {
60                 client->progress_ = value;
61                 client->MarkNeedRender(true);
62             }
63         });
64         animator_->AddInterpolator(focusAnimation_);
65         animator_->SetDuration(TOTAL_DURATION);
66         animator_->SetIteration(ANIMATION_REPEAT_INFINITE);
67     }
68 
69     isDisplay_ = false;
70     animationParamsSet_ = true;
71     isRoot_ = focusAnimation->IsRoot();
72 }
73 
MarkNeedRenderSpecial()74 bool RenderFocusAnimation::MarkNeedRenderSpecial()
75 {
76     auto parent = GetParent().Upgrade();
77     auto renderScroll = AceType::DynamicCast<RenderScroll>(parent);
78     if (renderScroll) {
79         return true;
80     }
81     return false;
82 }
83 
SetFocusAnimationProperties(const RRect & rrect,const Offset & offset)84 void RenderFocusAnimation::SetFocusAnimationProperties(const RRect& rrect, const Offset& offset)
85 {
86     rrect_ = rrect;
87     offset_ = offset - GetGlobalOffset();
88     isNeedClip_ = false;
89     if (focusTheme_) {
90         pathColor_ = focusTheme_->GetColor();
91     }
92     animationParamsSet_ = true;
93     if ((offset_.GetX() + rrect.Width()) > layoutSize_.Width() && (offset_.GetX() + rrect.Width()) > 0) {
94         layoutSize_.SetWidth(offset_.GetX() + rrect.Width() + NormalizeToPx(blurMaskRadius_) * 2); // 2: two radius
95         MarkNeedLayout();
96     }
97     if ((offset_.GetY() + rrect.Height()) > layoutSize_.Height() && (offset_.GetY() + rrect.Height()) > 0) {
98         layoutSize_.SetHeight((offset_.GetY() + rrect.Height()) + NormalizeToPx(blurMaskRadius_) * 2); // 2: two radius
99         MarkNeedLayout();
100     }
101 }
102 
SetFocusAnimationProperties(const RRect & rrect,const Color & color,const Offset & offset,bool isIndented)103 void RenderFocusAnimation::SetFocusAnimationProperties(
104     const RRect& rrect, const Color& color, const Offset& offset, bool isIndented)
105 {
106     SetFocusAnimationProperties(rrect, offset);
107     if (SystemProperties::GetDeviceType() == DeviceType::TV) {
108         pathColor_ = color;
109         if (!isDisplay_) {
110             isDisplay_ = true;
111             animator_->Play();
112         }
113     } else if (SystemProperties::GetDeviceType() == DeviceType::PHONE) {
114         if (isKeyEvent_) {
115             // When the device is phone, only the key event will require paint.
116             isDisplay_ = true;
117             isIndented_ = isIndented;
118             MarkNeedLayout();
119         }
120     }
121 }
122 
SetFocusAnimationProperties(const RRect & rrect,const Color & color,const Offset & offset,const Rect & clipRect)123 void RenderFocusAnimation::SetFocusAnimationProperties(
124     const RRect& rrect, const Color& color, const Offset& offset, const Rect& clipRect)
125 {
126     if (SystemProperties::GetDeviceType() == DeviceType::TV) {
127         isNeedClip_ = true;
128         clipRect_ = clipRect;
129     }
130     SetFocusAnimationProperties(rrect, color, offset, false);
131 }
132 
CancelFocusAnimation()133 void RenderFocusAnimation::CancelFocusAnimation()
134 {
135     isDisplay_ = false;
136     if (SystemProperties::GetDeviceType() == DeviceType::TV) {
137         animator_->Pause();
138     }
139     MarkNeedRender(true);
140 }
141 
PerformLayout()142 void RenderFocusAnimation::PerformLayout()
143 {
144     SetLayoutSize(layoutSize_);
145 }
146 
StopFocusAnimation()147 void RenderFocusAnimation::StopFocusAnimation()
148 {
149     if (SystemProperties::GetDeviceType() != DeviceType::TV) {
150         return;
151     }
152     animator_->Stop();
153     MarkNeedRender(true);
154 }
155 
StartFocusAnimation()156 void RenderFocusAnimation::StartFocusAnimation()
157 {
158     isDisplay_ = true;
159     if (SystemProperties::GetDeviceType() == DeviceType::PHONE) {
160         MarkNeedRender();
161     } else if (SystemProperties::GetDeviceType() == DeviceType::TV) {
162         animator_->Play();
163     }
164 }
165 
SetIsKeyEvent(bool isKeyEvent)166 void RenderFocusAnimation::SetIsKeyEvent(bool isKeyEvent)
167 {
168     isKeyEvent_ = isKeyEvent;
169     MarkNeedRender();
170 }
171 
172 } // namespace OHOS::Ace
173