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