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