1a3e0fd82Sopenharmony_ci/* 2a3e0fd82Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd. 3a3e0fd82Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4a3e0fd82Sopenharmony_ci * you may not use this file except in compliance with the License. 5a3e0fd82Sopenharmony_ci * You may obtain a copy of the License at 6a3e0fd82Sopenharmony_ci * 7a3e0fd82Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8a3e0fd82Sopenharmony_ci * 9a3e0fd82Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10a3e0fd82Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11a3e0fd82Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12a3e0fd82Sopenharmony_ci * See the License for the specific language governing permissions and 13a3e0fd82Sopenharmony_ci * limitations under the License. 14a3e0fd82Sopenharmony_ci */ 15a3e0fd82Sopenharmony_ci 16a3e0fd82Sopenharmony_ci#include "dock/focus_manager.h" 17a3e0fd82Sopenharmony_ci#if ENABLE_FOCUS_MANAGER 18a3e0fd82Sopenharmony_ci#include "components/root_view.h" 19a3e0fd82Sopenharmony_ci#include "gfx_utils/graphic_math.h" 20a3e0fd82Sopenharmony_ci 21a3e0fd82Sopenharmony_ci#include "common/input_method_manager.h" 22a3e0fd82Sopenharmony_ci 23a3e0fd82Sopenharmony_cinamespace OHOS { 24a3e0fd82Sopenharmony_ciFocusManager* FocusManager::GetInstance() 25a3e0fd82Sopenharmony_ci{ 26a3e0fd82Sopenharmony_ci static FocusManager instance; 27a3e0fd82Sopenharmony_ci return &instance; 28a3e0fd82Sopenharmony_ci} 29a3e0fd82Sopenharmony_ci 30a3e0fd82Sopenharmony_cibool FocusManager::RequestFocus(UIView* view) 31a3e0fd82Sopenharmony_ci{ 32a3e0fd82Sopenharmony_ci if (view == nullptr || view == focusView_ || !view->IsFocusable() || 33a3e0fd82Sopenharmony_ci !view->IsVisible()) { 34a3e0fd82Sopenharmony_ci return false; 35a3e0fd82Sopenharmony_ci } 36a3e0fd82Sopenharmony_ci lastFocusView_ = focusView_; 37a3e0fd82Sopenharmony_ci focusView_ = view; 38a3e0fd82Sopenharmony_ci 39a3e0fd82Sopenharmony_ci UIViewGroup* rootView = RootView::GetInstance(); 40a3e0fd82Sopenharmony_ci if (RootView::FindSubView(*rootView, lastFocusView_)) { 41a3e0fd82Sopenharmony_ci lastFocusView_->Blur(); 42a3e0fd82Sopenharmony_ci } 43a3e0fd82Sopenharmony_ci focusView_->Focus(); 44a3e0fd82Sopenharmony_ci 45a3e0fd82Sopenharmony_ci UIViewType viewType = focusView_->GetViewType(); 46a3e0fd82Sopenharmony_ci // show keyboard if the view is edittable 47a3e0fd82Sopenharmony_ci if (viewType == UI_EDIT_TEXT) { 48a3e0fd82Sopenharmony_ci InputMethodManager::GetInstance().ShowInputMethod(focusView_); 49a3e0fd82Sopenharmony_ci } 50a3e0fd82Sopenharmony_ci 51a3e0fd82Sopenharmony_ci return true; 52a3e0fd82Sopenharmony_ci} 53a3e0fd82Sopenharmony_ci 54a3e0fd82Sopenharmony_cibool FocusManager::ClearFocus() 55a3e0fd82Sopenharmony_ci{ 56a3e0fd82Sopenharmony_ci if (focusView_ == nullptr) { 57a3e0fd82Sopenharmony_ci return false; 58a3e0fd82Sopenharmony_ci } 59a3e0fd82Sopenharmony_ci lastFocusView_ = focusView_; 60a3e0fd82Sopenharmony_ci focusView_->Blur(); 61a3e0fd82Sopenharmony_ci focusView_ = nullptr; 62a3e0fd82Sopenharmony_ci return true; 63a3e0fd82Sopenharmony_ci} 64a3e0fd82Sopenharmony_ci 65a3e0fd82Sopenharmony_cibool FocusManager::RequestFocusByDirection(uint8_t direction) 66a3e0fd82Sopenharmony_ci{ 67a3e0fd82Sopenharmony_ci if (focusView_ != nullptr) { 68a3e0fd82Sopenharmony_ci UIView* candidate = nullptr; 69a3e0fd82Sopenharmony_ci if (GetNextFocus(focusView_, candidate, direction)) { 70a3e0fd82Sopenharmony_ci return RequestFocus(candidate); 71a3e0fd82Sopenharmony_ci } 72a3e0fd82Sopenharmony_ci } 73a3e0fd82Sopenharmony_ci return false; 74a3e0fd82Sopenharmony_ci} 75a3e0fd82Sopenharmony_ci 76a3e0fd82Sopenharmony_cibool FocusManager::CompareCandidates(UIView* focusedView, UIView*& candidate, UIView* current, uint8_t direction) 77a3e0fd82Sopenharmony_ci{ 78a3e0fd82Sopenharmony_ci if (current == focusedView) { 79a3e0fd82Sopenharmony_ci return false; 80a3e0fd82Sopenharmony_ci } 81a3e0fd82Sopenharmony_ci bool res = false; 82a3e0fd82Sopenharmony_ci switch (direction) { 83a3e0fd82Sopenharmony_ci case FOCUS_DIRECTION_UP: { 84a3e0fd82Sopenharmony_ci res = CompareCandidatesByUp(focusedView, candidate, current); 85a3e0fd82Sopenharmony_ci break; 86a3e0fd82Sopenharmony_ci } 87a3e0fd82Sopenharmony_ci case FOCUS_DIRECTION_DOWN: { 88a3e0fd82Sopenharmony_ci res = CompareCandidatesByDown(focusedView, candidate, current); 89a3e0fd82Sopenharmony_ci break; 90a3e0fd82Sopenharmony_ci } 91a3e0fd82Sopenharmony_ci case FOCUS_DIRECTION_LEFT: { 92a3e0fd82Sopenharmony_ci res = CompareCandidatesByLeft(focusedView, candidate, current); 93a3e0fd82Sopenharmony_ci break; 94a3e0fd82Sopenharmony_ci } 95a3e0fd82Sopenharmony_ci case FOCUS_DIRECTION_RIGHT: { 96a3e0fd82Sopenharmony_ci res = CompareCandidatesByRight(focusedView, candidate, current); 97a3e0fd82Sopenharmony_ci break; 98a3e0fd82Sopenharmony_ci } 99a3e0fd82Sopenharmony_ci default: 100a3e0fd82Sopenharmony_ci return false; 101a3e0fd82Sopenharmony_ci } 102a3e0fd82Sopenharmony_ci return res; 103a3e0fd82Sopenharmony_ci} 104a3e0fd82Sopenharmony_ci 105a3e0fd82Sopenharmony_cibool FocusManager::IsAtSameCol(const Rect& rect1, const Rect& rect2) 106a3e0fd82Sopenharmony_ci{ 107a3e0fd82Sopenharmony_ci return ((rect1.GetLeft() < rect2.GetRight()) && (rect1.GetRight() > rect2.GetLeft())); 108a3e0fd82Sopenharmony_ci} 109a3e0fd82Sopenharmony_ci 110a3e0fd82Sopenharmony_cibool FocusManager::IsAtSameRow(const Rect& rect1, const Rect& rect2) 111a3e0fd82Sopenharmony_ci{ 112a3e0fd82Sopenharmony_ci return ((rect1.GetBottom() < rect2.GetTop()) && (rect1.GetTop() > rect2.GetBottom())); 113a3e0fd82Sopenharmony_ci} 114a3e0fd82Sopenharmony_ci 115a3e0fd82Sopenharmony_cibool FocusManager::CompareCandidatesByUp(UIView* focusedView, UIView*& candidate, UIView* current) 116a3e0fd82Sopenharmony_ci{ 117a3e0fd82Sopenharmony_ci Rect focusedViewRect = focusedView->GetRect(); 118a3e0fd82Sopenharmony_ci Rect currentRect = current->GetRect(); 119a3e0fd82Sopenharmony_ci if (currentRect.GetBottom() >= focusedViewRect.GetBottom()) { 120a3e0fd82Sopenharmony_ci return false; 121a3e0fd82Sopenharmony_ci } 122a3e0fd82Sopenharmony_ci if (candidate != nullptr) { 123a3e0fd82Sopenharmony_ci Rect candidateRect = candidate->GetRect(); 124a3e0fd82Sopenharmony_ci if (IsAtSameCol(focusedViewRect, currentRect) && IsAtSameCol(focusedViewRect, candidateRect)) { 125a3e0fd82Sopenharmony_ci return currentRect.GetBottom() > candidateRect.GetBottom(); 126a3e0fd82Sopenharmony_ci } 127a3e0fd82Sopenharmony_ci return CompareCandidatesDistance(focusedViewRect, candidateRect, currentRect); 128a3e0fd82Sopenharmony_ci } 129a3e0fd82Sopenharmony_ci return true; 130a3e0fd82Sopenharmony_ci} 131a3e0fd82Sopenharmony_ci 132a3e0fd82Sopenharmony_cibool FocusManager::CompareCandidatesByDown(UIView* focusedView, UIView*& candidate, UIView* current) 133a3e0fd82Sopenharmony_ci{ 134a3e0fd82Sopenharmony_ci Rect focusedViewRect = focusedView->GetRect(); 135a3e0fd82Sopenharmony_ci Rect currentRect = current->GetRect(); 136a3e0fd82Sopenharmony_ci if (currentRect.GetTop() <= focusedViewRect.GetTop()) { 137a3e0fd82Sopenharmony_ci return false; 138a3e0fd82Sopenharmony_ci } 139a3e0fd82Sopenharmony_ci if (candidate != nullptr) { 140a3e0fd82Sopenharmony_ci Rect candidateRect = candidate->GetRect(); 141a3e0fd82Sopenharmony_ci if (IsAtSameCol(focusedViewRect, currentRect) && IsAtSameCol(focusedViewRect, candidateRect)) { 142a3e0fd82Sopenharmony_ci return currentRect.GetTop() < candidateRect.GetTop(); 143a3e0fd82Sopenharmony_ci } 144a3e0fd82Sopenharmony_ci return CompareCandidatesDistance(focusedViewRect, candidateRect, currentRect); 145a3e0fd82Sopenharmony_ci } 146a3e0fd82Sopenharmony_ci return true; 147a3e0fd82Sopenharmony_ci} 148a3e0fd82Sopenharmony_ci 149a3e0fd82Sopenharmony_cibool FocusManager::CompareCandidatesByLeft(UIView* focusedView, UIView*& candidate, UIView* current) 150a3e0fd82Sopenharmony_ci{ 151a3e0fd82Sopenharmony_ci Rect focusedViewRect = focusedView->GetRect(); 152a3e0fd82Sopenharmony_ci Rect currentRect = current->GetRect(); 153a3e0fd82Sopenharmony_ci if (currentRect.GetRight() >= focusedViewRect.GetRight()) { 154a3e0fd82Sopenharmony_ci return false; 155a3e0fd82Sopenharmony_ci } 156a3e0fd82Sopenharmony_ci if (candidate != nullptr) { 157a3e0fd82Sopenharmony_ci Rect candidateRect = candidate->GetRect(); 158a3e0fd82Sopenharmony_ci if (IsAtSameRow(focusedViewRect, currentRect) && IsAtSameRow(focusedViewRect, candidateRect)) { 159a3e0fd82Sopenharmony_ci return currentRect.GetRight() > candidateRect.GetRight(); 160a3e0fd82Sopenharmony_ci } 161a3e0fd82Sopenharmony_ci return CompareCandidatesDistance(focusedViewRect, candidateRect, currentRect); 162a3e0fd82Sopenharmony_ci } 163a3e0fd82Sopenharmony_ci return true; 164a3e0fd82Sopenharmony_ci} 165a3e0fd82Sopenharmony_ci 166a3e0fd82Sopenharmony_cibool FocusManager::CompareCandidatesByRight(UIView* focusedView, UIView*& candidate, UIView* current) 167a3e0fd82Sopenharmony_ci{ 168a3e0fd82Sopenharmony_ci Rect focusedViewRect = focusedView->GetRect(); 169a3e0fd82Sopenharmony_ci Rect currentRect = current->GetRect(); 170a3e0fd82Sopenharmony_ci if (currentRect.GetLeft() <= focusedViewRect.GetLeft()) { 171a3e0fd82Sopenharmony_ci return false; 172a3e0fd82Sopenharmony_ci } 173a3e0fd82Sopenharmony_ci if (candidate != nullptr) { 174a3e0fd82Sopenharmony_ci Rect candidateRect = candidate->GetRect(); 175a3e0fd82Sopenharmony_ci if (IsAtSameRow(focusedViewRect, currentRect) && IsAtSameRow(focusedViewRect, candidateRect)) { 176a3e0fd82Sopenharmony_ci return currentRect.GetLeft() < candidateRect.GetLeft(); 177a3e0fd82Sopenharmony_ci } 178a3e0fd82Sopenharmony_ci return CompareCandidatesDistance(focusedViewRect, candidateRect, currentRect); 179a3e0fd82Sopenharmony_ci } 180a3e0fd82Sopenharmony_ci return true; 181a3e0fd82Sopenharmony_ci} 182a3e0fd82Sopenharmony_ci 183a3e0fd82Sopenharmony_cibool FocusManager::CompareCandidatesDistance(const Rect& focused, const Rect& candidate, const Rect& current) 184a3e0fd82Sopenharmony_ci{ 185a3e0fd82Sopenharmony_ci uint64_t xDiff1 = focused.GetX() - candidate.GetX(); 186a3e0fd82Sopenharmony_ci uint64_t yDiff1 = focused.GetY() - candidate.GetY(); 187a3e0fd82Sopenharmony_ci uint64_t xDiff2 = focused.GetX() - current.GetX(); 188a3e0fd82Sopenharmony_ci uint64_t yDiff2 = focused.GetY() - current.GetY(); 189a3e0fd82Sopenharmony_ci uint64_t distance1 = xDiff1 * xDiff1 + yDiff1 * yDiff1; 190a3e0fd82Sopenharmony_ci uint64_t distance2 = xDiff2 * xDiff2 + yDiff2 * yDiff2; 191a3e0fd82Sopenharmony_ci return distance2 < distance1; 192a3e0fd82Sopenharmony_ci} 193a3e0fd82Sopenharmony_ci 194a3e0fd82Sopenharmony_cibool FocusManager::GetNextFocus(UIView* focusedView, UIView*& candidate, uint8_t direction) 195a3e0fd82Sopenharmony_ci{ 196a3e0fd82Sopenharmony_ci UIView* parent = focusedView->GetParent(); 197a3e0fd82Sopenharmony_ci if (parent == nullptr) { 198a3e0fd82Sopenharmony_ci return false; 199a3e0fd82Sopenharmony_ci } 200a3e0fd82Sopenharmony_ci UIView* child = nullptr; 201a3e0fd82Sopenharmony_ci bool isFoundBestCandidate = false; 202a3e0fd82Sopenharmony_ci UIView* current = focusedView; 203a3e0fd82Sopenharmony_ci while (parent != nullptr) { 204a3e0fd82Sopenharmony_ci if (isFoundBestCandidate) { 205a3e0fd82Sopenharmony_ci return true; 206a3e0fd82Sopenharmony_ci } 207a3e0fd82Sopenharmony_ci child = static_cast<UIViewGroup*>(parent)->GetChildrenHead(); 208a3e0fd82Sopenharmony_ci while (child != nullptr) { 209a3e0fd82Sopenharmony_ci if (child == current) { 210a3e0fd82Sopenharmony_ci child = child->GetNextSibling(); 211a3e0fd82Sopenharmony_ci continue; 212a3e0fd82Sopenharmony_ci } 213a3e0fd82Sopenharmony_ci if (child->IsViewGroup()) { 214a3e0fd82Sopenharmony_ci if (GetNextFocus(focusedView, candidate, static_cast<UIViewGroup*>(child), direction)) { 215a3e0fd82Sopenharmony_ci isFoundBestCandidate = true; 216a3e0fd82Sopenharmony_ci } 217a3e0fd82Sopenharmony_ci } else { 218a3e0fd82Sopenharmony_ci if (GetNextFocus(focusedView, candidate, child, direction)) { 219a3e0fd82Sopenharmony_ci isFoundBestCandidate = true; 220a3e0fd82Sopenharmony_ci } 221a3e0fd82Sopenharmony_ci } 222a3e0fd82Sopenharmony_ci child = child->GetNextSibling(); 223a3e0fd82Sopenharmony_ci } 224a3e0fd82Sopenharmony_ci if (isFoundBestCandidate) { 225a3e0fd82Sopenharmony_ci return true; 226a3e0fd82Sopenharmony_ci } else { 227a3e0fd82Sopenharmony_ci current = parent; 228a3e0fd82Sopenharmony_ci } 229a3e0fd82Sopenharmony_ci parent = parent->GetParent(); 230a3e0fd82Sopenharmony_ci } 231a3e0fd82Sopenharmony_ci return false; 232a3e0fd82Sopenharmony_ci} 233a3e0fd82Sopenharmony_ci 234a3e0fd82Sopenharmony_cibool FocusManager::GetNextFocus(UIView* focusedView, UIView*& candidate, UIView* view, uint8_t direction) 235a3e0fd82Sopenharmony_ci{ 236a3e0fd82Sopenharmony_ci UIView* current = view; 237a3e0fd82Sopenharmony_ci if (!current->IsVisible() || !current->IsFocusable()) { 238a3e0fd82Sopenharmony_ci return false; 239a3e0fd82Sopenharmony_ci } 240a3e0fd82Sopenharmony_ci if (CompareCandidates(focusedView, candidate, current, direction)) { 241a3e0fd82Sopenharmony_ci candidate = current; 242a3e0fd82Sopenharmony_ci return true; 243a3e0fd82Sopenharmony_ci } 244a3e0fd82Sopenharmony_ci return false; 245a3e0fd82Sopenharmony_ci} 246a3e0fd82Sopenharmony_ci 247a3e0fd82Sopenharmony_cibool FocusManager::GetNextFocus(UIView* focusedView, UIView*& candidate, UIViewGroup* viewGroup, uint8_t direction) 248a3e0fd82Sopenharmony_ci{ 249a3e0fd82Sopenharmony_ci UIViewGroup* current = viewGroup; 250a3e0fd82Sopenharmony_ci if (!current->IsVisible() || !current->IsFocusable()) { 251a3e0fd82Sopenharmony_ci return false; 252a3e0fd82Sopenharmony_ci } 253a3e0fd82Sopenharmony_ci if (current->IsInterceptFocus()) { 254a3e0fd82Sopenharmony_ci return GetNextFocus(focusedView, candidate, static_cast<UIView*>(current), direction); 255a3e0fd82Sopenharmony_ci } 256a3e0fd82Sopenharmony_ci 257a3e0fd82Sopenharmony_ci UIView* child = current->GetChildrenHead(); 258a3e0fd82Sopenharmony_ci bool childFocusable = false; 259a3e0fd82Sopenharmony_ci while (child != nullptr) { 260a3e0fd82Sopenharmony_ci if (child == focusedView) { 261a3e0fd82Sopenharmony_ci child = child->GetNextSibling(); 262a3e0fd82Sopenharmony_ci continue; 263a3e0fd82Sopenharmony_ci } 264a3e0fd82Sopenharmony_ci if (child->IsViewGroup()) { 265a3e0fd82Sopenharmony_ci if (GetNextFocus(focusedView, candidate, static_cast<UIViewGroup*>(child), direction)) { 266a3e0fd82Sopenharmony_ci childFocusable = true; 267a3e0fd82Sopenharmony_ci } 268a3e0fd82Sopenharmony_ci } else if (GetNextFocus(focusedView, candidate, child, direction)) { 269a3e0fd82Sopenharmony_ci childFocusable = true; 270a3e0fd82Sopenharmony_ci } 271a3e0fd82Sopenharmony_ci child = child->GetNextSibling(); 272a3e0fd82Sopenharmony_ci } 273a3e0fd82Sopenharmony_ci return childFocusable; 274a3e0fd82Sopenharmony_ci} 275a3e0fd82Sopenharmony_ci} 276a3e0fd82Sopenharmony_ci#endif 277