mirror of
https://github.com/openharmony/ace_ace_engine.git
synced 2026-07-18 12:45:07 -04:00
ede2aaa223
Signed-off-by: kangchongtao <kangchongtao@huawei.com> Change-Id: Ic0fc40d272c7986dec2463680b7b0fe7f5ee72d2 Signed-off-by: kangchongtao <kangchongtao@huawei.com>
1543 lines
59 KiB
C++
1543 lines
59 KiB
C++
/*
|
|
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "js_accessibility_manager.h"
|
|
|
|
#include "accessibility_event_info.h"
|
|
#include "accessibility_system_ability_client.h"
|
|
|
|
#include "adapter/ohos/entrance/ace_application_info.h"
|
|
#include "base/log/dump_log.h"
|
|
#include "base/log/event_report.h"
|
|
#include "base/log/log.h"
|
|
#include "base/utils/linear_map.h"
|
|
#include "base/utils/string_utils.h"
|
|
#include "base/utils/utils.h"
|
|
#include "core/pipeline/pipeline_context.h"
|
|
#include "frameworks/bridge/common/dom/dom_type.h"
|
|
|
|
|
|
using namespace OHOS::Accessibility;
|
|
using namespace std;
|
|
|
|
namespace OHOS::Ace::Framework {
|
|
namespace {
|
|
const int32_t EVENT_DUMP_PARAM_LENGTH = 3;
|
|
const int32_t PROPERTY_DUMP_PARAM_LENGTH = 2;
|
|
const char DUMP_ORDER[] = "-accessibility";
|
|
const char DUMP_INSPECTOR[] = "-inspector";
|
|
const char ACCESSIBILITY_FOCUSED_EVENT[] = "accessibilityfocus";
|
|
const char ACCESSIBILITY_CLEAR_FOCUS_EVENT[] = "accessibilityclearfocus";
|
|
const char TEXT_CHANGE_EVENT[] = "textchange";
|
|
const char PAGE_CHANGE_EVENT[] = "pagechange";
|
|
const char SCROLL_END_EVENT[] = "scrollend";
|
|
const char MOUSE_HOVER_ENTER[] = "mousehoverenter";
|
|
const char MOUSE_HOVER_EXIT[] = "mousehoverexit";
|
|
const char IMPORTANT_YES[] = "yes";
|
|
const char IMPORTANT_NO[] = "no";
|
|
const char IMPORTANT_NO_HIDE_DES[] = "no-hide-descendants";
|
|
constexpr int32_t DEFAULT_PARENT_ID = 2100000;
|
|
constexpr int32_t ROOT_STACK_BASE = 1100000;
|
|
constexpr int32_t CARD_NODE_ID_RATION = 10000;
|
|
constexpr int32_t CARD_ROOT_NODE_ID_RATION = 1000;
|
|
constexpr int32_t CARD_BASE = 100000;
|
|
constexpr int32_t WEIGHTED_VALUE = 13;
|
|
|
|
const int32_t FOCUS_DIRECTION_UP = 1;
|
|
const int32_t FOCUS_DIRECTION_DOWN = 1 << 1;
|
|
const int32_t FOCUS_DIRECTION_LEFT = 1 << 2;
|
|
const int32_t FOCUS_DIRECTION_RIGHT = 1 << 3;
|
|
const int32_t FOCUS_DIRECTION_FORWARD = 1 << 4;
|
|
const int32_t FOCUS_DIRECTION_BACKWARD = 1 << 5;
|
|
|
|
struct ActionTable {
|
|
AceAction aceAction;
|
|
ActionType action;
|
|
};
|
|
|
|
Accessibility::EventType ConvertStrToEventType(const std::string& type)
|
|
{
|
|
// static linear map must be sorted by key.
|
|
static const LinearMapNode<Accessibility::EventType> eventTypeMap[] = {
|
|
{ ACCESSIBILITY_CLEAR_FOCUS_EVENT, Accessibility::EventType::TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED_EVENT },
|
|
{ ACCESSIBILITY_FOCUSED_EVENT, Accessibility::EventType::TYPE_VIEW_ACCESSIBILITY_FOCUSED_EVENT },
|
|
{ DOM_CLICK, Accessibility::EventType::TYPE_VIEW_CLICKED_EVENT },
|
|
{ DOM_FOCUS, Accessibility::EventType::TYPE_VIEW_FOCUSED_EVENT },
|
|
{ DOM_LONG_PRESS, Accessibility::EventType::TYPE_VIEW_LONG_CLICKED_EVENT },
|
|
{ MOUSE_HOVER_ENTER, Accessibility::EventType::TYPE_VIEW_HOVER_ENTER_EVENT },
|
|
{ MOUSE_HOVER_EXIT, Accessibility::EventType::TYPE_VIEW_HOVER_EXIT_EVENT },
|
|
{ PAGE_CHANGE_EVENT, Accessibility::EventType::TYPE_PAGE_STATE_UPDATE },
|
|
{ SCROLL_END_EVENT, Accessibility::EventType::TYPE_VIEW_SCROLLED_EVENT },
|
|
{ DOM_SELECTED, Accessibility::EventType::TYPE_VIEW_SELECTED_EVENT },
|
|
{ TEXT_CHANGE_EVENT, Accessibility::EventType::TYPE_VIEW_TEXT_UPDATE_EVENT },
|
|
{ DOM_TOUCH_END, Accessibility::EventType::TYPE_TOUCH_END },
|
|
{ DOM_TOUCH_START, Accessibility::EventType::TYPE_TOUCH_BEGIN },
|
|
};
|
|
Accessibility::EventType eventType = Accessibility::EventType::TYPE_VIEW_INVALID;
|
|
int64_t idx = BinarySearchFindIndex(eventTypeMap, ArraySize(eventTypeMap), type.c_str());
|
|
if (idx >= 0) {
|
|
eventType = eventTypeMap[idx].value;
|
|
}
|
|
return eventType;
|
|
}
|
|
|
|
ActionType ConvertAceAction(AceAction aceAction)
|
|
{
|
|
static const ActionTable actionTable[] = {
|
|
{ AceAction::ACTION_CLICK, ActionType::ACCESSIBILITY_ACTION_CLICK },
|
|
{ AceAction::ACTION_LONG_CLICK, ActionType::ACCESSIBILITY_ACTION_LONG_CLICK },
|
|
{ AceAction::ACTION_SCROLL_FORWARD, ActionType::ACCESSIBILITY_ACTION_SCROLL_FORWARD },
|
|
{ AceAction::ACTION_SCROLL_BACKWARD, ActionType::ACCESSIBILITY_ACTION_SCROLL_BACKWARD },
|
|
{ AceAction::ACTION_FOCUS, ActionType::ACCESSIBILITY_ACTION_FOCUS },
|
|
{ AceAction::ACTION_ACCESSIBILITY_FOCUS, ActionType::ACCESSIBILITY_ACTION_ACCESSIBILITY_FOCUS },
|
|
{ AceAction::ACTION_CLEAR_ACCESSIBILITY_FOCUS, ActionType::ACCESSIBILITY_ACTION_CLEAR_ACCESSIBILITY_FOCUS },
|
|
{ AceAction::ACTION_NEXT_AT_MOVEMENT_GRANULARITY, ActionType::ACCESSIBILITY_ACTION_NEXT_TEXT },
|
|
{ AceAction::ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, ActionType::ACCESSIBILITY_ACTION_PREVIOUS_TEXT },
|
|
};
|
|
for (const auto& item : actionTable) {
|
|
if (aceAction == item.aceAction) {
|
|
return item.action;
|
|
}
|
|
}
|
|
return ActionType::ACCESSIBILITY_ACTION_INVALID;
|
|
}
|
|
|
|
inline RangeInfo ConvertAccessibilityValue(const AccessibilityValue& value)
|
|
{
|
|
return RangeInfo(static_cast<int>(value.min), static_cast<int>(value.max), static_cast<int>(value.current));
|
|
}
|
|
|
|
int32_t ConvertToCardAccessibilityId(int32_t nodeId, int32_t cardId, int32_t rootNodeId)
|
|
{
|
|
// result is integer total ten digits, top five for agp virtualViewId, end five for ace nodeId,
|
|
// for example agp virtualViewId is 32, ace nodeId is 1000001, convert to result is 00032 10001.
|
|
int32_t result = 0;
|
|
if (nodeId == rootNodeId + ROOT_STACK_BASE) {
|
|
// for example agp virtualViewId is 32 root node is 2100000, convert to result is 00032 21000.
|
|
result = cardId * CARD_BASE + (static_cast<int32_t>(nodeId / CARD_BASE)) * CARD_ROOT_NODE_ID_RATION +
|
|
nodeId % CARD_BASE;
|
|
} else {
|
|
result = cardId * CARD_BASE + (static_cast<int32_t>(nodeId / DOM_ROOT_NODE_ID_BASE)) * CARD_NODE_ID_RATION +
|
|
nodeId % DOM_ROOT_NODE_ID_BASE;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void UpdateAccessibilityNodeInfo(const RefPtr<AccessibilityNode>& node, AccessibilityElementInfo& nodeInfo,
|
|
const RefPtr<JsAccessibilityManager>& manager, int windowId, NodeId rootId)
|
|
{
|
|
LOGI("UpdateAccessibilityNodeInfo nodeId:%{public}d", node->GetNodeId());
|
|
int leftTopX = static_cast<int>(node->GetLeft()) + SystemProperties::GetWindowPosX();
|
|
int leftTopY = static_cast<int>(node->GetTop()) + SystemProperties::GetWindowPosY();
|
|
int rightBottomX = leftTopX + static_cast<int>(node->GetWidth());
|
|
int rightBottomY = leftTopY + static_cast<int>(node->GetHeight());
|
|
if (manager->isOhosHostCard()) {
|
|
int id = static_cast<int>(
|
|
ConvertToCardAccessibilityId(node->GetNodeId(), manager->GetCardId(), manager->GetRootNodeId()));
|
|
nodeInfo.SetAccessibilityId(id);
|
|
if (node->GetParentId() == -1) {
|
|
nodeInfo.SetParent(-1);
|
|
} else {
|
|
nodeInfo.SetParent(static_cast<int>(
|
|
ConvertToCardAccessibilityId(node->GetParentId(), manager->GetCardId(), manager->GetRootNodeId())));
|
|
}
|
|
leftTopX = static_cast<int>(node->GetLeft() + manager->GetCardOffset().GetX());
|
|
leftTopY = static_cast<int>(node->GetTop() + manager->GetCardOffset().GetY());
|
|
rightBottomX = leftTopX + static_cast<int>(node->GetWidth());
|
|
rightBottomY = leftTopY + static_cast<int>(node->GetHeight());
|
|
Accessibility::Rect bounds(leftTopX, leftTopY, rightBottomX, rightBottomY);
|
|
nodeInfo.SetRectInScreen(bounds);
|
|
} else {
|
|
Accessibility::Rect bounds(leftTopX, leftTopY, rightBottomX, rightBottomY);
|
|
nodeInfo.SetRectInScreen(bounds);
|
|
nodeInfo.SetComponentId(static_cast<int>(node->GetNodeId()));
|
|
nodeInfo.SetParent(static_cast<int>(node->GetParentId()));
|
|
}
|
|
|
|
if (node->GetParentId() == -1) {
|
|
const auto& children = node->GetChildList();
|
|
if (!children.empty()) {
|
|
auto lastChildNode = manager->GetAccessibilityNodeById(children.back()->GetNodeId());
|
|
if (lastChildNode) {
|
|
rightBottomX = leftTopX + static_cast<int>(lastChildNode->GetWidth());
|
|
rightBottomY = leftTopY + static_cast<int>(lastChildNode->GetHeight());
|
|
Accessibility::Rect bounds(leftTopX, leftTopY, rightBottomX, rightBottomY);
|
|
nodeInfo.SetRectInScreen(bounds);
|
|
}
|
|
}
|
|
} else {
|
|
LOGI("ACE::ParentID is %{public}d.", node->GetParentId());
|
|
}
|
|
if (node->GetNodeId() == 0) {
|
|
nodeInfo.SetParent(-1);
|
|
}
|
|
nodeInfo.SetWindowId(windowId);
|
|
nodeInfo.SetChecked(node->GetCheckedState());
|
|
nodeInfo.SetEnabled(node->GetEnabledState());
|
|
nodeInfo.SetFocused(node->GetFocusedState());
|
|
nodeInfo.SetSelected(node->GetSelectedState());
|
|
nodeInfo.SetCheckable(node->GetCheckableState());
|
|
nodeInfo.SetClickable(node->GetClickableState());
|
|
nodeInfo.SetFocusable(node->GetFocusableState());
|
|
nodeInfo.SetScrollable(node->GetScrollableState());
|
|
nodeInfo.SetLongClickable(node->GetLongClickableState());
|
|
nodeInfo.SetEditable(node->GetEditable());
|
|
nodeInfo.SetPluraLineSupported(node->GetIsMultiLine());
|
|
nodeInfo.SetPassword(node->GetIsPassword());
|
|
nodeInfo.SetTextLengthLimit(node->GetMaxTextLength());
|
|
nodeInfo.SetSelectedBegin(static_cast<int>(node->GetTextSelectionStart()));
|
|
nodeInfo.SetSelectedEnd(static_cast<int>(node->GetTextSelectionEnd()));
|
|
nodeInfo.SetVisible(node->GetShown() && node->GetVisible() && (node->GetWidth() != 0 && node->GetHeight() != 0));
|
|
nodeInfo.SetHint(node->GetHintText());
|
|
std::string accessibilityLabel = node->GetAccessibilityLabel();
|
|
nodeInfo.SetLabeled(atoi(accessibilityLabel.c_str()));
|
|
nodeInfo.SetError(node->GetErrorText());
|
|
nodeInfo.SetComponentResourceId(node->GetJsComponentId());
|
|
nodeInfo.SetInspectorKey(node->GetJsComponentId());
|
|
RangeInfo rangeInfo = ConvertAccessibilityValue(node->GetAccessibilityValue());
|
|
nodeInfo.SetRange(rangeInfo);
|
|
nodeInfo.SetInputType(static_cast<int>(node->GetTextInputType()));
|
|
nodeInfo.SetComponentType(node->GetTag());
|
|
GridInfo gridInfo(static_cast<int>(node->GetCollectionInfo().rows),
|
|
static_cast<int>(node->GetCollectionInfo().columns), (nodeInfo.IsPluraLineSupported() ? 0 : 1));
|
|
nodeInfo.SetGrid(gridInfo);
|
|
|
|
int row = static_cast<int>(node->GetCollectionItemInfo().row);
|
|
int column = static_cast<int>(node->GetCollectionItemInfo().column);
|
|
GridItemInfo gridItemInfo(row, row, column, column, false, nodeInfo.IsSelected());
|
|
nodeInfo.SetGridItem(gridItemInfo);
|
|
nodeInfo.SetBundleName(AceApplicationInfo::GetInstance().GetPackageName());
|
|
|
|
if (node->GetIsPassword()) {
|
|
std::string strStar(node->GetText().size(), '*');
|
|
nodeInfo.SetContent(strStar);
|
|
} else {
|
|
nodeInfo.SetContent(node->GetText());
|
|
}
|
|
|
|
if (!node->GetAccessibilityHint().empty()) {
|
|
if (node->GetAccessibilityLabel().empty()) {
|
|
LOGI("UpdateAccessibilityNodeInfo Label is null");
|
|
} else {
|
|
LOGI("UpdateAccessibilityNodeInfo Label is not null");
|
|
}
|
|
}
|
|
|
|
auto supportAceActions = node->GetSupportAction();
|
|
std::vector<ActionType> actions(supportAceActions.size());
|
|
|
|
for (auto it = supportAceActions.begin(); it != supportAceActions.end(); ++it) {
|
|
AccessibleAction action(ConvertAceAction(*it), "ace");
|
|
nodeInfo.AddAction(action);
|
|
LOGI("UpdateAccessibilityNodeInfo Action:%{public}d", ConvertAceAction(*it));
|
|
}
|
|
|
|
if (node->GetImportantForAccessibility() == IMPORTANT_YES) {
|
|
actions.emplace_back(ActionType::ACCESSIBILITY_ACTION_FOCUS);
|
|
nodeInfo.SetCheckable(true);
|
|
} else if (node->GetImportantForAccessibility() == IMPORTANT_NO ||
|
|
node->GetImportantForAccessibility() == IMPORTANT_NO_HIDE_DES) {
|
|
nodeInfo.SetVisible(false);
|
|
}
|
|
|
|
std::vector<int32_t> childIds = node->GetChildIds();
|
|
for (size_t i = 0; i < childIds.size(); ++i) {
|
|
nodeInfo.AddChild(childIds[i]);
|
|
}
|
|
|
|
#ifdef ACE_DEBUG
|
|
std::string actionForLog;
|
|
for (const auto& action : supportAceActions) {
|
|
if (!actionForLog.empty()) {
|
|
actionForLog.append(",");
|
|
}
|
|
actionForLog.append(std::to_string(static_cast<int32_t>(action)));
|
|
}
|
|
LOGD("Support action is %{public}s", actionForLog.c_str());
|
|
#endif
|
|
}
|
|
|
|
inline std::string BoolToString(bool tag)
|
|
{
|
|
return tag ? "true" : "false";
|
|
}
|
|
|
|
std::string ConvertInputTypeToString(AceTextCategory type)
|
|
{
|
|
switch (type) {
|
|
case AceTextCategory::INPUT_TYPE_DEFAULT:
|
|
return "INPUT_TYPE_DEFAULT";
|
|
case AceTextCategory::INPUT_TYPE_TEXT:
|
|
return "INPUT_TYPE_TEXT";
|
|
case AceTextCategory::INPUT_TYPE_EMAIL:
|
|
return "INPUT_TYPE_EMAIL";
|
|
case AceTextCategory::INPUT_TYPE_DATE:
|
|
return "INPUT_TYPE_DATE";
|
|
case AceTextCategory::INPUT_TYPE_TIME:
|
|
return "INPUT_TYPE_TIME";
|
|
case AceTextCategory::INPUT_TYPE_NUMBER:
|
|
return "INPUT_TYPE_NUMBER";
|
|
case AceTextCategory::INPUT_TYPE_PASSWORD:
|
|
return "INPUT_TYPE_PASSWORD";
|
|
default:
|
|
return "illegal input type";
|
|
}
|
|
}
|
|
|
|
bool FindFocus(const RefPtr<AccessibilityNode>& node, RefPtr<AccessibilityNode>& resultNode)
|
|
{
|
|
LOGI("FindFocus nodeId(%{public}d) focus(%{public}d)", node->GetNodeId(), node->GetFocusedState());
|
|
if (node->GetAccessibilityFocusedState()) {
|
|
resultNode = node;
|
|
LOGI("FindFocus nodeId(%{public}d)", resultNode->GetNodeId());
|
|
return true;
|
|
}
|
|
if (!node->GetChildList().empty()) {
|
|
for (const auto& item : node->GetChildList()) {
|
|
if (resultNode != nullptr) {
|
|
return true;
|
|
}
|
|
if (FindFocus(item, resultNode)) {
|
|
LOGI("FindFocus nodeId:%{public}d", resultNode->GetNodeId());
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void FindText(
|
|
const RefPtr<AccessibilityNode>& node, const std::string& text, std::list<RefPtr<AccessibilityNode>>& nodeList)
|
|
{
|
|
LOGI("FindText nodeId(%{public}d)", node->GetNodeId());
|
|
if ((node != nullptr) && (node->GetText().find(text) != std::string::npos)) {
|
|
LOGI("FindText find nodeId(%{public}d)", node->GetNodeId());
|
|
nodeList.push_back(node);
|
|
}
|
|
if (!node->GetChildList().empty()) {
|
|
for (const auto& child : node->GetChildList()) {
|
|
FindText(child, text, nodeList);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
JsAccessibilityManager::~JsAccessibilityManager()
|
|
{
|
|
auto eventType = AccessibilityStateEventType::EVENT_ACCESSIBILITY_STATE_CHANGED;
|
|
|
|
UnsubscribeStateObserver(eventType);
|
|
|
|
DeregisterInteractionOperation();
|
|
}
|
|
|
|
bool JsAccessibilityManager::SubscribeStateObserver(const int eventType)
|
|
{
|
|
LOGI("JsAccessibilityManager::SubscribeStateObserver");
|
|
stateObserver_ = std::make_shared<JsAccessibilityStateObserver>();
|
|
stateObserver_->SetHandler(WeakClaim(this));
|
|
|
|
auto instance = AccessibilitySystemAbilityClient::GetInstance();
|
|
if (instance == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
bool ret = instance->SubscribeStateObserver(stateObserver_, eventType);
|
|
LOGI("JsAccessibilityManager::SubscribeStateObserver:%{public}d", ret);
|
|
return ret;
|
|
}
|
|
|
|
bool JsAccessibilityManager::UnsubscribeStateObserver(const int eventType)
|
|
{
|
|
LOGI("JsAccessibilityManager::UnsubscribeStateObserver");
|
|
stateObserver_ = std::make_shared<JsAccessibilityStateObserver>();
|
|
stateObserver_->SetHandler(WeakClaim(this));
|
|
|
|
std::shared_ptr<AccessibilitySystemAbilityClient> instance = AccessibilitySystemAbilityClient::GetInstance();
|
|
if (instance == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
bool ret = instance->UnsubscribeStateObserver(stateObserver_, eventType);
|
|
LOGI("JsAccessibilityManager::UnsubscribeStateObserver:%{public}d", ret);
|
|
return ret;
|
|
}
|
|
|
|
void JsAccessibilityManager::InitializeCallback()
|
|
{
|
|
LOGI("JsAccessibilityManager::InitializeCallback");
|
|
if (IsRegister()) {
|
|
return;
|
|
}
|
|
|
|
SubscribeStateObserver(AccessibilityStateEventType::EVENT_ACCESSIBILITY_STATE_CHANGED);
|
|
|
|
auto pipelineContext = GetPipelineContext().Upgrade();
|
|
if (!pipelineContext) {
|
|
return;
|
|
}
|
|
|
|
RegisterInteractionOperation(pipelineContext->GetWindowId());
|
|
}
|
|
|
|
bool JsAccessibilityManager::SendAccessibilitySyncEvent(const AccessibilityEvent& accessibilityEvent)
|
|
{
|
|
LOGI("JsAccessibilityManager::SendAccessibilitySyncEvent type:%{public}s nodeId:%{public}d",
|
|
accessibilityEvent.eventType.c_str(), accessibilityEvent.nodeId);
|
|
if (!IsRegister()) {
|
|
return false;
|
|
}
|
|
|
|
auto client = AccessibilitySystemAbilityClient::GetInstance();
|
|
if (!client) {
|
|
return false;
|
|
}
|
|
if (!client->IsEnabled()) {
|
|
return false;
|
|
}
|
|
|
|
Accessibility::EventType type = ConvertStrToEventType(accessibilityEvent.eventType);
|
|
if (type == Accessibility::EventType::TYPE_VIEW_INVALID) {
|
|
return false;
|
|
}
|
|
|
|
auto pipelineContext = GetPipelineContext().Upgrade();
|
|
if (!pipelineContext) {
|
|
return false;
|
|
}
|
|
int32_t windowId = pipelineContext->GetWindowId();
|
|
if (windowId == 0) {
|
|
return false;
|
|
}
|
|
|
|
auto node = GetAccessibilityNodeFromPage(accessibilityEvent.nodeId);
|
|
if (!node) {
|
|
LOGW("can't attach component by Id = %{public}d", accessibilityEvent.nodeId);
|
|
return false;
|
|
}
|
|
|
|
AccessibilityEventInfo eventInfo;
|
|
eventInfo.SetWindowId(windowId);
|
|
eventInfo.SetSource(accessibilityEvent.nodeId);
|
|
eventInfo.SetEventType(type);
|
|
eventInfo.SetComponentType(node->GetTag());
|
|
eventInfo.SetCurrentIndex(static_cast<int>(accessibilityEvent.currentItemIndex));
|
|
eventInfo.SetItemCounts(static_cast<int>(accessibilityEvent.itemCount));
|
|
eventInfo.SetBundleName(AceApplicationInfo::GetInstance().GetPackageName());
|
|
eventInfo.SetPageId(node->GetPageId());
|
|
eventInfo.AddContent(node->GetText());
|
|
eventInfo.SetLatestContent(node->GetText());
|
|
|
|
LOGI("SendAccessibilitySyncEvent windowId:%{public}d", windowId);
|
|
return client->SendEvent(eventInfo);
|
|
}
|
|
|
|
void JsAccessibilityManager::SendAccessibilityAsyncEvent(const AccessibilityEvent& accessibilityEvent)
|
|
{
|
|
LOGI("SendAccessibilitySyncEvent eventType:%{public}s", accessibilityEvent.eventType.c_str());
|
|
auto context = GetPipelineContext().Upgrade();
|
|
if (!context) {
|
|
return;
|
|
}
|
|
|
|
context->GetTaskExecutor()->PostTask(
|
|
[weak = WeakClaim(this), accessibilityEvent] {
|
|
auto jsAccessibilityManager = weak.Upgrade();
|
|
if (!jsAccessibilityManager) {
|
|
return;
|
|
}
|
|
jsAccessibilityManager->SendAccessibilitySyncEvent(accessibilityEvent);
|
|
},
|
|
TaskExecutor::TaskType::BACKGROUND);
|
|
}
|
|
|
|
void JsAccessibilityManager::UpdateNodeChildIds(const RefPtr<AccessibilityNode>& node)
|
|
{
|
|
if (!node) {
|
|
return;
|
|
}
|
|
LOGI("JsAccessibilityManager::UpdateNodeChildIds");
|
|
node->ActionUpdateIds();
|
|
const auto& children = node->GetChildList();
|
|
std::vector<int32_t> childrenVec;
|
|
auto cardId = GetCardId();
|
|
auto rootNodeId = GetRootNodeId();
|
|
|
|
// get last stack children to barrier free service.
|
|
if ((node->GetNodeId() == GetRootNodeId() + ROOT_STACK_BASE) && !children.empty() && !IsDeclarative()) {
|
|
auto lastChildNodeId = children.back()->GetNodeId();
|
|
if (isOhosHostCard()) {
|
|
childrenVec.emplace_back(ConvertToCardAccessibilityId(lastChildNodeId, cardId, rootNodeId));
|
|
} else {
|
|
childrenVec.emplace_back(lastChildNodeId);
|
|
}
|
|
} else {
|
|
childrenVec.resize(children.size());
|
|
if (isOhosHostCard()) {
|
|
std::transform(children.begin(), children.end(), childrenVec.begin(),
|
|
[cardId, rootNodeId](const RefPtr<AccessibilityNode>& child) {
|
|
return ConvertToCardAccessibilityId(child->GetNodeId(), cardId, rootNodeId);
|
|
});
|
|
} else {
|
|
std::transform(children.begin(), children.end(), childrenVec.begin(),
|
|
[](const RefPtr<AccessibilityNode>& child) { return child->GetNodeId(); });
|
|
}
|
|
}
|
|
node->SetChildIds(childrenVec);
|
|
}
|
|
|
|
void JsAccessibilityManager::DumpHandleEvent(const std::vector<std::string>& params)
|
|
{
|
|
if (params.empty()) {
|
|
DumpLog::GetInstance().Print("Error: params is empty!");
|
|
return;
|
|
}
|
|
if (params.size() != EVENT_DUMP_PARAM_LENGTH) {
|
|
DumpLog::GetInstance().Print("Error: params length is illegal!");
|
|
return;
|
|
}
|
|
if (params[0] != DUMP_ORDER && params[0] != DUMP_INSPECTOR) {
|
|
DumpLog::GetInstance().Print("Error: not accessibility dump order!");
|
|
return;
|
|
}
|
|
int32_t ID = StringUtils::StringToInt(params[1]);
|
|
auto node = GetAccessibilityNodeFromPage(ID);
|
|
if (!node) {
|
|
DumpLog::GetInstance().Print("Error: can't find node with ID");
|
|
return;
|
|
}
|
|
auto action = static_cast<AceAction>(StringUtils::StringToInt(params[2]));
|
|
static const ActionTable actionEventTable[] = {
|
|
{ AceAction::ACTION_CLICK, ActionType::ACCESSIBILITY_ACTION_CLICK },
|
|
{ AceAction::ACTION_LONG_CLICK, ActionType::ACCESSIBILITY_ACTION_LONG_CLICK },
|
|
{ AceAction::ACTION_SCROLL_FORWARD, ActionType::ACCESSIBILITY_ACTION_SCROLL_FORWARD },
|
|
{ AceAction::ACTION_SCROLL_BACKWARD, ActionType::ACCESSIBILITY_ACTION_SCROLL_BACKWARD },
|
|
{ AceAction::ACTION_FOCUS, ActionType::ACCESSIBILITY_ACTION_FOCUS },
|
|
{ AceAction::ACTION_ACCESSIBILITY_FOCUS, ActionType::ACCESSIBILITY_ACTION_ACCESSIBILITY_FOCUS },
|
|
};
|
|
ActionType op = ActionType::ACCESSIBILITY_ACTION_INVALID;
|
|
for (const auto& item : actionEventTable) {
|
|
if (action == item.aceAction) {
|
|
op = item.action;
|
|
break;
|
|
}
|
|
}
|
|
auto context = GetPipelineContext().Upgrade();
|
|
if (context) {
|
|
context->GetTaskExecutor()->PostTask(
|
|
[weak = WeakClaim(this), op, node, context]() {
|
|
auto jsAccessibilityManager = weak.Upgrade();
|
|
if (!jsAccessibilityManager) {
|
|
return;
|
|
}
|
|
jsAccessibilityManager->AccessibilityActionEvent(op, {}, node, context);
|
|
},
|
|
TaskExecutor::TaskType::UI);
|
|
}
|
|
}
|
|
|
|
void JsAccessibilityManager::DumpProperty(const std::vector<std::string>& params)
|
|
{
|
|
if (!DumpLog::GetInstance().GetDumpFile()) {
|
|
return;
|
|
}
|
|
|
|
if (params.empty()) {
|
|
DumpLog::GetInstance().Print("Error: params cannot be empty!");
|
|
return;
|
|
}
|
|
if (params.size() != PROPERTY_DUMP_PARAM_LENGTH) {
|
|
DumpLog::GetInstance().Print("Error: params length is illegal!");
|
|
return;
|
|
}
|
|
if (params[0] != DUMP_ORDER && params[0] != DUMP_INSPECTOR) {
|
|
DumpLog::GetInstance().Print("Error: not accessibility dump order!");
|
|
return;
|
|
}
|
|
|
|
auto node = GetAccessibilityNodeFromPage(StringUtils::StringToInt(params[1]));
|
|
if (!node) {
|
|
DumpLog::GetInstance().Print("Error: can't find node with ID " + params[1]);
|
|
return;
|
|
}
|
|
|
|
const auto& supportAceActions = node->GetSupportAction();
|
|
std::string actionForDump;
|
|
for (const auto& action : supportAceActions) {
|
|
if (!actionForDump.empty()) {
|
|
actionForDump.append(",");
|
|
}
|
|
actionForDump.append(std::to_string(static_cast<int32_t>(action)));
|
|
}
|
|
|
|
const auto& charValue = node->GetChartValue();
|
|
|
|
DumpLog::GetInstance().AddDesc("ID: ", node->GetNodeId());
|
|
DumpLog::GetInstance().AddDesc("parent ID: ", node->GetParentId());
|
|
DumpLog::GetInstance().AddDesc("child IDs: ", GetNodeChildIds(node));
|
|
DumpLog::GetInstance().AddDesc("component type: ", node->GetTag());
|
|
DumpLog::GetInstance().AddDesc("input type: ", node->GetInputType());
|
|
DumpLog::GetInstance().AddDesc("text: ", node->GetText());
|
|
DumpLog::GetInstance().AddDesc("width: ", node->GetWidth());
|
|
DumpLog::GetInstance().AddDesc("height: ", node->GetHeight());
|
|
DumpLog::GetInstance().AddDesc("left: ", node->GetLeft() + GetCardOffset().GetX());
|
|
DumpLog::GetInstance().AddDesc("top: ", node->GetTop() + GetCardOffset().GetY());
|
|
DumpLog::GetInstance().AddDesc("enabled: ", BoolToString(node->GetEnabledState()));
|
|
DumpLog::GetInstance().AddDesc("checked: ", BoolToString(node->GetCheckedState()));
|
|
DumpLog::GetInstance().AddDesc("selected: ", BoolToString(node->GetSelectedState()));
|
|
DumpLog::GetInstance().AddDesc("focusable: ", BoolToString(node->GetFocusableState()));
|
|
DumpLog::GetInstance().AddDesc("focused: ", BoolToString(node->GetFocusedState()));
|
|
DumpLog::GetInstance().AddDesc("checkable: ", BoolToString(node->GetCheckableState()));
|
|
DumpLog::GetInstance().AddDesc("clickable: ", BoolToString(node->GetClickableState()));
|
|
DumpLog::GetInstance().AddDesc("long clickable: ", BoolToString(node->GetLongClickableState()));
|
|
DumpLog::GetInstance().AddDesc("scrollable: ", BoolToString(node->GetScrollableState()));
|
|
DumpLog::GetInstance().AddDesc("editable: ", BoolToString(node->GetEditable()));
|
|
DumpLog::GetInstance().AddDesc("hint text: ", node->GetHintText());
|
|
DumpLog::GetInstance().AddDesc("error text: ", node->GetErrorText());
|
|
DumpLog::GetInstance().AddDesc("js component id: ", node->GetJsComponentId());
|
|
DumpLog::GetInstance().AddDesc("accessibility label: ", node->GetAccessibilityLabel());
|
|
DumpLog::GetInstance().AddDesc("accessibility hint: ", node->GetAccessibilityHint());
|
|
DumpLog::GetInstance().AddDesc("max text length: ", node->GetMaxTextLength());
|
|
DumpLog::GetInstance().AddDesc("text selection start: ", node->GetTextSelectionStart());
|
|
DumpLog::GetInstance().AddDesc("text selection end: ", node->GetTextSelectionEnd());
|
|
DumpLog::GetInstance().AddDesc("is multi line: ", BoolToString(node->GetIsMultiLine()));
|
|
DumpLog::GetInstance().AddDesc("is password", BoolToString(node->GetIsPassword()));
|
|
DumpLog::GetInstance().AddDesc("text input type: ", ConvertInputTypeToString(node->GetTextInputType()));
|
|
DumpLog::GetInstance().AddDesc("min value: ", node->GetAccessibilityValue().min);
|
|
DumpLog::GetInstance().AddDesc("max value: ", node->GetAccessibilityValue().max);
|
|
DumpLog::GetInstance().AddDesc("current value: ", node->GetAccessibilityValue().current);
|
|
DumpLog::GetInstance().AddDesc("collection info rows: ", node->GetCollectionInfo().rows);
|
|
DumpLog::GetInstance().AddDesc("collection info columns: ", node->GetCollectionInfo().columns);
|
|
DumpLog::GetInstance().AddDesc("collection item info, row: ", node->GetCollectionItemInfo().row);
|
|
DumpLog::GetInstance().AddDesc("collection item info, column: ", node->GetCollectionItemInfo().column);
|
|
DumpLog::GetInstance().AddDesc("chart has value: ", BoolToString(charValue && !charValue->empty()));
|
|
DumpLog::GetInstance().AddDesc("accessibilityGroup: ", BoolToString(node->GetAccessible()));
|
|
DumpLog::GetInstance().AddDesc("accessibilityImportance: ", node->GetImportantForAccessibility());
|
|
DumpLog::GetInstance().AddDesc("support action: ", actionForDump);
|
|
|
|
DumpLog::GetInstance().Print(0, node->GetTag(), node->GetChildList().size());
|
|
}
|
|
|
|
void JsAccessibilityManager::SetCardViewParams(const std::string& key, bool focus)
|
|
{
|
|
LOGD("SetCardViewParams key=%{public}s focus=%{public}d", key.c_str(), focus);
|
|
callbackKey_ = key;
|
|
if (!callbackKey_.empty()) {
|
|
InitializeCallback();
|
|
}
|
|
}
|
|
|
|
void JsAccessibilityManager::UpdateViewScale()
|
|
{
|
|
auto context = GetPipelineContext().Upgrade();
|
|
if (!context) {
|
|
return;
|
|
}
|
|
float scaleX = 1.0;
|
|
float scaleY = 1.0;
|
|
if (context->GetViewScale(scaleX, scaleY)) {
|
|
scaleX_ = scaleX;
|
|
scaleY_ = scaleY;
|
|
}
|
|
}
|
|
|
|
void JsAccessibilityManager::HandleComponentPostBinding()
|
|
{
|
|
for (auto targetIter = nodeWithTargetMap_.begin(); targetIter != nodeWithTargetMap_.end();) {
|
|
auto nodeWithTarget = targetIter->second.Upgrade();
|
|
if (nodeWithTarget) {
|
|
if (nodeWithTarget->GetTag() == ACCESSIBILITY_TAG_POPUP) {
|
|
auto idNodeIter = nodeWithIdMap_.find(targetIter->first);
|
|
if (idNodeIter != nodeWithIdMap_.end()) {
|
|
auto nodeWithId = idNodeIter->second.Upgrade();
|
|
if (nodeWithId) {
|
|
nodeWithId->SetAccessibilityHint(nodeWithTarget->GetText());
|
|
} else {
|
|
nodeWithIdMap_.erase(idNodeIter);
|
|
}
|
|
}
|
|
}
|
|
++targetIter;
|
|
} else {
|
|
// clear the disabled node in the maps
|
|
nodeWithTargetMap_.erase(targetIter++);
|
|
}
|
|
}
|
|
|
|
// clear the disabled node in the maps
|
|
for (auto idItem = nodeWithIdMap_.begin(); idItem != nodeWithIdMap_.end();) {
|
|
if (!idItem->second.Upgrade()) {
|
|
nodeWithIdMap_.erase(idItem++);
|
|
} else {
|
|
++idItem;
|
|
}
|
|
}
|
|
}
|
|
|
|
RefPtr<AccessibilityNodeManager> AccessibilityNodeManager::Create()
|
|
{
|
|
return AceType::MakeRefPtr<JsAccessibilityManager>();
|
|
}
|
|
|
|
void JsAccessibilityManager::JsInteractionOperation::SearchElementInfoByAccessibilityId(
|
|
const long elementId, const int requestId, AccessibilityElementOperatorCallback& callback, const int mode)
|
|
{
|
|
LOGI("JsAccessibilityManager::SearchElementInfoByAccessibilityId elementId(%{public}ld)", elementId);
|
|
auto jsAccessibilityManager = GetHandler().Upgrade();
|
|
if (!jsAccessibilityManager) {
|
|
return;
|
|
}
|
|
|
|
auto context = jsAccessibilityManager->GetPipelineContext().Upgrade();
|
|
if (context) {
|
|
context->GetTaskExecutor()->PostTask(
|
|
[jsAccessibilityManager, elementId, requestId, &callback, mode]() {
|
|
if (!jsAccessibilityManager) {
|
|
std::list<AccessibilityElementInfo> infos;
|
|
AccessibilityElementInfo nodeInfo;
|
|
infos.push_back(nodeInfo);
|
|
callback.SetSearchElementInfoByAccessibilityIdResult(infos, requestId);
|
|
return;
|
|
}
|
|
jsAccessibilityManager->SearchElementInfoByAccessibilityId(elementId, requestId, callback, mode);
|
|
},
|
|
TaskExecutor::TaskType::UI);
|
|
}
|
|
}
|
|
|
|
void JsAccessibilityManager::SearchElementInfoByAccessibilityId(
|
|
const long elementId, const int requestId, AccessibilityElementOperatorCallback& callback, const int mode)
|
|
{
|
|
LOGI("SearchElementInfoByAccessibilityId elementId(%{public}ld) mode(%{public}d)", elementId, mode);
|
|
auto weak = WeakClaim(this);
|
|
auto jsAccessibilityManager = weak.Upgrade();
|
|
if (!jsAccessibilityManager) {
|
|
return;
|
|
}
|
|
|
|
NodeId nodeId = static_cast<NodeId>(elementId);
|
|
// get root node
|
|
if (elementId == -1) {
|
|
nodeId = 0;
|
|
}
|
|
auto node = jsAccessibilityManager->GetAccessibilityNodeFromPage(nodeId);
|
|
if (!node) {
|
|
LOGW("AccessibilityNodeInfo can't attach component by Id = %{public}d", nodeId);
|
|
return;
|
|
}
|
|
LOGI("SearchElementInfoByAccessibilityId nodeId(%{public}d)", node->GetNodeId());
|
|
AccessibilityElementInfo nodeInfo;
|
|
std::list<AccessibilityElementInfo> infos;
|
|
jsAccessibilityManager->UpdateNodeChildIds(node);
|
|
UpdateAccessibilityNodeInfo(node, nodeInfo, jsAccessibilityManager, jsAccessibilityManager->windowId_,
|
|
jsAccessibilityManager->GetRootNodeId());
|
|
infos.push_back(nodeInfo);
|
|
|
|
// parent and me.
|
|
RefPtr<AccessibilityNode> parentNode;
|
|
uint32_t umode = mode;
|
|
if (umode & static_cast<uint32_t>(PREFETCH_PREDECESSORS)) {
|
|
if (node->GetParentId() != -1 && node->GetParentId() != DEFAULT_PARENT_ID) {
|
|
auto parentNode = node->GetParentNode();
|
|
UpdateAccessibilityNodeInfo(parentNode, nodeInfo, jsAccessibilityManager, jsAccessibilityManager->windowId_,
|
|
jsAccessibilityManager->GetRootNodeId());
|
|
infos.push_back(nodeInfo);
|
|
|
|
// sister/brothers.
|
|
if (umode & static_cast<uint32_t>(PREFETCH_SIBLINGS)) {
|
|
auto childs = parentNode->GetChildList();
|
|
for (const auto& item : node->GetChildList()) {
|
|
UpdateAccessibilityNodeInfo(item, nodeInfo, jsAccessibilityManager,
|
|
jsAccessibilityManager->windowId_, jsAccessibilityManager->GetRootNodeId());
|
|
infos.push_back(nodeInfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// childs.
|
|
if (umode & static_cast<uint32_t>(PREFETCH_CHILDREN)) {
|
|
auto childs = node->GetChildList();
|
|
for (const auto& item : node->GetChildList()) {
|
|
UpdateAccessibilityNodeInfo(item, nodeInfo, jsAccessibilityManager, jsAccessibilityManager->windowId_,
|
|
jsAccessibilityManager->GetRootNodeId());
|
|
infos.push_back(nodeInfo);
|
|
}
|
|
}
|
|
|
|
LOGI("SetSearchElementInfoByAccessibilityIdResult");
|
|
callback.SetSearchElementInfoByAccessibilityIdResult(infos, requestId);
|
|
}
|
|
|
|
void JsAccessibilityManager::JsInteractionOperation::SearchElementInfosByText(const long elementId,
|
|
const std::string& text, const int requestId, AccessibilityElementOperatorCallback& callback)
|
|
{
|
|
LOGI("JsAccessibilityManager::SearchElementInfosByText elementId(%{public}ld)", elementId);
|
|
if (text.empty()) {
|
|
LOGW("Text is null");
|
|
return;
|
|
}
|
|
auto jsAccessibilityManager = GetHandler().Upgrade();
|
|
if (!jsAccessibilityManager) {
|
|
return;
|
|
}
|
|
|
|
auto context = jsAccessibilityManager->GetPipelineContext().Upgrade();
|
|
if (context) {
|
|
context->GetTaskExecutor()->PostTask(
|
|
[jsAccessibilityManager, elementId, text, requestId, &callback]() {
|
|
AccessibilityElementInfo nodeInfo;
|
|
if (!jsAccessibilityManager) {
|
|
std::list<AccessibilityElementInfo> infos;
|
|
AccessibilityElementInfo nodeInfo;
|
|
infos.push_back(nodeInfo);
|
|
callback.SetSearchElementInfoByTextResult(infos, requestId);
|
|
return;
|
|
}
|
|
|
|
jsAccessibilityManager->SearchElementInfosByText(elementId, text, requestId, callback);
|
|
},
|
|
TaskExecutor::TaskType::UI);
|
|
}
|
|
}
|
|
|
|
void JsAccessibilityManager::SearchElementInfosByText(const long elementId, const std::string& text,
|
|
const int requestId, AccessibilityElementOperatorCallback& callback)
|
|
{
|
|
LOGI("SearchElementInfosByText text(%{public}s)", text.c_str());
|
|
if (text.empty()) {
|
|
LOGW("Text is null");
|
|
return;
|
|
}
|
|
auto weak = WeakClaim(this);
|
|
auto jsAccessibilityManager = weak.Upgrade();
|
|
if (!jsAccessibilityManager) {
|
|
return;
|
|
}
|
|
|
|
NodeId nodeId = static_cast<NodeId>(elementId);
|
|
if (elementId == -1) {
|
|
return;
|
|
}
|
|
|
|
LOGI("SearchElementInfosByText nodeId(%{public}d)", nodeId);
|
|
auto node = jsAccessibilityManager->GetAccessibilityNodeFromPage(nodeId);
|
|
if (!node) {
|
|
return;
|
|
}
|
|
|
|
std::list<AccessibilityElementInfo> infos;
|
|
std::list<RefPtr<AccessibilityNode>> nodeList;
|
|
FindText(node, text, nodeList);
|
|
if (!nodeList.empty()) {
|
|
for (const auto& node : nodeList) {
|
|
LOGI(" FindText end nodeId:%{public}d", node->GetNodeId());
|
|
AccessibilityElementInfo nodeInfo;
|
|
UpdateAccessibilityNodeInfo(node, nodeInfo, jsAccessibilityManager, jsAccessibilityManager->windowId_,
|
|
jsAccessibilityManager->GetRootNodeId());
|
|
infos.emplace_back(nodeInfo);
|
|
}
|
|
}
|
|
|
|
LOGI("SetSearchElementInfoByTextResult infos.size(%{public}d)", infos.size());
|
|
callback.SetSearchElementInfoByTextResult(infos, requestId);
|
|
}
|
|
|
|
void JsAccessibilityManager::JsInteractionOperation::FindFocusedElementInfo(
|
|
const long elementId, const int focusType, const int requestId, AccessibilityElementOperatorCallback& callback)
|
|
{
|
|
LOGI("JsAccessibilityManager::FindFocusedElementInfo elementId(%{public}ld)", elementId);
|
|
auto jsAccessibilityManager = GetHandler().Upgrade();
|
|
if (!jsAccessibilityManager) {
|
|
return;
|
|
}
|
|
|
|
auto context = jsAccessibilityManager->GetPipelineContext().Upgrade();
|
|
if (context) {
|
|
context->GetTaskExecutor()->PostTask(
|
|
[jsAccessibilityManager, elementId, focusType, requestId, &callback]() {
|
|
if (!jsAccessibilityManager) {
|
|
AccessibilityElementInfo nodeInfo;
|
|
nodeInfo.SetValidElement(false);
|
|
callback.SetFindFocusedElementInfoResult(nodeInfo, requestId);
|
|
return;
|
|
}
|
|
jsAccessibilityManager->FindFocusedElementInfo(elementId, focusType, requestId, callback);
|
|
},
|
|
TaskExecutor::TaskType::UI);
|
|
}
|
|
}
|
|
|
|
void JsAccessibilityManager::FindFocusedElementInfo(
|
|
const long elementId, const int focusType, const int requestId, AccessibilityElementOperatorCallback& callback)
|
|
{
|
|
LOGI("FindFocusedElementInfo elementId(%{public}ld)", elementId);
|
|
auto weak = WeakClaim(this);
|
|
auto jsAccessibilityManager = weak.Upgrade();
|
|
if (!jsAccessibilityManager) {
|
|
LOGI("FindFocusedElementInfo jsAccessibilityManager is null");
|
|
return;
|
|
}
|
|
|
|
AccessibilityElementInfo nodeInfo;
|
|
NodeId nodeId = static_cast<NodeId>(elementId);
|
|
if (elementId == -1) {
|
|
nodeId = jsAccessibilityManager->GetRootNodeId();
|
|
nodeId = 0;
|
|
}
|
|
|
|
auto node = jsAccessibilityManager->GetAccessibilityNodeFromPage(nodeId);
|
|
if (!node) {
|
|
nodeInfo.SetValidElement(false);
|
|
callback.SetFindFocusedElementInfoResult(nodeInfo, requestId);
|
|
return;
|
|
}
|
|
|
|
RefPtr<AccessibilityNode> resultNode = nullptr;
|
|
bool status = FindFocus(node, resultNode);
|
|
LOGI("FindFocus status(%{public}d)", status);
|
|
if ((status) && (resultNode != nullptr)) {
|
|
LOGI("FindFocus nodeId:%{public}d", resultNode->GetNodeId());
|
|
UpdateAccessibilityNodeInfo(resultNode, nodeInfo, jsAccessibilityManager, jsAccessibilityManager->windowId_,
|
|
jsAccessibilityManager->GetRootNodeId());
|
|
}
|
|
|
|
LOGI("SetFindFocusedElementInfoResult");
|
|
callback.SetFindFocusedElementInfoResult(nodeInfo, requestId);
|
|
}
|
|
|
|
void JsAccessibilityManager::JsInteractionOperation::ExecuteAction(const long elementId, const int action,
|
|
const std::map<std::string, std::string> actionArguments, const int requestId,
|
|
AccessibilityElementOperatorCallback& callback)
|
|
{
|
|
LOGI("JsAccessibilityManager::ExecuteAction, id:%{public}ld, action:%{public}d, request:%{public}d.",
|
|
elementId, action, requestId);
|
|
auto jsAccessibilityManager = GetHandler().Upgrade();
|
|
if (!jsAccessibilityManager) {
|
|
return;
|
|
}
|
|
|
|
auto context = jsAccessibilityManager->GetPipelineContext().Upgrade();
|
|
if (!context) {
|
|
return;
|
|
}
|
|
|
|
ActionType actionInfo = static_cast<ActionType>(action);
|
|
context->GetTaskExecutor()->PostTask(
|
|
[jsAccessibilityManager, elementId, actionInfo, actionArguments, requestId, &callback] {
|
|
if (!jsAccessibilityManager) {
|
|
return;
|
|
}
|
|
jsAccessibilityManager->ExecuteAction(elementId, actionInfo, actionArguments, requestId, callback);
|
|
},
|
|
TaskExecutor::TaskType::UI);
|
|
}
|
|
|
|
bool JsAccessibilityManager::AccessibilityActionEvent(const ActionType& action,
|
|
const std::map<std::string, std::string> actionArguments, const RefPtr<AccessibilityNode>& node,
|
|
const RefPtr<PipelineContext>& context)
|
|
{
|
|
LOGI("JsAccessibilityManager::AccessibilityActionEvent");
|
|
if (!node || !context) {
|
|
return false;
|
|
}
|
|
switch (action) {
|
|
case ActionType::ACCESSIBILITY_ACTION_CLICK: {
|
|
node->SetClicked(true);
|
|
if (!node->GetClickEventMarker().IsEmpty()) {
|
|
context->SendEventToFrontend(node->GetClickEventMarker());
|
|
node->ActionClick();
|
|
return true;
|
|
}
|
|
return node->ActionClick();
|
|
}
|
|
case ActionType::ACCESSIBILITY_ACTION_LONG_CLICK: {
|
|
if (!node->GetLongPressEventMarker().IsEmpty()) {
|
|
context->SendEventToFrontend(node->GetLongPressEventMarker());
|
|
node->ActionLongClick();
|
|
return true;
|
|
}
|
|
return node->ActionLongClick();
|
|
}
|
|
case ActionType::ACCESSIBILITY_ACTION_FOCUS: {
|
|
context->AccessibilityRequestFocus(std::to_string(node->GetNodeId()));
|
|
if (!node->GetFocusEventMarker().IsEmpty()) {
|
|
context->SendEventToFrontend(node->GetFocusEventMarker());
|
|
node->ActionFocus();
|
|
return true;
|
|
}
|
|
return node->ActionFocus();
|
|
}
|
|
case ActionType::ACCESSIBILITY_ACTION_ACCESSIBILITY_FOCUS: {
|
|
return RequestAccessibilityFocus(node);
|
|
}
|
|
case ActionType::ACCESSIBILITY_ACTION_CLEAR_ACCESSIBILITY_FOCUS: {
|
|
return ClearAccessibilityFocus(node);
|
|
}
|
|
case ActionType::ACCESSIBILITY_ACTION_SCROLL_FORWARD:
|
|
return node->ActionScrollForward();
|
|
case ActionType::ACCESSIBILITY_ACTION_SCROLL_BACKWARD:
|
|
return node->ActionScrollBackward();
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void JsAccessibilityManager::ExecuteAction(const long elementId, const ActionType& action,
|
|
const std::map<std::string, std::string> actionArguments, const int requestId,
|
|
AccessibilityElementOperatorCallback& callback)
|
|
{
|
|
LOGI("ExecuteAction action:%{public}d", action);
|
|
auto weak = WeakClaim(this);
|
|
auto jsAccessibilityManager = weak.Upgrade();
|
|
|
|
auto node = jsAccessibilityManager->GetAccessibilityNodeFromPage((NodeId)elementId);
|
|
if (!node) {
|
|
LOGW("AccessibilityNodeInfo can't attach component by Id = %{public}d", (NodeId)elementId);
|
|
callback.SetExecuteActionResult(false, requestId);
|
|
return;
|
|
}
|
|
|
|
auto context = jsAccessibilityManager->GetPipelineContext().Upgrade();
|
|
if (!context) {
|
|
callback.SetExecuteActionResult(false, requestId);
|
|
return;
|
|
}
|
|
|
|
bool actionResult = AccessibilityActionEvent(action, actionArguments, node, context);
|
|
|
|
LOGI("SetExecuteActionResult actionResult= %{public}d", actionResult);
|
|
callback.SetExecuteActionResult(actionResult, requestId);
|
|
}
|
|
|
|
void JsAccessibilityManager::JsInteractionOperation::ClearFocus()
|
|
{
|
|
LOGI("JsAccessibilityManager::ClearFocus");
|
|
auto jsAccessibilityManager = GetHandler().Upgrade();
|
|
if (!jsAccessibilityManager) {
|
|
return;
|
|
}
|
|
|
|
auto context = jsAccessibilityManager->GetPipelineContext().Upgrade();
|
|
if (!context) {
|
|
return;
|
|
}
|
|
|
|
context->GetTaskExecutor()->PostTask(
|
|
[jsAccessibilityManager] {
|
|
if (!jsAccessibilityManager) {
|
|
return;
|
|
}
|
|
jsAccessibilityManager->ClearCurrentFocus();
|
|
},
|
|
TaskExecutor::TaskType::UI);
|
|
}
|
|
|
|
void JsAccessibilityManager::JsInteractionOperation::OutsideTouch() {}
|
|
|
|
bool JsAccessibilityManager::IsRegister()
|
|
{
|
|
return isReg_;
|
|
}
|
|
|
|
void JsAccessibilityManager::Register(bool state)
|
|
{
|
|
isReg_ = state;
|
|
}
|
|
|
|
int JsAccessibilityManager::RegisterInteractionOperation(const int windowId)
|
|
{
|
|
LOGI("JsAccessibilityManager::RegisterInteractionOperation windowId:%{public}d", windowId);
|
|
if (IsRegister()) {
|
|
return 0;
|
|
}
|
|
|
|
SetWindowId(windowId);
|
|
std::shared_ptr<AccessibilitySystemAbilityClient> instance = AccessibilitySystemAbilityClient::GetInstance();
|
|
if (instance == nullptr) {
|
|
return (-1);
|
|
}
|
|
|
|
interactionOperation_ = std::make_shared<JsInteractionOperation>();
|
|
interactionOperation_->SetHandler(WeakClaim(this));
|
|
int32_t userId = AceApplicationInfo::GetInstance().GetUserId();
|
|
int retReg = instance->RegisterElementOperator(windowId, interactionOperation_, userId);
|
|
LOGI("RegisterInteractionOperation end windowId:%{public}d, ret:%{public}d", windowId, retReg);
|
|
Register(!retReg);
|
|
|
|
return retReg;
|
|
}
|
|
|
|
void JsAccessibilityManager::DeregisterInteractionOperation()
|
|
{
|
|
LOGI("JsAccessibilityManager::DeregisterInteractionOperation");
|
|
if (!IsRegister()) {
|
|
return;
|
|
}
|
|
int windowId = GetWindowId();
|
|
|
|
auto instance = AccessibilitySystemAbilityClient::GetInstance();
|
|
if (instance == nullptr) {
|
|
return;
|
|
}
|
|
Register(false);
|
|
currentFocusNodeId_ = -1;
|
|
LOGI("DeregisterInteractionOperation windowId:%{public}d", windowId);
|
|
return instance->DeregisterElementOperator(windowId);
|
|
}
|
|
|
|
void JsAccessibilityManager::JsAccessibilityStateObserver::OnStateChanged(const bool state)
|
|
{
|
|
LOGI("JsAccessibilityManager::OnStateChanged changed:%{public}d", state);
|
|
auto jsAccessibilityManager = GetHandler().Upgrade();
|
|
if (!jsAccessibilityManager) {
|
|
return;
|
|
}
|
|
|
|
auto context = jsAccessibilityManager->GetPipelineContext().Upgrade();
|
|
if (context) {
|
|
context->GetTaskExecutor()->PostTask(
|
|
[jsAccessibilityManager, state]() {
|
|
if (state) {
|
|
jsAccessibilityManager->RegisterInteractionOperation(jsAccessibilityManager->GetWindowId());
|
|
} else {
|
|
jsAccessibilityManager->DeregisterInteractionOperation();
|
|
}
|
|
},
|
|
TaskExecutor::TaskType::UI);
|
|
}
|
|
}
|
|
|
|
void JsAccessibilityManager::JsInteractionOperation::FocusMoveSearch(
|
|
const long elementId, const int direction, const int requestId, AccessibilityElementOperatorCallback& callback)
|
|
{
|
|
LOGI("JsAccessibilityManager::FocusMoveSearch elementId:%{public}ld", elementId);
|
|
auto jsAccessibilityManager = GetHandler().Upgrade();
|
|
if (!jsAccessibilityManager) {
|
|
return;
|
|
}
|
|
|
|
auto context = jsAccessibilityManager->GetPipelineContext().Upgrade();
|
|
if (!context) {
|
|
return;
|
|
}
|
|
|
|
context->GetTaskExecutor()->PostTask(
|
|
[jsAccessibilityManager, elementId, direction, requestId, &callback] {
|
|
if (!jsAccessibilityManager) {
|
|
return;
|
|
}
|
|
jsAccessibilityManager->FocusMoveSearch(elementId, direction, requestId, callback);
|
|
},
|
|
TaskExecutor::TaskType::UI);
|
|
}
|
|
|
|
void JsAccessibilityManager::FocusMoveSearch(const long elementId, const int direction, const int requestId,
|
|
Accessibility::AccessibilityElementOperatorCallback& callback)
|
|
{
|
|
LOGI("FocusMoveSearch elementId:%{public}ld", elementId);
|
|
auto weak = WeakClaim(this);
|
|
auto jsAccessibilityManager = weak.Upgrade();
|
|
AccessibilityElementInfo nodeInfo;
|
|
auto node = jsAccessibilityManager->GetAccessibilityNodeFromPage((NodeId)elementId);
|
|
if (!node) {
|
|
LOGW("AccessibilityNodeInfo can't attach component by Id = %{public}d", (NodeId)elementId);
|
|
callback.SetFocusMoveSearchResult(nodeInfo, requestId);
|
|
return;
|
|
}
|
|
LOGI("FocusMoveSearch nodeId:%{public}d", node->GetNodeId());
|
|
|
|
auto context = GetPipelineContext().Upgrade();
|
|
if (!context) {
|
|
LOGI("FocusMoveSearch context is null");
|
|
callback.SetFocusMoveSearchResult(nodeInfo, requestId);
|
|
return;
|
|
}
|
|
|
|
// get root node.
|
|
auto rootNode = node;
|
|
while (rootNode->GetParentNode()) {
|
|
rootNode = rootNode->GetParentNode();
|
|
LOGI("FocusMoveSearch nodeId:%{public}d isRoot:%{public}d", rootNode->GetNodeId(), rootNode->IsRootNode());
|
|
if (!rootNode->GetParentNode()) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::list<RefPtr<AccessibilityNode>> nodeList;
|
|
AddFocusableNode(nodeList, rootNode);
|
|
RefPtr<AccessibilityNode> resultNode;
|
|
|
|
switch (direction) {
|
|
case FOCUS_DIRECTION_FORWARD:
|
|
case FOCUS_DIRECTION_BACKWARD:
|
|
// forward and backward
|
|
resultNode = FindNodeInRelativeDirection(nodeList, node, direction);
|
|
break;
|
|
case FOCUS_DIRECTION_UP:
|
|
case FOCUS_DIRECTION_DOWN:
|
|
case FOCUS_DIRECTION_LEFT:
|
|
case FOCUS_DIRECTION_RIGHT:
|
|
// up, down, left and right
|
|
resultNode = FindNodeInAbsoluteDirection(nodeList, node, direction);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (resultNode) {
|
|
LOGI("FocusMoveSearch end nodeId:%{public}d", resultNode->GetNodeId());
|
|
jsAccessibilityManager->UpdateNodeChildIds(resultNode);
|
|
UpdateAccessibilityNodeInfo(resultNode, nodeInfo, jsAccessibilityManager, windowId_, rootNode->GetNodeId());
|
|
}
|
|
LOGI("SetFocusMoveSearchResult");
|
|
callback.SetFocusMoveSearchResult(nodeInfo, requestId);
|
|
}
|
|
|
|
void JsAccessibilityManager::AddFocusableNode(
|
|
std::list<RefPtr<AccessibilityNode>>& nodeList, const RefPtr<AccessibilityNode>& node)
|
|
{
|
|
LOGI("JsAccessibilityManager::AddFocusableNode");
|
|
const std::string importance = node->GetImportantForAccessibility();
|
|
if (CanAccessibilityFocused(node)) {
|
|
nodeList.push_back(node);
|
|
}
|
|
if (!node->GetAccessible() && importance != "no-hide-descendants") {
|
|
for (auto& child : node->GetChildList()) {
|
|
AddFocusableNode(nodeList, child);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool JsAccessibilityManager::CanAccessibilityFocused(const RefPtr<AccessibilityNode>& node)
|
|
{
|
|
LOGI("JsAccessibilityManager::CanAccessibilityFocused");
|
|
return node != nullptr && !node->IsRootNode() && node->GetVisible() &&
|
|
node->GetImportantForAccessibility() != "no" &&
|
|
node->GetImportantForAccessibility() != "no-hide-descendants";
|
|
}
|
|
|
|
RefPtr<AccessibilityNode> JsAccessibilityManager::FindNodeInRelativeDirection(
|
|
const std::list<RefPtr<AccessibilityNode>>& nodeList, RefPtr<AccessibilityNode>& node, const int direction)
|
|
{
|
|
LOGI("JsAccessibilityManager::FindNodeInRelativeDirection");
|
|
switch (direction) {
|
|
case FOCUS_DIRECTION_FORWARD:
|
|
return GetNextFocusableNode(nodeList, node);
|
|
case FOCUS_DIRECTION_BACKWARD:
|
|
return GetPreviousFocusableNode(nodeList, node);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<AccessibilityNode> JsAccessibilityManager::FindNodeInAbsoluteDirection(
|
|
const std::list<RefPtr<AccessibilityNode>>& nodeList, RefPtr<AccessibilityNode>& node, const int direction)
|
|
{
|
|
LOGI("JsAccessibilityManager::FindNodeInAbsoluteDirection");
|
|
auto tempBest = node->GetRect();
|
|
auto nodeRect = node->GetRect();
|
|
|
|
switch (direction) {
|
|
case FOCUS_DIRECTION_LEFT:
|
|
tempBest.SetLeft(node->GetLeft() + node->GetWidth() + 1);
|
|
break;
|
|
case FOCUS_DIRECTION_RIGHT:
|
|
tempBest.SetLeft(node->GetLeft() - node->GetWidth() - 1);
|
|
break;
|
|
case FOCUS_DIRECTION_UP:
|
|
tempBest.SetTop(node->GetTop() + node->GetHeight() + 1);
|
|
break;
|
|
case FOCUS_DIRECTION_DOWN:
|
|
tempBest.SetTop(node->GetTop() + node->GetHeight() - 1);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
RefPtr<AccessibilityNode> nearestNode = nullptr;
|
|
for (auto nodeItem = nodeList.begin(); nodeItem != nodeList.end(); nodeItem++) {
|
|
if ((*nodeItem)->GetNodeId() == node->GetNodeId() || (*nodeItem)->IsRootNode()) {
|
|
continue;
|
|
}
|
|
auto itemRect = (*nodeItem)->GetRect();
|
|
if (CheckBetterRect(nodeRect, direction, itemRect, tempBest)) {
|
|
tempBest = itemRect;
|
|
nearestNode = (*nodeItem);
|
|
}
|
|
}
|
|
|
|
return nearestNode;
|
|
}
|
|
|
|
RefPtr<AccessibilityNode> JsAccessibilityManager::GetNextFocusableNode(
|
|
const std::list<RefPtr<AccessibilityNode>>& nodeList, RefPtr<AccessibilityNode>& node)
|
|
{
|
|
LOGI("JsAccessibilityManager::GetNextFocusableNode");
|
|
auto nodeItem = nodeList.begin();
|
|
for (; nodeItem != nodeList.end(); nodeItem++) {
|
|
if ((*nodeItem)->GetNodeId() == node->GetNodeId()) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (nodeItem != nodeList.end() && ++nodeItem != nodeList.end()) {
|
|
return (*nodeItem);
|
|
}
|
|
if (nodeList.size() > 0) {
|
|
return (*nodeList.begin());
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<AccessibilityNode> JsAccessibilityManager::GetPreviousFocusableNode(
|
|
const std::list<RefPtr<AccessibilityNode>>& nodeList, RefPtr<AccessibilityNode>& node)
|
|
{
|
|
LOGI("JsAccessibilityManager::GetPreviousFocusableNode");
|
|
auto nodeItem = nodeList.rbegin();
|
|
for (; nodeItem != nodeList.rend(); nodeItem++) {
|
|
if ((*nodeItem)->GetNodeId() == node->GetNodeId()) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (nodeItem != nodeList.rend() && ++nodeItem != nodeList.rend()) {
|
|
return (*nodeItem);
|
|
}
|
|
|
|
if (nodeList.size() > 0) {
|
|
return (*nodeList.rbegin());
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool JsAccessibilityManager::CheckBetterRect(Rect nodeRect, const int direction, Rect itemRect, Rect tempBest)
|
|
{
|
|
if (!IsCandidateRect(nodeRect, itemRect, direction)) {
|
|
return false;
|
|
}
|
|
|
|
if (!IsCandidateRect(nodeRect, tempBest, direction)) {
|
|
return true;
|
|
}
|
|
|
|
// now both of item and tempBest are all at the direction of node.
|
|
if (OutrightBetter(nodeRect, direction, itemRect, tempBest)) {
|
|
return true;
|
|
}
|
|
|
|
if (OutrightBetter(nodeRect, direction, tempBest, itemRect)) {
|
|
return false;
|
|
}
|
|
|
|
// otherwise, do fudge-tastic comparison of the major and minor axis
|
|
return (GetWeightedDistanceFor(
|
|
MajorAxisDistance(nodeRect, itemRect, direction), MinorAxisDistance(nodeRect, itemRect, direction)) <
|
|
GetWeightedDistanceFor(
|
|
MajorAxisDistance(nodeRect, tempBest, direction), MinorAxisDistance(nodeRect, tempBest, direction)));
|
|
}
|
|
|
|
bool JsAccessibilityManager::IsCandidateRect(Rect nodeRect, Rect itemRect, const int direction)
|
|
{
|
|
switch (direction) {
|
|
case FOCUS_DIRECTION_LEFT:
|
|
return nodeRect.Left() > itemRect.Left() && nodeRect.Right() > itemRect.Right();
|
|
case FOCUS_DIRECTION_RIGHT:
|
|
return nodeRect.Left() < itemRect.Left() && nodeRect.Right() < itemRect.Right();
|
|
case FOCUS_DIRECTION_UP:
|
|
return nodeRect.Top() > itemRect.Top() && nodeRect.Bottom() > itemRect.Bottom();
|
|
case FOCUS_DIRECTION_DOWN:
|
|
return nodeRect.Top() < itemRect.Top() && nodeRect.Bottom() < itemRect.Bottom();
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Check whether rect1 is outright better than rect2.
|
|
bool JsAccessibilityManager::OutrightBetter(Rect nodeRect, const int direction, Rect Rect1, Rect Rect2)
|
|
{
|
|
bool rect1InSrcBeam = CheckRectBeam(nodeRect, Rect1, direction);
|
|
bool rect2InSrcBeam = CheckRectBeam(nodeRect, Rect2, direction);
|
|
if (rect2InSrcBeam || !rect1InSrcBeam) {
|
|
return false;
|
|
}
|
|
|
|
if (!IsToDirectionOf(nodeRect, Rect2, direction)) {
|
|
return true;
|
|
}
|
|
|
|
// for direction left or right
|
|
if (direction == FOCUS_DIRECTION_LEFT || direction == FOCUS_DIRECTION_RIGHT) {
|
|
return true;
|
|
}
|
|
|
|
return (MajorAxisDistance(nodeRect, Rect1, direction) < MajorAxisDistanceToFarEdge(nodeRect, Rect2, direction));
|
|
}
|
|
|
|
bool JsAccessibilityManager::CheckRectBeam(Rect nodeRect, Rect itemRect, const int direction)
|
|
{
|
|
switch (direction) {
|
|
case FOCUS_DIRECTION_LEFT:
|
|
case FOCUS_DIRECTION_RIGHT:
|
|
return nodeRect.Top() < itemRect.Bottom() && itemRect.Top() < nodeRect.Bottom();
|
|
case FOCUS_DIRECTION_UP:
|
|
case FOCUS_DIRECTION_DOWN:
|
|
return nodeRect.Left() < itemRect.Right() && itemRect.Left() < nodeRect.Right();
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool JsAccessibilityManager::IsToDirectionOf(Rect nodeRect, Rect itemRect, const int direction)
|
|
{
|
|
switch (direction) {
|
|
case FOCUS_DIRECTION_LEFT:
|
|
return nodeRect.Left() >= itemRect.Right();
|
|
case FOCUS_DIRECTION_RIGHT:
|
|
return nodeRect.Right() <= itemRect.Left();
|
|
case FOCUS_DIRECTION_UP:
|
|
return nodeRect.Top() >= itemRect.Bottom();
|
|
case FOCUS_DIRECTION_DOWN:
|
|
return nodeRect.Bottom() <= itemRect.Top();
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
double JsAccessibilityManager::MajorAxisDistanceToFarEdge(Rect nodeRect, Rect itemRect, const int direction)
|
|
{
|
|
double distance = 0.0;
|
|
switch (direction) {
|
|
case FOCUS_DIRECTION_LEFT:
|
|
distance = nodeRect.Left() - itemRect.Left();
|
|
break;
|
|
case FOCUS_DIRECTION_RIGHT:
|
|
distance = nodeRect.Right() - itemRect.Right();
|
|
break;
|
|
case FOCUS_DIRECTION_UP:
|
|
distance = nodeRect.Top() - itemRect.Top();
|
|
break;
|
|
case FOCUS_DIRECTION_DOWN:
|
|
distance = nodeRect.Bottom() - itemRect.Bottom();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return distance > 1.0 ? distance : 1.0;
|
|
}
|
|
|
|
double JsAccessibilityManager::MajorAxisDistance(Rect nodeRect, Rect itemRect, const int direction)
|
|
{
|
|
double distance = 0.0;
|
|
switch (direction) {
|
|
case FOCUS_DIRECTION_LEFT:
|
|
distance = nodeRect.Left() - itemRect.Right();
|
|
break;
|
|
case FOCUS_DIRECTION_RIGHT:
|
|
distance = nodeRect.Right() - itemRect.Left();
|
|
break;
|
|
case FOCUS_DIRECTION_UP:
|
|
distance = nodeRect.Top() - itemRect.Bottom();
|
|
break;
|
|
case FOCUS_DIRECTION_DOWN:
|
|
distance = nodeRect.Bottom() - itemRect.Top();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return distance > 0.0 ? distance : 0.0;
|
|
}
|
|
|
|
double JsAccessibilityManager::MinorAxisDistance(Rect nodeRect, Rect itemRect, const int direction)
|
|
{
|
|
double distance = 0.0;
|
|
switch (direction) {
|
|
case FOCUS_DIRECTION_LEFT:
|
|
case FOCUS_DIRECTION_RIGHT:
|
|
distance = (nodeRect.Top() + nodeRect.Bottom()) / 2 - (itemRect.Top() + itemRect.Bottom()) / 2;
|
|
break;
|
|
case FOCUS_DIRECTION_UP:
|
|
case FOCUS_DIRECTION_DOWN:
|
|
distance = (nodeRect.Left() + nodeRect.Right()) / 2 - (itemRect.Left() + itemRect.Right()) / 2;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return distance > 0.0 ? distance : -distance;
|
|
}
|
|
|
|
double JsAccessibilityManager::GetWeightedDistanceFor(double majorAxisDistance, double minorAxisDistance)
|
|
{
|
|
return WEIGHTED_VALUE * majorAxisDistance * majorAxisDistance + minorAxisDistance * minorAxisDistance;
|
|
}
|
|
|
|
bool JsAccessibilityManager::RequestAccessibilityFocus(const RefPtr<AccessibilityNode>& node)
|
|
{
|
|
LOGI("JsAccessibilityManager::RequestAccessibilityFocus");
|
|
auto requestNodeId = node->GetNodeId();
|
|
if (currentFocusNodeId_ == requestNodeId) {
|
|
LOGW("This node is focused.");
|
|
return false;
|
|
}
|
|
|
|
ClearCurrentFocus();
|
|
currentFocusNodeId_ = requestNodeId;
|
|
node->SetFocusedState(true);
|
|
node->SetAccessibilityFocusedState(true);
|
|
LOGI("RequestAccessibilityFocus SetFocusedState true nodeId:%{public}d", node->GetNodeId());
|
|
return node->ActionAccessibilityFocus(true);
|
|
}
|
|
|
|
bool JsAccessibilityManager::ClearAccessibilityFocus(const RefPtr<AccessibilityNode>& node)
|
|
{
|
|
LOGI("JsAccessibilityManager::ClearAccessibilityFocus");
|
|
auto requestNodeId = node->GetNodeId();
|
|
if (currentFocusNodeId_ != requestNodeId) {
|
|
LOGW("This node is not focused.");
|
|
return false;
|
|
}
|
|
|
|
currentFocusNodeId_ = -1;
|
|
node->SetFocusedState(false);
|
|
node->SetAccessibilityFocusedState(false);
|
|
return node->ActionAccessibilityFocus(false);
|
|
}
|
|
|
|
bool JsAccessibilityManager::ClearCurrentFocus()
|
|
{
|
|
LOGI("JsAccessibilityManager::ClearCurrentFocus");
|
|
auto currentFocusNode = GetAccessibilityNodeFromPage(currentFocusNodeId_);
|
|
if (currentFocusNode != nullptr) {
|
|
currentFocusNodeId_ = -1;
|
|
currentFocusNode->SetFocusedState(false);
|
|
currentFocusNode->SetAccessibilityFocusedState(false);
|
|
LOGI("ClearCurrentFocus SetFocusedState false nodeId:%{public}d", currentFocusNode->GetNodeId());
|
|
return currentFocusNode->ActionAccessibilityFocus(false);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
} // namespace OHOS::Ace::Framework
|