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