1 /*
2 * Copyright (c) 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 #include "core/components_ng/pattern/folder_stack/folder_stack_pattern.h"
16
17 #include "base/log/dump_log.h"
18 #include "base/memory/ace_type.h"
19 #include "base/utils/utils.h"
20 #include "core/common/container.h"
21 #include "core/common/display_info.h"
22 #include "core/components/common/layout/constants.h"
23 #include "core/components_ng/base/frame_node.h"
24 #include "core/components_ng/layout/layout_property.h"
25 #include "core/components_ng/pattern/folder_stack/control_parts_stack_node.h"
26 #include "core/components_ng/pattern/folder_stack/folder_stack_event_hub.h"
27 #include "core/components_ng/pattern/folder_stack/folder_stack_group_node.h"
28 #include "core/components_ng/pattern/folder_stack/folder_stack_layout_algorithm.h"
29 #include "core/components_ng/pattern/folder_stack/folder_stack_layout_property.h"
30 #include "core/components_ng/pattern/folder_stack/folder_stack_pattern.h"
31 #include "core/components_ng/pattern/folder_stack/hover_stack_node.h"
32 #include "core/components_ng/property/property.h"
33 #include "core/components_ng/render/paint_property.h"
34 #include "core/pipeline/pipeline_base.h"
35 #include "core/pipeline_ng/pipeline_context.h"
36
37 namespace OHOS::Ace::NG {
38 namespace {
39 constexpr int32_t ANIMATION_TIME = 400;
40 constexpr int32_t DELAY_TIME = 300;
41 const RefPtr<Curve> FOLDER_STACK_ANIMATION_CURVE =
42 AceType::MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 328.0f, 36.0f);
43 } // namespace
44
OnAttachToFrameNode()45 void FolderStackPattern::OnAttachToFrameNode()
46 {
47 Pattern::OnAttachToFrameNode();
48 auto pipeline = PipelineContext::GetCurrentContext();
49 CHECK_NULL_VOID(pipeline);
50 CHECK_NULL_VOID(OHOS::Ace::SystemProperties::IsBigFoldProduct());
51 auto callbackId = pipeline->RegisterFoldStatusChangedCallback([weak = WeakClaim(this)](FoldStatus folderStatus) {
52 auto pattern = weak.Upgrade();
53 if (pattern) {
54 pattern->RefreshStack(folderStatus);
55 }
56 });
57 UpdateFoldStatusChangedCallbackId(callbackId);
58 }
59
OnDetachFromFrameNode(FrameNode * node)60 void FolderStackPattern::OnDetachFromFrameNode(FrameNode* node)
61 {
62 auto pipeline = PipelineContext::GetCurrentContext();
63 CHECK_NULL_VOID(pipeline);
64 if (HasFoldStatusChangedCallbackId()) {
65 pipeline->UnRegisterFoldStatusChangedCallback(foldStatusChangedCallbackId_.value_or(-1));
66 }
67 Pattern::OnDetachFromFrameNode(node);
68 }
69
OnModifyDone()70 void FolderStackPattern::OnModifyDone()
71 {
72 Pattern::OnModifyDone();
73 InitFolderStackPatternAppearCallback();
74 }
75
InitFolderStackPatternAppearCallback()76 void FolderStackPattern::InitFolderStackPatternAppearCallback()
77 {
78 auto frameNode = GetHost();
79 CHECK_NULL_VOID(frameNode);
80 if (isAppearCallback_) {
81 return;
82 }
83 auto eventHub = frameNode->GetEventHub<EventHub>();
84 CHECK_NULL_VOID(eventHub);
85 auto onDisappear = [weak = WeakClaim(this)]() {
86 auto folderStackPattern = weak.Upgrade();
87 CHECK_NULL_VOID(folderStackPattern);
88 folderStackPattern->RestoreScreenState();
89 };
90 eventHub->SetOnDisappear(std::move(onDisappear));
91 isAppearCallback_ = true;
92 }
93
DumpInfo()94 void FolderStackPattern::DumpInfo()
95 {
96 CHECK_NULL_VOID(displayInfo_);
97 auto rotation = displayInfo_->GetRotation();
98 DumpLog::GetInstance().AddDesc(std::string("rotation: ").append(std::to_string(static_cast<int32_t>(rotation))));
99 }
100
SetLayoutBeforeAnimation(const RefPtr<FolderStackGroupNode> & hostNode)101 void FolderStackPattern::SetLayoutBeforeAnimation(const RefPtr<FolderStackGroupNode>& hostNode)
102 {
103 auto controlPartsStackNode = hostNode->GetControlPartsStackNode();
104 auto index = hostNode->GetChildIndexById(controlPartsStackNode->GetId());
105 auto controlPartsStackWrapper = hostNode->GetOrCreateChildByIndex(index);
106 CHECK_NULL_VOID(controlPartsStackWrapper);
107 auto controlPartsgeometryNode = controlPartsStackWrapper->GetGeometryNode();
108 auto controlPartsOffset = controlPartsgeometryNode->GetMarginFrameOffset();
109 auto controlPartsChildNodeList = controlPartsStackWrapper->GetAllChildrenWithBuild();
110 for (auto& controlPartsChildNode : controlPartsChildNodeList) {
111 auto controlPartsChildGeometryNode = controlPartsChildNode->GetGeometryNode();
112 auto controlPartsChildOffset = OffsetT<float>(controlPartsChildGeometryNode->GetMarginFrameOffset().GetX(),
113 controlPartsOffset.GetY() + controlPartsChildGeometryNode->GetMarginFrameOffset().GetY());
114 controlPartsChildGeometryNode->SetMarginFrameOffset(controlPartsChildOffset);
115 auto controlPartsChildFrameNode = controlPartsChildNode->GetHostNode();
116 if (!controlPartsChildFrameNode) {
117 continue;
118 }
119 auto renderContext = controlPartsChildFrameNode->GetRenderContext();
120 CHECK_NULL_VOID(renderContext);
121 renderContext->SyncGeometryProperties(AceType::RawPtr(controlPartsChildGeometryNode));
122 }
123 auto hoverStackOffset = OffsetT<float>(0.0f, 0.0f);
124 controlPartsgeometryNode->SetMarginFrameOffset(hoverStackOffset);
125 auto ControlPartsFrameNode = AceType::DynamicCast<FrameNode>(controlPartsStackNode);
126 CHECK_NULL_VOID(ControlPartsFrameNode);
127 auto renderContext = ControlPartsFrameNode->GetRenderContext();
128 CHECK_NULL_VOID(renderContext);
129 renderContext->SyncGeometryProperties(AceType::RawPtr(controlPartsgeometryNode));
130 }
131
RefreshStack(FoldStatus foldStatus)132 void FolderStackPattern::RefreshStack(FoldStatus foldStatus)
133 {
134 TAG_LOGD(AceLogTag::ACE_FOLDER_STACK, "the current folding state is:%{public}d", foldStatus);
135 currentFoldStatus_ = foldStatus;
136 if (foldStatusDelayTask_) {
137 foldStatusDelayTask_.Cancel();
138 }
139 auto pipeline = PipelineContext::GetCurrentContext();
140 CHECK_NULL_VOID(pipeline);
141 auto taskExecutor = pipeline->GetTaskExecutor();
142 CHECK_NULL_VOID(taskExecutor);
143 foldStatusDelayTask_.Reset([weak = WeakClaim(this), currentFoldStatus = currentFoldStatus_,
144 lastFoldStatus = lastFoldStatus_]() {
145 auto pattern = weak.Upgrade();
146 CHECK_NULL_VOID(pattern);
147 auto container = Container::Current();
148 CHECK_NULL_VOID(container);
149 auto pipeline = DynamicCast<PipelineContext>(container->GetPipelineContext());
150 CHECK_NULL_VOID(pipeline);
151 auto displayInfo = container->GetDisplayInfo();
152 if (displayInfo->GetFoldStatus() != FoldStatus::HALF_FOLD) {
153 pattern->RestoreScreenState();
154 } else {
155 pattern->SetAutoRotate();
156 }
157 auto windowManager = pipeline->GetWindowManager();
158 auto windowMode = windowManager->GetWindowMode();
159 auto rotation = displayInfo->GetRotation();
160 auto isLandscape = rotation == Rotation::ROTATION_90 || rotation == Rotation::ROTATION_270;
161 if (currentFoldStatus == displayInfo->GetFoldStatus() && isLandscape &&
162 windowMode == WindowMode::WINDOW_MODE_FULLSCREEN) {
163 auto host = pattern->GetHost();
164 CHECK_NULL_VOID(host);
165 auto hostNode = AceType::DynamicCast<FolderStackGroupNode>(host);
166 CHECK_NULL_VOID(hostNode);
167 if (currentFoldStatus == FoldStatus::EXPAND && lastFoldStatus == FoldStatus::HALF_FOLD) {
168 pattern->SetLayoutBeforeAnimation(hostNode);
169 }
170 pattern->OnFolderStateChangeSend(currentFoldStatus);
171 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
172 }
173 pattern->hasFoldStatusDelayTask_ = false;
174 });
175 lastFoldStatus_ = currentFoldStatus_;
176 TAG_LOGD(AceLogTag::ACE_FOLDER_STACK, "the last folding state was:%{public}d", lastFoldStatus_);
177 hasFoldStatusDelayTask_ = true;
178 taskExecutor->PostDelayedTask(
179 foldStatusDelayTask_, TaskExecutor::TaskType::UI, DELAY_TIME, "ArkUIFolderStackStatusChange");
180 }
181
OnFolderStateChangeSend(FoldStatus foldStatus)182 void FolderStackPattern::OnFolderStateChangeSend(FoldStatus foldStatus)
183 {
184 FolderEventInfo event(foldStatus);
185 auto eventHub = GetEventHub<FolderStackEventHub>();
186 if (eventHub) {
187 eventHub->OnFolderStateChange(event);
188 }
189 }
190
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,bool skipMeasure,bool skipLayout)191 bool FolderStackPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, bool skipMeasure, bool skipLayout)
192 {
193 if (skipMeasure && skipLayout) {
194 return false;
195 }
196 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
197 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
198 auto folderStackLayoutAlgorithm =
199 DynamicCast<FolderStackLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
200 CHECK_NULL_RETURN(folderStackLayoutAlgorithm, false);
201 auto isIntoFolderStack = folderStackLayoutAlgorithm->GetIsIntoFolderStack();
202 if (isIntoFolderStack != hasInHoverMode_) {
203 StartOffsetEnteringAnimation();
204 }
205 hasInHoverMode_ = isIntoFolderStack;
206 return false;
207 }
208
StartOffsetEnteringAnimation()209 void FolderStackPattern::StartOffsetEnteringAnimation()
210 {
211 auto host = GetHost();
212 if (!host->GetLayoutProperty<FolderStackLayoutProperty>()->GetEnableAnimation().value_or(true)) {
213 return;
214 }
215 AnimationOption optionPosition;
216 optionPosition.SetDuration(ANIMATION_TIME);
217 optionPosition.SetCurve(FOLDER_STACK_ANIMATION_CURVE);
218 auto renderContext = GetRenderContext();
219 auto pipeline = host->GetContext();
220 CHECK_NULL_VOID(pipeline);
221 auto pageNode = pipeline->GetStageManager()->GetLastPage();
222 auto pageHeight = pageNode->GetGeometryNode()->GetFrameSize().Height();
223 TranslateOptions rawTranslate = TranslateOptions(0.0f, pageHeight, 0.0f);
224 renderContext->OnTransformTranslateUpdate(rawTranslate);
225 TranslateOptions targetTranslate = TranslateOptions(0.0f, 0.0f, 0.0f);
226 AnimationUtils::Animate(optionPosition, [&]() { renderContext->OnTransformTranslateUpdate(targetTranslate); });
227 }
228
GetRenderContext()229 RefPtr<RenderContext> FolderStackPattern::GetRenderContext()
230 {
231 auto frameNode = GetHost();
232 CHECK_NULL_RETURN(frameNode, nullptr);
233 return frameNode->GetRenderContext();
234 }
235
BeforeCreateLayoutWrapper()236 void FolderStackPattern::BeforeCreateLayoutWrapper()
237 {
238 Pattern::BeforeCreateLayoutWrapper();
239 UpdateChildAlignment();
240 SetAutoRotate();
241 }
242
SetAutoRotate()243 void FolderStackPattern::SetAutoRotate()
244 {
245 auto layoutProperty = GetLayoutProperty<FolderStackLayoutProperty>();
246 auto autoHalfFold = layoutProperty->GetAutoHalfFold().value_or(true);
247 auto container = Container::Current();
248 CHECK_NULL_VOID(container);
249 auto displayInfo = container->GetDisplayInfo();
250 CHECK_NULL_VOID(displayInfo);
251 displayInfo_ = displayInfo;
252 auto foldStatus = displayInfo->GetFoldStatus();
253 auto orientation = container->GetOrientation();
254 TAG_LOGI(AceLogTag::ACE_FOLDER_STACK,
255 "the autoHalfFold state is:%{public}d, direction of rotation is:%{public}d",
256 autoHalfFold, orientation);
257 if (autoHalfFold && foldStatus == FoldStatus::HALF_FOLD && orientation != Orientation::SENSOR) {
258 container->SetOrientation(Orientation::SENSOR);
259 isScreenRotationLocked_ = true;
260 lastOrientation_ = orientation;
261 isNeedRestoreScreenState_ = true;
262 }
263 }
264
OnVisibleChange(bool isVisible)265 void FolderStackPattern::OnVisibleChange(bool isVisible)
266 {
267 Pattern::OnVisibleChange(isVisible);
268 if (!isVisible) {
269 RestoreScreenState();
270 }
271 }
272
RestoreScreenState()273 void FolderStackPattern::RestoreScreenState()
274 {
275 if (isNeedRestoreScreenState_) {
276 isNeedRestoreScreenState_ = false;
277 auto container = Container::Current();
278 CHECK_NULL_VOID(container);
279 TAG_LOGD(AceLogTag::ACE_FOLDER_STACK, "set orientation to lastOrientation:%{public}d", lastOrientation_);
280 container->SetOrientation(lastOrientation_);
281 }
282 }
283
UpdateChildAlignment()284 void FolderStackPattern::UpdateChildAlignment()
285 {
286 auto hostNode = AceType::DynamicCast<FolderStackGroupNode>(GetHost());
287 CHECK_NULL_VOID(hostNode);
288 auto folderStackLayoutProperty = GetLayoutProperty<FolderStackLayoutProperty>();
289 CHECK_NULL_VOID(folderStackLayoutProperty);
290 auto align = Alignment::CENTER;
291 if (folderStackLayoutProperty->GetPositionProperty()) {
292 align = folderStackLayoutProperty->GetPositionProperty()->GetAlignment().value_or(Alignment::CENTER);
293 }
294 auto controlPartsStackNode = AceType::DynamicCast<ControlPartsStackNode>(hostNode->GetControlPartsStackNode());
295 if (controlPartsStackNode) {
296 auto controlPartsLayoutProperty =
297 AceType::DynamicCast<LayoutProperty>(controlPartsStackNode->GetLayoutProperty());
298 controlPartsLayoutProperty->UpdateAlignment(align);
299 }
300 auto hoverStackNode = AceType::DynamicCast<HoverStackNode>(hostNode->GetHoverNode());
301 if (hoverStackNode) {
302 auto hoverLayoutProperty = AceType::DynamicCast<LayoutProperty>(hoverStackNode->GetLayoutProperty());
303 hoverLayoutProperty->UpdateAlignment(align);
304 }
305 }
306
DumpSimplifyInfo(std::unique_ptr<JsonValue> & json)307 void FolderStackPattern::DumpSimplifyInfo(std::unique_ptr<JsonValue>& json)
308 {
309 CHECK_NULL_VOID(displayInfo_);
310 auto rotation = displayInfo_->GetRotation();
311 json->Put("Rotation", static_cast<int32_t>(rotation));
312 }
313 } // namespace OHOS::Ace::NG