1 /*
2 * Copyright (c) 2021-2022 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_v2/pattern_lock/render_pattern_lock.h"
17
18 namespace OHOS::Ace::V2 {
RenderPatternLock()19 RenderPatternLock::RenderPatternLock()
20 {
21 touchRecognizer_ = AceType::MakeRefPtr<RawRecognizer>();
22 auto weak = AceType::WeakClaim(this);
23 touchRecognizer_->SetOnTouchDown([weak](const TouchEventInfo& info) {
24 auto patternLock = weak.Upgrade();
25 if (patternLock && !info.GetTouches().empty()) {
26 const auto& locationInfo = info.GetTouches().front();
27 double moveDeltaX = locationInfo.GetLocalLocation().GetX();
28 double moveDeltaY = locationInfo.GetLocalLocation().GetY();
29 Offset touchPoint;
30 touchPoint.SetX(moveDeltaX);
31 touchPoint.SetY(moveDeltaY);
32 patternLock->HandleCellTouchDown(touchPoint);
33 }
34 });
35 touchRecognizer_->SetOnTouchMove([weak](const TouchEventInfo& info) {
36 auto patternLock = weak.Upgrade();
37 if (patternLock && !info.GetTouches().empty()) {
38 const auto& locationInfo = info.GetTouches().front();
39 double moveDeltaX = locationInfo.GetLocalLocation().GetX();
40 double moveDeltaY = locationInfo.GetLocalLocation().GetY();
41 Offset touchPoint;
42 touchPoint.SetX(moveDeltaX);
43 touchPoint.SetY(moveDeltaY);
44 patternLock->HandleCellTouchMove(touchPoint);
45 }
46 });
47 touchRecognizer_->SetOnTouchUp([weak](const TouchEventInfo& info) {
48 auto patternLock = weak.Upgrade();
49 if (patternLock) {
50 patternLock->HandleCellTouchUp();
51 }
52 });
53 touchRecognizer_->SetOnTouchCancel([weak](const TouchEventInfo& info) {
54 auto patternLock = weak.Upgrade();
55 if (patternLock) {
56 patternLock->HandleCellTouchCancel();
57 }
58 });
59 }
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)60 void RenderPatternLock::OnTouchTestHit(
61 const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
62 {
63 touchRecognizer_->SetCoordinateOffset(coordinateOffset);
64 result.emplace_back(touchRecognizer_);
65 }
HandleCellTouchDown(const Offset & offset)66 void RenderPatternLock::HandleCellTouchDown(const Offset& offset)
67 {
68 if (!CheckAutoReset()) {
69 return;
70 }
71 HandleReset();
72 cellCenter_ = offset;
73 bool isAdd = false;
74 for (int16_t i = 0; i < COL_COUNT && !isAdd; i++) {
75 for (int16_t j = 0; j < COL_COUNT && !isAdd; j++) {
76 isAdd = AddChoosePoint(offset, i + 1, j + 1);
77 }
78 }
79 MarkNeedRender();
80 isMoveEventValid_ = true;
81 }
HandleCellTouchMove(const Offset & offset)82 void RenderPatternLock::HandleCellTouchMove(const Offset& offset)
83 {
84 if (!isMoveEventValid_) {
85 return;
86 }
87 cellCenter_ = offset;
88 bool isAdd = false;
89 for (int16_t i = 0; i < COL_COUNT && !isAdd; i++) {
90 for (int16_t j = 0; j < COL_COUNT && !isAdd; j++) {
91 isAdd = AddChoosePoint(offset, i + 1, j + 1);
92 }
93 }
94 MarkNeedRender();
95 }
HandleCellTouchUp()96 void RenderPatternLock::HandleCellTouchUp()
97 {
98 if (!CheckAutoReset()) {
99 return;
100 }
101 animator_->Finish();
102 isMoveEventValid_ = false;
103 std::vector<int> chooseCellVec;
104 for (auto it = choosePoint_.begin(); it != choosePoint_.end(); it++) {
105 chooseCellVec.push_back((*it).GetCode());
106 }
107 if (callbackForJS_) {
108 auto event = std::make_shared<PatternCompleteEvent>(chooseCellVec);
109 if (event) {
110 callbackForJS_(event);
111 }
112 }
113 animator_->SetDuration(DOWN_DURATION);
114 animator_->Forward();
115 MarkNeedRender();
116 }
117
HandleCellTouchCancel()118 void RenderPatternLock::HandleCellTouchCancel()
119 {
120 HandleCellTouchUp();
121 }
UpdateAttr(const RefPtr<Component> & component)122 void RenderPatternLock::UpdateAttr(const RefPtr<Component>& component)
123 {
124 const auto& patternLockComponent = AceType::DynamicCast<PatternLockComponent>(component);
125 if (!patternLockComponent) {
126 LOGE("PatternLockComponent is null!");
127 return;
128 }
129 sideLength_ = patternLockComponent->GetSideLength().Value() < 0.0 ? 0.0_vp : patternLockComponent->GetSideLength();
130 double cSideLength = patternLockComponent->GetSideLength().ConvertToVp();
131 double cCircleRadius = patternLockComponent->GetCircleRadius().ConvertToVp();
132 const int16_t radiusCount = COL_COUNT * RADIUS_TO_DIAMETER;
133 double handleCircleRadius = cCircleRadius > cSideLength / SCALE_SELECTED_CIRCLE_RADIUS / radiusCount
134 ? cSideLength / SCALE_SELECTED_CIRCLE_RADIUS / radiusCount
135 : cCircleRadius;
136 circleRadius_ = Dimension(handleCircleRadius < 0 ? 0 : handleCircleRadius, DimensionUnit::VP);
137 double cStrokeWidth = patternLockComponent->GetStrokeWidth().ConvertToVp();
138 double handleStrokeWidth = cStrokeWidth > cSideLength / COL_COUNT ? cSideLength / COL_COUNT : cStrokeWidth;
139 strokeWidth_ = Dimension(handleStrokeWidth < 0 ? 0 : handleStrokeWidth, DimensionUnit::VP);
140 circleRadiusAnimatorToIncrease_ = circleRadius_;
141 circleRadiusAnimatorToDecrease_ = circleRadius_ * SCALE_ACTIVE_CIRCLE_RADIUS;
142 regularColor_ = patternLockComponent->GetRegularColor();
143 selectedColor_ = patternLockComponent->GetSelectedColor();
144 activeColor_ = patternLockComponent->GetActiveColor();
145 pathColor_ = patternLockComponent->GetPathColor();
146 autoReset_ = patternLockComponent->GetAutoReset();
147 callbackForJS_ = AceAsyncEvent<void(const std::shared_ptr<PatternCompleteEvent>&)>::Create(
148 patternLockComponent->GetPatternCompleteEvent(), context_);
149 patternLockController_ = patternLockComponent->GetPatternLockController();
150 if (patternLockController_) {
151 auto weak = AceType::WeakClaim(this);
152 patternLockController_->SetResetImpl([weak]() {
153 auto patternLock = weak.Upgrade();
154 if (patternLock) {
155 patternLock->HandleReset();
156 }
157 });
158 }
159 }
Update(const RefPtr<Component> & component)160 void RenderPatternLock::Update(const RefPtr<Component>& component)
161 {
162 UpdateAttr(component);
163 // animator
164 if (!animator_) {
165 animator_ = CREATE_ANIMATOR(GetContext());
166 auto touchAnimation = AceType::MakeRefPtr<CurveAnimation<double>>(0.0, 1.0, Curves::SHARP);
167 touchAnimation->AddListener([weak = AceType::WeakClaim(this)](double value) {
168 auto patternLock = weak.Upgrade();
169 if (patternLock) {
170 Dimension radiusFir { patternLock->circleRadius_.ConvertToVp() *
171 (1 + (SCALE_SELECTED_CIRCLE_RADIUS - 1) * value),
172 DimensionUnit::VP };
173 patternLock->circleRadiusAnimatorToIncrease_ = radiusFir;
174 double decreaseRate = 1 + (1 - value) * (SCALE_DECREASE - 1);
175 Dimension radiusSec { patternLock->circleRadius_.ConvertToVp() * SCALE_ACTIVE_CIRCLE_RADIUS *
176 decreaseRate,
177 DimensionUnit::VP };
178 patternLock->circleRadiusAnimatorToDecrease_ = radiusSec;
179 patternLock->MarkNeedRender();
180 }
181 });
182 animator_->ClearInterpolators();
183 animator_->AddInterpolator(touchAnimation);
184 animator_->SetFillMode(FillMode::FORWARDS);
185 }
186 MarkNeedLayout();
187 }
PerformLayout()188 void RenderPatternLock::PerformLayout()
189 {
190 Size layoutSizeAfterConstrain =
191 GetLayoutParam().Constrain(Size(NormalizeToPx(sideLength_), NormalizeToPx(sideLength_)));
192 SetLayoutSize(layoutSizeAfterConstrain);
193 }
AddChoosePoint(Offset offset,int16_t x,int16_t y)194 bool RenderPatternLock::AddChoosePoint(Offset offset, int16_t x, int16_t y)
195 {
196 const int16_t scale = RADIUS_TO_DIAMETER;
197 double offsetX = NormalizeToPx(sideLength_) / COL_COUNT / scale * (scale * x - 1);
198 double offsetY = NormalizeToPx(sideLength_) / COL_COUNT / scale * (scale * y - 1);
199 Offset centerOffset;
200 centerOffset.SetX(offsetX);
201 centerOffset.SetY(offsetY);
202 double distance = (offset - centerOffset).GetDistance();
203 if (distance <= (NormalizeToPx(circleRadius_) * SCALE_SELECTED_CIRCLE_RADIUS)) {
204 if (!CheckChoosePoint(x, y)) {
205 AddPassPoint(offset, x, y);
206 animator_->SetDuration(DOWN_DURATION);
207 animator_->Forward();
208 choosePoint_.push_back(PatternLockCell(x, y));
209 }
210 return true;
211 }
212 return false;
213 }
HandleReset()214 void RenderPatternLock::HandleReset()
215 {
216 isMoveEventValid_ = false;
217 choosePoint_.clear();
218 cellCenter_ = Offset::Zero();
219 MarkNeedRender();
220 }
GetCircleCenterByXY(const Offset & offset,int16_t x,int16_t y)221 Offset RenderPatternLock::GetCircleCenterByXY(const Offset& offset, int16_t x, int16_t y)
222 {
223 const int16_t scale = RADIUS_TO_DIAMETER;
224 Offset cellCenter;
225 cellCenter.SetX(offset.GetX() + NormalizeToPx(sideLength_) / COL_COUNT / scale * (x * scale - 1));
226 cellCenter.SetY(offset.GetY() + NormalizeToPx(sideLength_) / COL_COUNT / scale * (y * scale - 1));
227 return cellCenter;
228 }
CheckChoosePoint(int16_t x,int16_t y) const229 bool RenderPatternLock::CheckChoosePoint(int16_t x, int16_t y) const
230 {
231 for (auto it = choosePoint_.begin(); it != choosePoint_.end(); it++) {
232 if ((*it).GetColumn() == x && (*it).GetRow() == y) {
233 return true;
234 }
235 }
236 return false;
237 }
CheckChoosePointIsLastIndex(int16_t x,int16_t y,int16_t index) const238 bool RenderPatternLock::CheckChoosePointIsLastIndex(int16_t x, int16_t y, int16_t index) const
239 {
240 if (!choosePoint_.empty() && static_cast<int16_t>(choosePoint_.size()) >= index) {
241 if (choosePoint_.at(choosePoint_.size() - static_cast<uint32_t>(index)).GetColumn() == x &&
242 choosePoint_.at(choosePoint_.size() - static_cast<uint32_t>(index)).GetRow() == y) {
243 return true;
244 }
245 }
246 return false;
247 }
CheckAutoReset() const248 bool RenderPatternLock::CheckAutoReset() const
249 {
250 if (!autoReset_ && !choosePoint_.empty() && !isMoveEventValid_) {
251 return false;
252 }
253 return true;
254 }
AddPassPoint(Offset offset,int16_t x,int16_t y)255 void RenderPatternLock::AddPassPoint(Offset offset, int16_t x, int16_t y)
256 {
257 if (choosePoint_.empty()) {
258 return;
259 }
260 passPointCount_ = 0;
261 PatternLockCell lastCell = choosePoint_.back();
262 int16_t lastX = lastCell.GetColumn();
263 int16_t lastY = lastCell.GetRow();
264 int16_t lastCode = lastCell.GetCode();
265 int16_t nowCode = COL_COUNT * (y - 1) + (x - 1);
266 std::vector<PatternLockCell> passPointVec;
267 for (int16_t i = 1; i <= COL_COUNT; i++) {
268 for (int16_t j = 1; j <= COL_COUNT; j++) {
269 PatternLockCell passPoint = PatternLockCell(i, j);
270 if ((passPoint.GetCode() >= nowCode && passPoint.GetCode() >= lastCode) ||
271 (passPoint.GetCode() <= nowCode && passPoint.GetCode() <= lastCode)) {
272 continue;
273 }
274 if ((j != y) && (j != lastY) &&
275 ((double(lastX - i) / (lastY - j) == double(i - x) / (j - y)) && !CheckChoosePoint(i, j))) {
276 passPointVec.push_back(passPoint);
277 }
278 if ((j == lastY) && (j == y) && !CheckChoosePoint(i, j)) {
279 passPointVec.push_back(passPoint);
280 }
281 }
282 }
283 size_t passPointLength = passPointVec.size();
284 if (passPointLength == 0) {
285 return;
286 }
287 passPointCount_ = static_cast<int16_t>(passPointLength);
288 if (nowCode > lastCode) {
289 choosePoint_.push_back(passPointVec.front());
290 if (passPointLength > 1) {
291 choosePoint_.push_back(passPointVec.back());
292 }
293 } else {
294 choosePoint_.push_back(passPointVec.back());
295 if (passPointLength > 1) {
296 choosePoint_.push_back(passPointVec.front());
297 }
298 }
299 }
300 } // namespace OHOS::Ace::V2
301