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 
16 #include "core/components_ng/pattern/patternlock/patternlock_modifier.h"
17 
18 #include <algorithm>
19 #include <string>
20 #include <vector>
21 
22 #include "base/geometry/dimension.h"
23 #include "base/geometry/ng/offset_t.h"
24 #include "base/geometry/ng/size_t.h"
25 #include "base/memory/ace_type.h"
26 #include "base/utils/utils.h"
27 #include "core/common/container.h"
28 #include "core/components/common/properties/color.h"
29 #include "core/components_ng/base/modifier.h"
30 #include "core/components_ng/pattern/patternlock/patternlock_paint_property.h"
31 #include "core/components_ng/render/drawing.h"
32 #include "core/components_ng/render/drawing_prop_convertor.h"
33 
34 namespace OHOS::Ace::NG {
35 namespace {
36 constexpr int32_t PATTERN_LOCK_COL_COUNT = 3;
37 constexpr int32_t PATTERN_LOCK_POINT_COUNT = 9;
38 constexpr int32_t RADIUS_TO_DIAMETER = 2;
39 constexpr float FLASH_POINT_OPACITY = 0.5f;
40 constexpr int32_t ACTIVE_RADIUS_ANIMATION_DURATION = 200;
41 constexpr int32_t LIGHT_RING_RADIUS_ANIMATION_DURATION = 500;
42 constexpr int32_t LIGHT_RING_ALPHAF_ANIMATION_DURATION_FIRST = 200;
43 constexpr int32_t LIGHT_RING_ALPHAF_ANIMATION_DURATION_SECOND = 300;
44 constexpr int32_t CONNECT_ANIMATION_DURATION_FIRST = 100;
45 constexpr int32_t WRONG_ANIMATION_DURATION_DIMMING = 150;
46 constexpr int32_t WRONG_ANIMATION_DURATION_BRIGHTENING = 200;
47 constexpr int32_t WRONG_ANIMATION_DURATION_FLASH_ONCE =
48     WRONG_ANIMATION_DURATION_DIMMING + WRONG_ANIMATION_DURATION_BRIGHTENING;
49 constexpr int32_t WRONG_ANIMATION_DURATION_FLASH_TWICE =
50     WRONG_ANIMATION_DURATION_FLASH_ONCE + WRONG_ANIMATION_DURATION_FLASH_ONCE;
51 constexpr float BACKGROUND_RADIUS_SPRING_RESPONSE = 0.347f;
52 constexpr float BACKGROUND_RADIUS_SPRING_DAMPING = 0.55f;
53 constexpr Dimension LIGHT_RING_LINE_WIDTH = 2.5_vp;
54 constexpr Dimension LIGHT_RING_MASK_RADIUS = 10.0_vp;
55 constexpr float LIGHT_RING_ALPHAF_START = 0.0f;
56 constexpr float LIGHT_RING_ALPHAF_END = 0.5f;
57 constexpr float CONNECTED_LINE_SPRING_RESPONSE = 0.22f;
58 constexpr float CONNECTED_LINE_SPRING_DAMPING = 0.88f;
59 constexpr float CANCELED_LINE_SPRING_RESPONSE = 0.22f;
60 constexpr float CANCELED_LINE_SPRING_DAMPING = 0.88f;
61 constexpr float CANCELED_LINE_MIN_POINT = 0.1f;
62 constexpr int32_t ANIMATABLE_POINT_COUNT = 2;
63 constexpr float DIAMETER_TO_RADIUS = 0.5f;
64 constexpr float GRADUAL_CHANGE_POINT = 0.5;
65 constexpr int32_t MAX_ALPHA = 255;
66 constexpr double EPSILON = 0.01f;
67 } // namespace
68 
PatternLockCell(int32_t column,int32_t row)69 PatternLockCell::PatternLockCell(int32_t column, int32_t row)
70 {
71     column_ = column;
72     row_ = row;
73     code_ = PATTERN_LOCK_COL_COUNT * (row - 1) + (column - 1);
74 }
75 
CreateProperties()76 void PatternLockModifier::CreateProperties()
77 {
78     sideLength_ = AceType::MakeRefPtr<PropertyFloat>(0.0f);
79     circleRadius_ = AceType::MakeRefPtr<PropertyFloat>(0.0f);
80     regularColor_ = AceType::MakeRefPtr<PropertyColor>(Color::BLACK);
81     selectedColor_ = AceType::MakeRefPtr<PropertyColor>(Color::BLACK);
82     activeColor_ = AceType::MakeRefPtr<PropertyColor>(Color::BLACK);
83     hoverColor_ = AceType::MakeRefPtr<PropertyColor>(Color::BLACK);
84     wrongColor_ = AceType::MakeRefPtr<PropertyColor>(Color::RED);
85     correctColor_ = AceType::MakeRefPtr<PropertyColor>(Color::BLUE);
86     pathColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color::BLUE));
87     pointAnimateColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color::BLACK));
88     pathStrokeWidth_ = AceType::MakeRefPtr<PropertyFloat>(0.0f);
89     offset_ = AceType::MakeRefPtr<PropertyOffsetF>(OffsetF());
90     cellCenter_ = AceType::MakeRefPtr<PropertyOffsetF>(OffsetF());
91     isMoveEventValid_ = AceType::MakeRefPtr<PropertyBool>(false);
92     isHover_ = AceType::MakeRefPtr<PropertyBool>(false);
93     hoverIndex_ = AceType::MakeRefPtr<PropertyInt>(-1);
94     connectedLineTailPoint_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(OffsetF());
95     canceledLineTailPoint_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(OffsetF());
96     activeCircleColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color::BLACK));
97     activeBackgroundRadius_ = AceType::MakeRefPtr<PropertyFloat>(0.0f);
98     enableWaveEffect_ = AceType::MakeRefPtr<PropertyBool>(false);
99 }
100 
AttachProperties()101 void PatternLockModifier::AttachProperties()
102 {
103     AttachProperty(sideLength_);
104     AttachProperty(circleRadius_);
105     AttachProperty(regularColor_);
106     AttachProperty(selectedColor_);
107     AttachProperty(activeColor_);
108     AttachProperty(hoverColor_);
109     AttachProperty(wrongColor_);
110     AttachProperty(correctColor_);
111     AttachProperty(pathColor_);
112     AttachProperty(pointAnimateColor_);
113     AttachProperty(pathStrokeWidth_);
114     AttachProperty(cellCenter_);
115     AttachProperty(offset_);
116     AttachProperty(isMoveEventValid_);
117     AttachProperty(isHover_);
118     AttachProperty(hoverIndex_);
119     AttachProperty(connectedLineTailPoint_);
120     AttachProperty(canceledLineTailPoint_);
121     AttachProperty(activeCircleColor_);
122     AttachProperty(activeBackgroundRadius_);
123     AttachProperty(enableWaveEffect_);
124 }
125 
PatternLockModifier()126 PatternLockModifier::PatternLockModifier()
127 {
128     CreateProperties();
129     AttachProperties();
130     for (size_t count = 0; count < PATTERN_LOCK_POINT_COUNT; count++) {
131         auto backgroundRadius = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f);
132         AttachProperty(backgroundRadius);
133         backgroundCircleRadius_.emplace_back(backgroundRadius);
134 
135         auto activeRadius = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f);
136         AttachProperty(activeRadius);
137         activeCircleRadius_.emplace_back(activeRadius);
138 
139         auto lightRingRadius = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f);
140         AttachProperty(lightRingRadius);
141         lightRingRadius_.emplace_back(lightRingRadius);
142 
143         auto lightRingAlphaF = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f);
144         AttachProperty(lightRingAlphaF);
145         lightRingAlphaF_.emplace_back(lightRingAlphaF);
146     }
147 }
148 
onDraw(DrawingContext & context)149 void PatternLockModifier::onDraw(DrawingContext& context)
150 {
151     auto pipeline = PipelineBase::GetCurrentContext();
152     CHECK_NULL_VOID(pipeline);
153     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
154         DrawForApiNine(context);
155         return;
156     }
157     auto& canvas = context.canvas;
158     PaintLockLine(canvas, offset_->Get());
159     canvas.Save();
160     for (int i = 0; i < PATTERN_LOCK_COL_COUNT; i++) {
161         for (int j = 0; j < PATTERN_LOCK_COL_COUNT; j++) {
162             PaintLockCircle(canvas, offset_->Get(), i + 1, j + 1);
163         }
164     }
165     canvas.Restore();
166 }
167 
DrawForApiNine(DrawingContext & context)168 void PatternLockModifier::DrawForApiNine(DrawingContext& context)
169 {
170     auto& canvas = context.canvas;
171     PaintLockLineForApiNine(canvas, offset_->Get());
172     canvas.Save();
173     for (int i = 0; i < PATTERN_LOCK_COL_COUNT; i++) {
174         for (int j = 0; j < PATTERN_LOCK_COL_COUNT; j++) {
175             PaintLockCircleForApiNine(canvas, offset_->Get(), i + 1, j + 1);
176         }
177     }
178     canvas.Restore();
179 }
180 
PaintLockLineForApiNine(RSCanvas & canvas,const OffsetF & offset)181 void PatternLockModifier::PaintLockLineForApiNine(RSCanvas& canvas, const OffsetF& offset)
182 {
183     size_t count = choosePoint_.size();
184     if (count == 0) {
185         return;
186     }
187 
188     float sideLength = sideLength_->Get();
189     float pathStrokeWidth = pathStrokeWidth_->Get();
190     if (LessOrEqual(pathStrokeWidth, 0.0)) {
191         return;
192     }
193     float handleStrokeWidth = std::min(pathStrokeWidth, sideLength / PATTERN_LOCK_COL_COUNT);
194     pathStrokeWidth = std::max(handleStrokeWidth, 0.0f);
195 
196     auto pathColor = pathColor_->Get();
197     auto cellCenter = cellCenter_->Get();
198     RSPen pen;
199     pen.SetAntiAlias(true);
200     pen.SetColor(ToRSColor(pathColor));
201     pen.SetWidth(pathStrokeWidth);
202     pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
203 
204     Color pathColorAlpha255 = pathColor.ToColor().ChangeAlpha(MAX_ALPHA);
205     pen.SetColor(pathColorAlpha255.GetValue());
206     canvas.AttachPen(pen);
207     for (size_t i = 0; i < count - 1; i++) {
208         OffsetF pointBegin = GetCircleCenterByXY(offset, choosePoint_[i].GetColumn(), choosePoint_[i].GetRow());
209         OffsetF pointEnd = GetCircleCenterByXY(offset, choosePoint_[i + 1].GetColumn(), choosePoint_[i + 1].GetRow());
210         canvas.DrawLine(RSPoint(pointBegin.GetX(), pointBegin.GetY()), RSPoint(pointEnd.GetX(), pointEnd.GetY()));
211     }
212     if (isMoveEventValid_->Get()) {
213         OffsetF pointBegin =
214             GetCircleCenterByXY(offset, choosePoint_[count - 1].GetColumn(), choosePoint_[count - 1].GetRow());
215         float x1 = pointBegin.GetX();
216         float y1 = pointBegin.GetY();
217         float x2 = cellCenter.GetX();
218         float y2 = cellCenter.GetY();
219         x2 = x2 > offset.GetX() + sideLength ? offset.GetX() + sideLength : x2;
220         x2 = x2 < offset.GetX() ? offset.GetX() : x2;
221         y2 = y2 > offset.GetY() + sideLength ? offset.GetY() + sideLength : y2;
222         y2 = y2 < offset.GetY() ? offset.GetY() : y2;
223 
224         std::vector<RSColorQuad> colors = { pathColorAlpha255.GetValue(), pathColorAlpha255.GetValue(),
225             pathColorAlpha255.ChangeOpacity(0.0).GetValue() };
226         std::vector<RSScalar> pos = { 0.0, GRADUAL_CHANGE_POINT, 1.0 };
227         auto shader = pen.GetShaderEffect();
228         shader->CreateLinearGradient(RSPoint(x1, y1), RSPoint(x2, y2), colors, pos, RSTileMode::CLAMP);
229         pen.SetShaderEffect(shader);
230         canvas.DrawLine(RSPoint(x1, y1), RSPoint(x2, y2));
231     }
232     canvas.DetachPen();
233     canvas.Restore();
234 }
235 
PaintLockCircleForApiNine(RSCanvas & canvas,const OffsetF & offset,int32_t x,int32_t y)236 void PatternLockModifier::PaintLockCircleForApiNine(RSCanvas& canvas, const OffsetF& offset, int32_t x, int32_t y)
237 {
238     auto activeColor = activeColor_->Get();
239     auto regularColor = regularColor_->Get();
240     auto selectedColor = selectedColor_->Get();
241     auto sideLength = sideLength_->Get();
242     auto circleRadius = circleRadius_->Get();
243 
244     RSBrush brush;
245     brush.SetAntiAlias(true);
246     brush.SetColor(ToRSColor(regularColor));
247     OffsetF cellcenter = GetCircleCenterByXY(offset, x, y);
248     OffsetF firstCellcenter = GetCircleCenterByXY(offset, 1, 1);
249     float offsetX = cellcenter.GetX();
250     float offsetY = cellcenter.GetY();
251     const int32_t radiusCount = RADIUS_TO_DIAMETER * PATTERN_LOCK_COL_COUNT;
252     float handleCircleRadius = std::min(circleRadius, sideLength / scaleBackgroundCircleRadius_ / radiusCount);
253     circleRadius = std::max(handleCircleRadius, 0.0f);
254     if (CheckChoosePoint(x, y)) {
255         const int32_t lastIndexFir = 1;
256         if (CheckChoosePointIsLastIndex(x, y, lastIndexFir)) {
257             if (isMoveEventValid_->Get()) {
258                 brush.SetColor(ToRSColor(activeColor));
259                 canvas.AttachBrush(brush);
260                 auto radius = circleRadius * scaleBackgroundCircleRadius_;
261                 canvas.DrawCircle(
262                     RSPoint(offsetX, offsetY), std::min(static_cast<float>(radius), firstCellcenter.GetX()));
263             } else {
264                 brush.SetColor(ToRSColor(selectedColor));
265                 canvas.AttachBrush(brush);
266                 canvas.DrawCircle(RSPoint(offsetX, offsetY), circleRadius * scaleActiveCircleRadius_);
267             }
268         } else {
269             brush.SetColor(ToRSColor(selectedColor));
270             canvas.AttachBrush(brush);
271             canvas.DrawCircle(RSPoint(offsetX, offsetY), circleRadius * scaleActiveCircleRadius_);
272         }
273     } else {
274         canvas.AttachBrush(brush);
275         canvas.DrawCircle(RSPoint(offsetX, offsetY), circleRadius);
276     }
277     canvas.DetachBrush();
278 }
279 
PaintLockLine(RSCanvas & canvas,const OffsetF & offset)280 void PatternLockModifier::PaintLockLine(RSCanvas& canvas, const OffsetF& offset)
281 {
282     size_t count = choosePoint_.size();
283     if (count < 1) {
284         return;
285     }
286 
287     float sideLength = sideLength_->Get();
288     float pathStrokeWidth = pathStrokeWidth_->Get();
289     if (LessOrEqual(pathStrokeWidth, 0.0)) {
290         return;
291     }
292     float handleStrokeWidth = std::min(pathStrokeWidth, sideLength / PATTERN_LOCK_COL_COUNT);
293     pathStrokeWidth = std::max(handleStrokeWidth, 0.0f);
294 
295     auto pathColor = pathColor_->Get();
296     RSPen pen;
297     pen.SetAntiAlias(true);
298     pen.SetWidth(pathStrokeWidth);
299     pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
300 
301     pen.SetColor(pathColor.GetValue());
302     canvas.Save();
303     SetCircleClip(canvas);
304     canvas.AttachPen(pen);
305     RSPath path;
306     if (count > ANIMATABLE_POINT_COUNT) {
307         for (size_t i = 0; i < count - ANIMATABLE_POINT_COUNT; i++) {
308             OffsetF pointBegin = GetCircleCenterByXY(offset, choosePoint_[i].GetColumn(), choosePoint_[i].GetRow());
309             OffsetF pointEnd =
310                 GetCircleCenterByXY(offset, choosePoint_[i + 1].GetColumn(), choosePoint_[i + 1].GetRow());
311             path.MoveTo(pointBegin.GetX(), pointBegin.GetY());
312             path.LineTo(pointEnd.GetX(), pointEnd.GetY());
313         }
314     }
315     AddConnectedLineToPath(path, offset);
316     if (isMoveEventValid_->Get()) {
317         OffsetF pointBegin =
318             GetCircleCenterByXY(offset, choosePoint_[count - 1].GetColumn(), choosePoint_[count - 1].GetRow());
319         OffsetF pointEnd = GetPointEndByCellCenter();
320         if (pointEnd != pointBegin) {
321             path.MoveTo(pointBegin.GetX(), pointBegin.GetY());
322             path.LineTo(pointEnd.GetX(), pointEnd.GetY());
323         }
324     }
325     AddCanceledLineToPath(path, offset);
326     canvas.DrawPath(path);
327     canvas.DetachPen();
328     canvas.Restore();
329 }
330 
AddConnectedLineToPath(RSPath & path,const OffsetF & offset)331 void PatternLockModifier::AddConnectedLineToPath(RSPath& path, const OffsetF& offset)
332 {
333     size_t count = choosePoint_.size();
334     if (count < ANIMATABLE_POINT_COUNT) {
335         return;
336     }
337     OffsetF pointBegin = GetCircleCenterByXY(offset, choosePoint_[count - ANIMATABLE_POINT_COUNT].GetColumn(),
338         choosePoint_[count - ANIMATABLE_POINT_COUNT].GetRow());
339     OffsetF pointEnd = GetConnectedLineTailPoint();
340     if (pointEnd != pointBegin) {
341         path.MoveTo(pointBegin.GetX(), pointBegin.GetY());
342         path.LineTo(pointEnd.GetX(), pointEnd.GetY());
343     }
344 }
345 
AddCanceledLineToPath(RSPath & path,const OffsetF & offset)346 void PatternLockModifier::AddCanceledLineToPath(RSPath& path, const OffsetF& offset)
347 {
348     if (!needCanceledLine_) {
349         return;
350     }
351     size_t count = choosePoint_.size();
352     OffsetF pointBegin =
353         GetCircleCenterByXY(offset, choosePoint_[count - 1].GetColumn(), choosePoint_[count - 1].GetRow());
354     OffsetF pointEnd = GetCanceledLineTailPoint();
355     if ((!NearEqual(pointBegin.GetX(), pointEnd.GetX(), EPSILON)
356         || !NearEqual(pointBegin.GetY(), pointEnd.GetY(), EPSILON))
357         && GreatOrEqual(pointEnd.GetY(), CANCELED_LINE_MIN_POINT)) {
358         path.MoveTo(pointBegin.GetX(), pointBegin.GetY());
359         path.LineTo(pointEnd.GetX(), pointEnd.GetY());
360     }
361 }
362 
PaintLockCircle(RSCanvas & canvas,const OffsetF & offset,int32_t x,int32_t y)363 void PatternLockModifier::PaintLockCircle(RSCanvas& canvas, const OffsetF& offset, int32_t x, int32_t y)
364 {
365     auto activeColor = activeColor_->Get();
366     auto regularColor = regularColor_->Get();
367     auto selectedColor = selectedColor_->Get();
368     auto circleRadius = circleRadius_->Get();
369     auto pointAnimateColor = pointAnimateColor_->Get();
370     auto activeCircleColor = activeCircleColor_->Get();
371 
372     OffsetF cellcenter = GetCircleCenterByXY(offset, x, y);
373     float offsetX = cellcenter.GetX();
374     float offsetY = cellcenter.GetY();
375 
376     auto index = (x - 1) * PATTERN_LOCK_COL_COUNT + y - 1;
377     if (CheckChoosePoint(x, y)) {
378         PaintCircle(canvas, offsetX, offsetY, GetBackgroundCircleRadius(index), ToRSColor(activeCircleColor));
379         PaintLightRing(canvas, offsetX, offsetY, GetLightRingCircleRadius(index), GetLightRingAlphaF(index));
380         const int32_t lastIndexFir = 1;
381         CheckIsHoverAndPaint(canvas, offsetX, offsetY, GetActiveCircleRadius(index), index);
382         if (isMoveEventValid_->Get() && CheckChoosePointIsLastIndex(x, y, lastIndexFir)) {
383             PaintCircle(canvas, offsetX, offsetY, GetActiveCircleRadius(index), ToRSColor(activeColor));
384         } else {
385             if (challengeResult_.has_value()) {
386                 PaintCircle(canvas, offsetX, offsetY, GetActiveCircleRadius(index), ToRSColor(pointAnimateColor));
387             } else {
388                 PaintCircle(canvas, offsetX, offsetY, GetActiveCircleRadius(index), ToRSColor(selectedColor));
389             }
390         }
391     } else {
392         CheckIsHoverAndPaint(canvas, offsetX, offsetY, circleRadius, index);
393         PaintCircle(canvas, offsetX, offsetY, circleRadius, ToRSColor(regularColor));
394     }
395 }
396 
CheckIsHoverAndPaint(RSCanvas & canvas,float offsetX,float offsetY,float radius,int32_t index)397 void PatternLockModifier::CheckIsHoverAndPaint(
398     RSCanvas& canvas, float offsetX, float offsetY, float radius, int32_t index)
399 {
400     if (isHover_->Get() && hoverIndex_->Get() == index) {
401         PaintCircle(canvas, offsetX, offsetY, radius * hoverRadiusScale_, ToRSColor(hoverColor_->Get()));
402     }
403 }
404 
PaintCircle(RSCanvas & canvas,float offsetX,float offsetY,float radius,const RSColor & circleColor)405 void PatternLockModifier::PaintCircle(
406     RSCanvas& canvas, float offsetX, float offsetY, float radius, const RSColor& circleColor)
407 {
408     RSBrush brush;
409     brush.SetAntiAlias(true);
410     brush.SetColor(circleColor);
411     canvas.AttachBrush(brush);
412     canvas.DrawCircle(RSPoint(offsetX, offsetY), radius);
413     canvas.DetachBrush();
414 }
415 
PaintLightRing(RSCanvas & canvas,float offsetX,float offsetY,float radius,float alphaF)416 void PatternLockModifier::PaintLightRing(RSCanvas& canvas, float offsetX, float offsetY, float radius, float alphaF)
417 {
418     if (NearZero(alphaF)) {
419         return;
420     }
421     RSPen pen;
422     pen.SetWidth(LIGHT_RING_LINE_WIDTH.ConvertToPx());
423     pen.SetAntiAlias(true);
424     pen.SetColor(ToRSColor(activeColor_->Get()));
425     pen.SetAlphaF(alphaF);
426     RSFilter filter;
427     filter.SetMaskFilter(RSMaskFilter::CreateBlurMaskFilter(
428         RSBlurType::NORMAL, RSDrawing::ConvertRadiusToSigma(LIGHT_RING_MASK_RADIUS.ConvertToPx())));
429     pen.SetFilter(filter);
430 
431     canvas.AttachPen(pen);
432     RSPath path;
433     path.AddCircle(offsetX, offsetY, radius);
434     canvas.DrawPath(path);
435     canvas.DetachPen();
436 }
437 
CheckChoosePoint(int32_t x,int32_t y) const438 bool PatternLockModifier::CheckChoosePoint(int32_t x, int32_t y) const
439 {
440     for (auto it : choosePoint_) {
441         if (it.GetColumn() == x && it.GetRow() == y) {
442             return true;
443         }
444     }
445     return false;
446 }
447 
CheckChoosePointIsLastIndex(int32_t x,int32_t y,int32_t index) const448 bool PatternLockModifier::CheckChoosePointIsLastIndex(int32_t x, int32_t y, int32_t index) const
449 {
450     if (!choosePoint_.empty() && static_cast<int32_t>(choosePoint_.size()) >= index) {
451         if (choosePoint_.at(choosePoint_.size() - static_cast<uint32_t>(index)).GetColumn() == x &&
452             choosePoint_.at(choosePoint_.size() - static_cast<uint32_t>(index)).GetRow() == y) {
453             return true;
454         }
455     }
456     return false;
457 }
458 
GetCircleCenterByXY(const OffsetF & offset,int32_t x,int32_t y)459 OffsetF PatternLockModifier::GetCircleCenterByXY(const OffsetF& offset, int32_t x, int32_t y)
460 {
461     float sideLength = sideLength_->Get();
462     OffsetF cellCenter;
463     int32_t scale = RADIUS_TO_DIAMETER;
464     cellCenter.SetX(offset.GetX() + sideLength / PATTERN_LOCK_COL_COUNT / scale * (x * scale - 1));
465     cellCenter.SetY(offset.GetY() + sideLength / PATTERN_LOCK_COL_COUNT / scale * (y * scale - 1));
466     return cellCenter;
467 }
468 
SetSideLength(float sideLength)469 void PatternLockModifier::SetSideLength(float sideLength)
470 {
471     CHECK_NULL_VOID(sideLength_);
472     if (!NearEqual(sideLength_->Get(), sideLength)) {
473         sideLength_->Set(sideLength);
474         size_t count = choosePoint_.size();
475         if (count > 0) {
476             OffsetF lastPoint = GetCircleCenterByXY(
477                 offset_->Get(), choosePoint_[count - 1].GetColumn(), choosePoint_[count - 1].GetRow());
478             connectedLineTailPoint_->Set(lastPoint);
479             canceledLineTailPoint_->Set(lastPoint);
480         }
481     }
482 }
483 
SetCircleRadius(float circleRadius)484 void PatternLockModifier::SetCircleRadius(float circleRadius)
485 {
486     CHECK_NULL_VOID(circleRadius_);
487     auto sideLength = sideLength_->Get();
488     if (NearZero(scaleBackgroundCircleRadius_)) {
489         return;
490     }
491     float handleCircleRadius =
492         std::min(circleRadius, sideLength / scaleBackgroundCircleRadius_ / PATTERN_LOCK_COL_COUNT * DIAMETER_TO_RADIUS);
493     circleRadius = std::max(handleCircleRadius, 0.0f);
494     if (!NearEqual(circleRadius_->Get(), circleRadius)) {
495         circleRadius_->Set(circleRadius);
496         for (const auto& cell : choosePoint_) {
497             auto index = (cell.GetColumn() - 1) * PATTERN_LOCK_COL_COUNT + cell.GetRow() - 1;
498             if (index < PATTERN_LOCK_POINT_COUNT && index >= 0) {
499                 backgroundCircleRadius_.at(index)->Set(circleRadius * scaleBackgroundCircleRadius_);
500                 activeCircleRadius_.at(index)->Set(circleRadius * scaleActiveCircleRadius_);
501                 lightRingRadius_.at(index)->Set(circleRadius * scaleLightRingRadiusStart_);
502             }
503         }
504     }
505 }
506 
SetRegularColor(const Color & regularColor)507 void PatternLockModifier::SetRegularColor(const Color& regularColor)
508 {
509     CHECK_NULL_VOID(regularColor_);
510     regularColor_->Set(regularColor);
511 }
512 
SetSelectColor(const Color & selectedColor)513 void PatternLockModifier::SetSelectColor(const Color& selectedColor)
514 {
515     CHECK_NULL_VOID(selectedColor_);
516     if (selectedColor_->Get() != selectedColor) {
517         selectedColor_->Set(selectedColor);
518     }
519 }
520 
SetActiveColor(const Color & activeColor)521 void PatternLockModifier::SetActiveColor(const Color& activeColor)
522 {
523     CHECK_NULL_VOID(activeColor_);
524     activeColor_->Set(activeColor);
525 }
526 
SetPathColor(const LinearColor & pathColor)527 void PatternLockModifier::SetPathColor(const LinearColor& pathColor)
528 {
529     CHECK_NULL_VOID(pathColor_);
530     pathColor_->Set(pathColor);
531 }
532 
SetHoverColor(const Color & hoverColor)533 void PatternLockModifier::SetHoverColor(const Color& hoverColor)
534 {
535     CHECK_NULL_VOID(hoverColor_);
536     if (hoverColor_->Get() != hoverColor) {
537         hoverColor_->Set(hoverColor);
538     }
539 }
540 
SetWrongColor(const Color & wrongColor)541 void PatternLockModifier::SetWrongColor(const Color& wrongColor)
542 {
543     CHECK_NULL_VOID(wrongColor_);
544     if (wrongColor_->Get() != wrongColor) {
545         wrongColor_->Set(wrongColor);
546     }
547 }
548 
SetCorrectColor(const Color & correctColor)549 void PatternLockModifier::SetCorrectColor(const Color& correctColor)
550 {
551     CHECK_NULL_VOID(correctColor_);
552     correctColor_->Set(correctColor);
553 }
554 
SetPathStrokeWidth(float pathStrokeWidth)555 void PatternLockModifier::SetPathStrokeWidth(float pathStrokeWidth)
556 {
557     CHECK_NULL_VOID(pathStrokeWidth_);
558     pathStrokeWidth_->Set(pathStrokeWidth);
559 }
560 
SetContentOffset(const OffsetF & offset)561 void PatternLockModifier::SetContentOffset(const OffsetF& offset)
562 {
563     CHECK_NULL_VOID(offset_);
564     if (!NearEqual(offset_->Get(), offset)) {
565         offset_->Set(offset);
566         size_t count = choosePoint_.size();
567         if (count > 0) {
568             OffsetF lastPoint =
569                 GetCircleCenterByXY(offset, choosePoint_[count - 1].GetColumn(), choosePoint_[count - 1].GetRow());
570             connectedLineTailPoint_->Set(lastPoint);
571             canceledLineTailPoint_->Set(lastPoint);
572         }
573     }
574 }
575 
SetIsMoveEventValid(bool isMoveEventValid)576 void PatternLockModifier::SetIsMoveEventValid(bool isMoveEventValid)
577 {
578     isMoveEventValid_->Set(isMoveEventValid);
579 }
580 
SetIsHover(bool isHover)581 void PatternLockModifier::SetIsHover(bool isHover)
582 {
583     isHover_->Set(isHover);
584 }
585 
SetHoverIndex(int32_t hoverIndex)586 void PatternLockModifier::SetHoverIndex(int32_t hoverIndex)
587 {
588     hoverIndex_->Set(hoverIndex);
589 }
590 
SetActiveCircleColor(const LinearColor & activeCircleColor)591 void PatternLockModifier::SetActiveCircleColor(const LinearColor& activeCircleColor)
592 {
593     CHECK_NULL_VOID(activeCircleColor_);
594     activeCircleColor_->Set(activeCircleColor);
595 }
596 
SetActiveBackgroundRadius(float activeBackgroundRadius)597 void PatternLockModifier::SetActiveBackgroundRadius(float activeBackgroundRadius)
598 {
599     CHECK_NULL_VOID(activeBackgroundRadius_);
600     activeBackgroundRadius_->Set(activeBackgroundRadius);
601 }
602 
SetEnableWaveEffect(bool enableWaveEffect)603 void PatternLockModifier::SetEnableWaveEffect(bool enableWaveEffect)
604 {
605     CHECK_NULL_VOID(enableWaveEffect_);
606     enableWaveEffect_->Set(enableWaveEffect);
607 }
608 
StartChallengeResultAnimate()609 void PatternLockModifier::StartChallengeResultAnimate()
610 {
611     if (!challengeResult_.has_value()) {
612         return;
613     }
614     if (challengeResult_.value() == NG::PatternLockChallengeResult::CORRECT) {
615         pointAnimateColor_->Set(LinearColor(selectedColor_->Get()));
616         AnimationOption option = AnimationOption();
617         option.SetDuration(CONNECT_ANIMATION_DURATION_FIRST);
618         option.SetCurve(Curves::SHARP);
619         AnimationUtils::Animate(option, [&]() { pointAnimateColor_->Set(LinearColor(correctColor_->Get())); });
620     } else if (challengeResult_.value() == NG::PatternLockChallengeResult::WRONG) {
621         pointAnimateColor_->Set(LinearColor(wrongColor_->Get()));
622         auto pathColor = pathColor_->Get();
623         auto activeCircleColor = activeCircleColor_->Get();
624         AnimationOption option = AnimationOption();
625         option.SetDuration(WRONG_ANIMATION_DURATION_FLASH_TWICE);
626         option.SetCurve(Curves::SHARP);
627         auto dimmingAnimation = [weak = WeakClaim(this)]() {
628             auto modifier = weak.Upgrade();
629             CHECK_NULL_VOID(modifier);
630             modifier->pointAnimateColor_->Set(
631                 LinearColor(modifier->wrongColor_->Get().BlendOpacity(FLASH_POINT_OPACITY)));
632             modifier->SetPathColor(LinearColor(modifier->pathColor_->Get().BlendOpacity(FLASH_POINT_OPACITY)));
633             modifier->SetActiveCircleColor(
634                 LinearColor(modifier->activeCircleColor_->Get().BlendOpacity(FLASH_POINT_OPACITY)));
635         };
636         auto brighteningAnimation = [weak = WeakClaim(this), pathColor, activeCircleColor]() {
637             auto modifier = weak.Upgrade();
638             CHECK_NULL_VOID(modifier);
639             modifier->pointAnimateColor_->Set(LinearColor(modifier->wrongColor_->Get()));
640             modifier->SetPathColor(pathColor);
641             modifier->SetActiveCircleColor(activeCircleColor);
642         };
643         AnimationUtils::OpenImplicitAnimation(option, Curves::SHARP, nullptr);
644         AnimationUtils::AddKeyFrame(((float)WRONG_ANIMATION_DURATION_DIMMING / WRONG_ANIMATION_DURATION_FLASH_TWICE),
645             Curves::SHARP, dimmingAnimation);
646         AnimationUtils::AddKeyFrame(((float)WRONG_ANIMATION_DURATION_FLASH_ONCE / WRONG_ANIMATION_DURATION_FLASH_TWICE),
647             Curves::SHARP, brighteningAnimation);
648         AnimationUtils::AddKeyFrame(((float)(WRONG_ANIMATION_DURATION_FLASH_ONCE + WRONG_ANIMATION_DURATION_DIMMING) /
649                                         WRONG_ANIMATION_DURATION_FLASH_TWICE),
650             Curves::SHARP, dimmingAnimation);
651         AnimationUtils::AddKeyFrame(1.0f, Curves::SHARP, brighteningAnimation);
652         AnimationUtils::CloseImplicitAnimation();
653     }
654 }
655 
SetChallengeResult(std::optional<NG::PatternLockChallengeResult> & challengeResult)656 void PatternLockModifier::SetChallengeResult(std::optional<NG::PatternLockChallengeResult>& challengeResult)
657 {
658     if (challengeResult_ != challengeResult) {
659         challengeResult_ = challengeResult;
660         StartChallengeResultAnimate();
661     }
662 }
663 
SetCellCenterOffset(const OffsetF & cellcenter)664 void PatternLockModifier::SetCellCenterOffset(const OffsetF& cellcenter)
665 {
666     CHECK_NULL_VOID(cellCenter_);
667     cellCenter_->Set(cellcenter);
668 }
669 
SetChoosePoint(const std::vector<PatternLockCell> & choosePoint)670 void PatternLockModifier::SetChoosePoint(const std::vector<PatternLockCell>& choosePoint)
671 {
672     choosePoint_ = choosePoint;
673 }
674 
SetActiveCircleRadiusScale(float scale)675 void PatternLockModifier::SetActiveCircleRadiusScale(float scale)
676 {
677     scaleActiveCircleRadius_ = scale;
678 }
679 
SetBackgroundCircleRadiusScale(float scale)680 void PatternLockModifier::SetBackgroundCircleRadiusScale(float scale)
681 {
682     scaleBackgroundCircleRadius_ = scale;
683 }
684 
SetLightRingRadiusStartScale(float scale)685 void PatternLockModifier::SetLightRingRadiusStartScale(float scale)
686 {
687     scaleLightRingRadiusStart_ = scale;
688 }
689 
SetLightRingRadiusEndScale(float scale)690 void PatternLockModifier::SetLightRingRadiusEndScale(float scale)
691 {
692     scaleLightRingRadiusEnd_ = scale;
693 }
694 
SetHoverRadiusScale(float scale)695 void PatternLockModifier::SetHoverRadiusScale(float scale)
696 {
697     hoverRadiusScale_ = scale;
698 }
699 
SetBackgroundCircleRadius(int32_t index)700 void PatternLockModifier::SetBackgroundCircleRadius(int32_t index)
701 {
702     auto backgroundCircleRadius = GetBackgroundCircleRadius(index);
703     if (index < static_cast<int32_t>(backgroundCircleRadius_.size()) && index >= 0) {
704         if (enableWaveEffect_->Get()) {
705             backgroundCircleRadius_.at(index)->Set(0.0f);
706             AnimationOption option = AnimationOption();
707             auto curve = AceType::MakeRefPtr<ResponsiveSpringMotion>(
708                 BACKGROUND_RADIUS_SPRING_RESPONSE, BACKGROUND_RADIUS_SPRING_DAMPING);
709             option.SetCurve(curve);
710             AnimationUtils::Animate(option,
711                 [&]() { backgroundCircleRadius_.at(index)->Set(backgroundCircleRadius); });
712         } else {
713             backgroundCircleRadius_.at(index)->Set(backgroundCircleRadius);
714         }
715     }
716 }
717 
GetBackgroundCircleRadius(int32_t index) const718 float PatternLockModifier::GetBackgroundCircleRadius(int32_t index) const
719 {
720     if ((index >= PATTERN_LOCK_POINT_COUNT || index < 0)) {
721         return 0;
722     }
723     auto activeBackgroundRadius = activeBackgroundRadius_->Get();
724     float handleCircleRadius = std::min(activeBackgroundRadius,
725         sideLength_->Get() / PATTERN_LOCK_COL_COUNT * DIAMETER_TO_RADIUS);
726     activeBackgroundRadius = std::max(handleCircleRadius, 0.0f);
727     if (Positive(activeBackgroundRadius)) {
728         backgroundCircleRadius_.at(index)->Set(activeBackgroundRadius);
729     } else {
730         backgroundCircleRadius_.at(index)->Set(circleRadius_->Get() * scaleBackgroundCircleRadius_);
731     }
732     return backgroundCircleRadius_.at(index)->Get();
733 }
734 
SetActiveCircleRadius(int32_t index)735 void PatternLockModifier::SetActiveCircleRadius(int32_t index)
736 {
737     if (index < static_cast<int32_t>(activeCircleRadius_.size()) && index >= 0) {
738         activeCircleRadius_.at(index)->Set(circleRadius_->Get());
739         AnimationOption option = AnimationOption();
740         option.SetDuration(ACTIVE_RADIUS_ANIMATION_DURATION);
741         option.SetCurve(Curves::FRICTION);
742         AnimationUtils::Animate(
743             option, [&]() { activeCircleRadius_.at(index)->Set(circleRadius_->Get() * scaleActiveCircleRadius_); });
744     }
745 }
746 
GetActiveCircleRadius(int32_t index) const747 float PatternLockModifier::GetActiveCircleRadius(int32_t index) const
748 {
749     if ((index >= PATTERN_LOCK_POINT_COUNT || index < 0)) {
750         return 0;
751     }
752     return activeCircleRadius_.at(index)->Get();
753 }
754 
SetLightRingCircleRadius(int32_t index)755 void PatternLockModifier::SetLightRingCircleRadius(int32_t index)
756 {
757     if (index < static_cast<int32_t>(lightRingRadius_.size()) && index >= 0) {
758         auto circleRadius = circleRadius_->Get();
759         lightRingRadius_.at(index)->Set(circleRadius * scaleLightRingRadiusStart_);
760         AnimationOption option = AnimationOption();
761         option.SetDuration(LIGHT_RING_RADIUS_ANIMATION_DURATION);
762         option.SetCurve(Curves::LINEAR);
763         AnimationUtils::Animate(
764             option, [&]() { lightRingRadius_.at(index)->Set(circleRadius * scaleLightRingRadiusEnd_); });
765     }
766 }
767 
GetLightRingCircleRadius(int32_t index) const768 float PatternLockModifier::GetLightRingCircleRadius(int32_t index) const
769 {
770     if ((index >= PATTERN_LOCK_POINT_COUNT || index < 0)) {
771         return 0;
772     }
773     return lightRingRadius_.at(index)->Get();
774 }
775 
SetLightRingAlphaF(int32_t index)776 void PatternLockModifier::SetLightRingAlphaF(int32_t index)
777 {
778     if (index < static_cast<int32_t>(lightRingAlphaF_.size()) && index >= 0) {
779         auto singleLightRingAlphaF = lightRingAlphaF_.at(index);
780         singleLightRingAlphaF->Set(LIGHT_RING_ALPHAF_START);
781         AnimationOption optionFirst = AnimationOption();
782         optionFirst.SetDuration(LIGHT_RING_ALPHAF_ANIMATION_DURATION_FIRST);
783         optionFirst.SetCurve(Curves::SHARP);
784         optionFirst.SetOnFinishEvent([=] {
785             AnimationOption optionSecond = AnimationOption();
786             optionSecond.SetDuration(LIGHT_RING_ALPHAF_ANIMATION_DURATION_SECOND);
787             optionSecond.SetCurve(Curves::SHARP);
788             AnimationUtils::Animate(optionSecond, [=]() { singleLightRingAlphaF->Set(LIGHT_RING_ALPHAF_START); });
789         });
790         AnimationUtils::Animate(
791             optionFirst, [&]() { singleLightRingAlphaF->Set(LIGHT_RING_ALPHAF_END); }, optionFirst.GetOnFinishEvent());
792     }
793 }
794 
GetLightRingAlphaF(int32_t index) const795 float PatternLockModifier::GetLightRingAlphaF(int32_t index) const
796 {
797     if ((index >= PATTERN_LOCK_POINT_COUNT || index < 0)) {
798         return 0;
799     }
800     return lightRingAlphaF_.at(index)->Get();
801 }
802 
SetConnectedLineTailPoint(int32_t x,int32_t y)803 void PatternLockModifier::SetConnectedLineTailPoint(int32_t x, int32_t y)
804 {
805     size_t count = choosePoint_.size();
806     if (count < 1) {
807         return;
808     }
809     OffsetF lastPoint = GetCircleCenterByXY(offset_->Get(), x, y);
810     if (isTouchDown_ && isMoveEventValid_) {
811         connectedLineTailPoint_->Set(cellCenter_->Get());
812         AnimationOption option = AnimationOption();
813         auto curve =
814             AceType::MakeRefPtr<ResponsiveSpringMotion>(CONNECTED_LINE_SPRING_RESPONSE, CONNECTED_LINE_SPRING_DAMPING);
815         option.SetCurve(curve);
816         AnimationUtils::Animate(option, [&]() { connectedLineTailPoint_->Set(lastPoint); });
817     } else {
818         connectedLineTailPoint_->Set(lastPoint);
819     }
820 }
821 
GetConnectedLineTailPoint() const822 OffsetF PatternLockModifier::GetConnectedLineTailPoint() const
823 {
824     return connectedLineTailPoint_->Get();
825 }
826 
SetCanceledLineTailPoint()827 void PatternLockModifier::SetCanceledLineTailPoint()
828 {
829     size_t count = choosePoint_.size();
830     if (count < 1) {
831         return;
832     }
833 
834     canceledLineTailPoint_->Set(GetPointEndByCellCenter());
835     OffsetF pointEnd =
836         GetCircleCenterByXY(offset_->Get(), choosePoint_[count - 1].GetColumn(), choosePoint_[count - 1].GetRow());
837     AnimationOption option = AnimationOption();
838     auto curve =
839         AceType::MakeRefPtr<ResponsiveSpringMotion>(CANCELED_LINE_SPRING_RESPONSE, CANCELED_LINE_SPRING_DAMPING);
840     option.SetCurve(curve);
841     AnimationUtils::Animate(option, [&]() { canceledLineTailPoint_->Set(pointEnd); });
842 }
843 
GetCanceledLineTailPoint() const844 OffsetF PatternLockModifier::GetCanceledLineTailPoint() const
845 {
846     return canceledLineTailPoint_->Get();
847 }
848 
StartConnectedCircleAnimate(int32_t x,int32_t y)849 void PatternLockModifier::StartConnectedCircleAnimate(int32_t x, int32_t y)
850 {
851     auto index = (x - 1) * PATTERN_LOCK_COL_COUNT + y - 1;
852     SetBackgroundCircleRadius(index);
853     SetActiveCircleRadius(index);
854     if (enableWaveEffect_->Get()) {
855         SetLightRingCircleRadius(index);
856         SetLightRingAlphaF(index);
857     }
858 }
859 
StartConnectedLineAnimate(int32_t x,int32_t y)860 void PatternLockModifier::StartConnectedLineAnimate(int32_t x, int32_t y)
861 {
862     SetConnectedLineTailPoint(x, y);
863 }
864 
StartCanceledAnimate()865 void PatternLockModifier::StartCanceledAnimate()
866 {
867     SetCanceledLineTailPoint();
868 }
869 
Reset()870 void PatternLockModifier::Reset()
871 {
872     SetIsTouchDown(false);
873     needCanceledLine_ = false;
874     challengeResult_.reset();
875     choosePoint_.clear();
876     connectedLineTailPoint_->Set(OffsetF());
877     canceledLineTailPoint_->Set(OffsetF());
878     for (auto& radius : backgroundCircleRadius_) {
879         radius->Set(0.0f);
880     }
881     for (auto& radius : activeCircleRadius_) {
882         radius->Set(circleRadius_->Get());
883     }
884     for (auto& radius : lightRingRadius_) {
885         radius->Set(circleRadius_->Get() * scaleLightRingRadiusStart_);
886     }
887     for (auto& alphaF : lightRingAlphaF_) {
888         alphaF->Set(LIGHT_RING_ALPHAF_START);
889     }
890 }
891 
SetIsTouchDown(bool isTouchDown)892 void PatternLockModifier::SetIsTouchDown(bool isTouchDown)
893 {
894     if (isTouchDown_ && (!isTouchDown)) {
895         needCanceledLine_ = true;
896     } else if ((!isTouchDown_) && isTouchDown) {
897         needCanceledLine_ = false;
898     }
899     isTouchDown_ = isTouchDown;
900 }
901 
GetPointEndByCellCenter() const902 OffsetF PatternLockModifier::GetPointEndByCellCenter() const
903 {
904     auto offset = offset_->Get();
905     float sideLength = sideLength_->Get();
906     auto cellCenter = cellCenter_->Get();
907     float x = cellCenter.GetX();
908     float y = cellCenter.GetY();
909     x = x > offset.GetX() + sideLength ? offset.GetX() + sideLength : x;
910     x = x < offset.GetX() ? offset.GetX() : x;
911     y = y > offset.GetY() + sideLength ? offset.GetY() + sideLength : y;
912     y = y < offset.GetY() ? offset.GetY() : y;
913     return OffsetF(x, y);
914 }
915 
SetCircleClip(RSCanvas & canvas)916 void PatternLockModifier::SetCircleClip(RSCanvas& canvas)
917 {
918     int32_t x = 0;
919     int32_t y = 0;
920     int32_t index = 0;
921     OffsetF center;
922     float backgroundCircleRadius = 0.0f;
923     float activeCircleRadius = 0.0f;
924     float clipRadius = 0.0f;
925     RSPath path;
926     for (const auto& point : choosePoint_) {
927         x = point.GetColumn();
928         y = point.GetRow();
929         center = GetCircleCenterByXY(offset_->Get(), x, y);
930         index = (x - 1) * PATTERN_LOCK_COL_COUNT + y - 1;
931         backgroundCircleRadius = GetBackgroundCircleRadius(index);
932         activeCircleRadius = GetActiveCircleRadius(index);
933         clipRadius = backgroundCircleRadius > activeCircleRadius ? backgroundCircleRadius : activeCircleRadius;
934         path.AddCircle(center.GetX(), center.GetY(), clipRadius);
935     }
936     canvas.ClipPath(path, RSClipOp::DIFFERENCE, true);
937 }
938 
UpdateBoundsRect()939 void PatternLockModifier::UpdateBoundsRect()
940 {
941     auto offset = offset_->Get();
942     auto pathStrokeWidth = pathStrokeWidth_->Get();
943     auto sideLength = sideLength_->Get();
944 
945     auto addDistance = circleRadius_->Get() * scaleLightRingRadiusEnd_ -
946                        sideLength_->Get() / PATTERN_LOCK_COL_COUNT / RADIUS_TO_DIAMETER;
947     if (pathStrokeWidth / 2.0f > addDistance) {
948         addDistance = pathStrokeWidth / 2.0f;
949     }
950 
951     RectF boundsRect;
952     boundsRect.SetLeft((offset.GetX() - addDistance) < 0 ? (offset.GetX() - addDistance) : 0);
953     boundsRect.SetTop((offset.GetY() - addDistance) < 0 ? (offset.GetY() - addDistance) : 0);
954     boundsRect.SetWidth(sideLength + addDistance * 2.0f);
955     boundsRect.SetHeight(sideLength + addDistance * 2.0f);
956     SetBoundsRect(boundsRect);
957 }
958 } // namespace OHOS::Ace::NG
959