* Copyright (C) 2022-2025 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 "accessible_ability_client_impl.h"
#include <chrono>
#include <cinttypes>
#include <thread>
#ifdef OHOS_BUILD_ENABLE_HITRACE
#include <hitrace_meter.h>
#endif
#include "accessible_ability_client.h"
#include "hilog_wrapper.h"
#include "if_system_ability_manager.h"
#include "iservice_registry.h"
#include "parameter.h"
#include "system_ability_definition.h"
#include "api_reporter_helper.h"
#include "accessibility_def.h"
namespace OHOS {
namespace Accessibility {
constexpr int WAIT_WINDOW_REGIST = 500;
constexpr int64_t ROOT_PARENT_ELEMENT_ID = -2100000;
const int32_t ROOT_TREE_ID = 0;
constexpr uint64_t ELEMENT_MOVE_BIT = 40;
namespace {
const std::string SYSTEM_PARAMETER_AAMS_SERVICE = "accessibility.config.ready";
constexpr int64_t ROOT_NONE_ID = -1;
constexpr int64_t NODE_ID_MAX = 0x7FFFFFFE;
ffrt::mutex g_Mutex;
sptr<AccessibleAbilityClientImpl> g_Instance = nullptr;
constexpr int32_t SA_CONNECT_TIMEOUT = 6 * 1000;
bool isParameterWatcherRegistered = false;
constexpr int32_t SCENE_BOARD_WINDOW_ID = 1;
constexpr int32_t INVALID_SCENE_BOARD_INNER_WINDOW_ID = -1;
constexpr int64_t INVALID_SCENE_BOARD_ELEMENT_ID = -1;
constexpr int32_t MAX_CACHE_WINDOW_SIZE = 5;
}
sptr<AccessibleAbilityClient> AccessibleAbilityClient::GetInstance()
{
HILOG_DEBUG();
std::lock_guard<ffrt::mutex> lock(g_Mutex);
if (g_Instance == nullptr) {
g_Instance = new(std::nothrow) AccessibleAbilityClientImpl();
}
return g_Instance;
}
sptr<AccessibleAbilityClientImpl> AccessibleAbilityClientImpl::GetAbilityClientImplement()
{
HILOG_DEBUG();
std::lock_guard<ffrt::mutex> lock(g_Mutex);
if (g_Instance == nullptr) {
g_Instance = new(std::nothrow) AccessibleAbilityClientImpl();
}
return g_Instance;
}
AccessibleAbilityClientImpl::AccessibleAbilityClientImpl()
{
HILOG_DEBUG();
if (!InitAccessibilityServiceProxy()) {
HILOG_ERROR("Init accessibility service proxy failed");
}
#ifndef ACCESSIBILITY_WATCH_FEATURE
int retSysParam = WatchParameter(SYSTEM_PARAMETER_AAMS_SERVICE.c_str(),
&AccessibleAbilityClientImpl::OnParameterChanged, this);
if (retSysParam) {
HILOG_ERROR("Watch parameter failed, error = %{public}d", retSysParam);
isParameterWatcherRegistered = false;
} else {
isParameterWatcherRegistered = true;
}
#endif
}
AccessibleAbilityClientImpl::~AccessibleAbilityClientImpl()
{
HILOG_DEBUG();
std::unique_lock<ffrt::shared_mutex> wLock(rwServiceLock_);
if (serviceProxy_ && serviceProxy_->AsObject()) {
HILOG_DEBUG("Remove service death recipient");
serviceProxy_->AsObject()->RemoveDeathRecipient(accessibilityServiceDeathRecipient_);
}
if (isParameterWatcherRegistered) {
RemoveParameterWatcher(SYSTEM_PARAMETER_AAMS_SERVICE.c_str(),
&AccessibleAbilityClientImpl::OnParameterChanged, this);
}
}
bool AccessibleAbilityClientImpl::InitAccessibilityServiceProxy()
{
if (serviceProxy_ != nullptr) {
HILOG_DEBUG("Accessibility Service is connected");
return true;
}
sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (samgr == nullptr) {
HILOG_ERROR("Failed to get ISystemAbilityManager");
return false;
}
HILOG_DEBUG("ISystemAbilityManager obtained");
sptr<IRemoteObject> object = samgr->CheckSystemAbility(ACCESSIBILITY_MANAGER_SERVICE_ID);
if (object != nullptr) {
if (accessibilityServiceDeathRecipient_ == nullptr) {
accessibilityServiceDeathRecipient_ = new(std::nothrow) AccessibilityServiceDeathRecipient(*this);
if (accessibilityServiceDeathRecipient_ == nullptr) {
HILOG_ERROR("Failed to create service deathRecipient.");
return false;
}
}
serviceProxy_ = iface_cast<IAccessibleAbilityManagerService>(object);
if (serviceProxy_ == nullptr) {
HILOG_ERROR("InitAccessibilityServiceProxy failed.");
return false;
}
if (serviceProxy_->AsObject() &&
serviceProxy_->AsObject()->AddDeathRecipient(accessibilityServiceDeathRecipient_)) {
return true;
}
} else {
if (LoadAccessibilityService() == false) {
HILOG_ERROR("LoadSystemAbilityService failed.");
return false;
} else {
return true;
}
}
return false;
}
void AccessibleAbilityClientImpl::OnParameterChanged(const char *key, const char *value, void *context)
{
if (key == nullptr || std::strcmp(key, SYSTEM_PARAMETER_AAMS_SERVICE.c_str())) {
return;
}
if (value == nullptr || std::strcmp(value, "true")) {
return;
}
if (context == nullptr) {
return;
}
AccessibleAbilityClientImpl *implPtr = static_cast<AccessibleAbilityClientImpl *>(context);
std::unique_lock<ffrt::shared_mutex> wLock(implPtr->rwServiceLock_);
if (implPtr->InitAccessibilityServiceProxy()) {
HILOG_INFO("InitAccessibilityServiceProxy success");
}
}
bool AccessibleAbilityClientImpl::CheckServiceProxy()
{
if (serviceProxy_ != nullptr || LoadAccessibilityService() == true) {
return true;
}
return false;
}
RetError AccessibleAbilityClientImpl::CheckConnection()
{
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
if (!channelClient_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
return RET_OK;
}
bool AccessibleAbilityClientImpl::LoadAccessibilityService()
{
std::unique_lock<ffrt::mutex> lock(conVarMutex_);
sptr<AccessibilityLoadCallback> loadCallback = new(std::nothrow) AccessibilityLoadCallback();
if (loadCallback == nullptr) {
return false;
}
auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (samgr == nullptr) {
return false;
}
int32_t ret = samgr->LoadSystemAbility(ACCESSIBILITY_MANAGER_SERVICE_ID, loadCallback);
if (ret != 0) {
return false;
}
auto waitStatus = proxyConVar_.wait_for(lock, std::chrono::milliseconds(SA_CONNECT_TIMEOUT),
[this]() { return serviceProxy_ != nullptr; });
if (!waitStatus) {
return false;
}
return true;
}
void AccessibleAbilityClientImpl::LoadSystemAbilitySuccess(const sptr<IRemoteObject> &remoteObject)
{
std::lock_guard<ffrt::mutex> lock(conVarMutex_);
do {
if (serviceProxy_ != nullptr) {
break;
}
sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (samgr == nullptr) {
break;
}
sptr<IRemoteObject> object = samgr->CheckSystemAbility(ACCESSIBILITY_MANAGER_SERVICE_ID);
if (object == nullptr) {
break;
}
serviceProxy_ = iface_cast<IAccessibleAbilityManagerService>(object);
if (serviceProxy_ == nullptr) {
break;
}
if (accessibilityServiceDeathRecipient_ == nullptr) {
accessibilityServiceDeathRecipient_ = new(std::nothrow) AccessibilityServiceDeathRecipient(*this);
}
if (accessibilityServiceDeathRecipient_ == nullptr) {
break;
}
if (serviceProxy_->AsObject() != nullptr) {
serviceProxy_->AsObject()->AddDeathRecipient(accessibilityServiceDeathRecipient_);
}
} while (0);
proxyConVar_.notify_one();
}
void AccessibleAbilityClientImpl::LoadSystemAbilityFail()
{
std::lock_guard<ffrt::mutex> lock(conVarMutex_);
HILOG_WARN("LoadSystemAbilityFail.");
proxyConVar_.notify_one();
}
sptr<IRemoteObject> AccessibleAbilityClientImpl::GetRemoteObject()
{
HILOG_DEBUG();
return this->AsObject();
}
RetError AccessibleAbilityClientImpl::CheckExtensionAbilityPermission()
{
HILOG_DEBUG();
std::shared_lock<ffrt::shared_mutex> rLock(rwServiceLock_);
if (CheckServiceProxy() == false) {
HILOG_ERROR("failed to connect to aams!");
return RET_ERR_SAMGR;
}
std::string processName = "";
auto ret = serviceProxy_->CheckExtensionAbilityPermission(processName);
if (ret != 0) {
HILOG_ERROR("check permission failed!");
return static_cast<RetError>(ret);
}
return RET_OK;
}
RetError AccessibleAbilityClientImpl::RegisterAbilityListener(
const std::shared_ptr<AccessibleAbilityListener> &listener)
{
HILOG_DEBUG();
std::unique_lock<ffrt::shared_mutex> wLock(rwChannelLock_);
if (listener_) {
HILOG_DEBUG("listener already exists.");
return RET_ERR_REGISTER_EXIST;
}
listener_ = listener;
return RET_OK;
}
void AccessibleAbilityClientImpl::Init(const sptr<IAccessibleAbilityChannel> &channel, const int32_t channelId)
{
HILOG_DEBUG("channelId[%{public}d]", channelId);
if (!channel || channelId == INVALID_CHANNEL_ID) {
HILOG_ERROR("channel is nullptr, or channelId is invalid");
return;
}
std::shared_ptr<AccessibleAbilityListener> listener = nullptr;
{
std::unique_lock<ffrt::shared_mutex> wLock(rwChannelLock_);
if (!listener_) {
HILOG_ERROR("listener_ is nullptr.");
return;
}
listener = listener_;
channelClient_ = std::make_shared<AccessibleAbilityChannelClient>(channelId, channel);
if (deathRecipient_ == nullptr) {
deathRecipient_ = new(std::nothrow) AccessibleAbilityDeathRecipient(*this);
if (deathRecipient_ == nullptr) {
HILOG_ERROR("Failed to create deathRecipient.");
return;
}
}
if (channel->AsObject()) {
HILOG_DEBUG("Add death recipient");
channel->AsObject()->AddDeathRecipient(deathRecipient_);
}
}
isConnected_ = true;
#ifndef ACCESSIBILITY_WATCH_FEATURE
std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_WINDOW_REGIST));
#endif
if (listener) {
listener->OnAbilityConnected();
}
}
void AccessibleAbilityClientImpl::Disconnect(const int32_t channelId)
{
HILOG_DEBUG("channelId[%{public}d]", channelId);
std::shared_ptr<AccessibleAbilityListener> listener = nullptr;
{
isConnected_ = false;
std::unique_lock<ffrt::shared_mutex> wLock(rwChannelLock_);
listener = listener_;
if (callbackList_.empty()) {
if (channelClient_ && channelClient_->GetRemote()) {
HILOG_ERROR("Remove death recipient");
channelClient_->GetRemote()->RemoveDeathRecipient(deathRecipient_);
}
channelClient_ = nullptr;
listener_ = nullptr;
} else {
isDisconnectCallbackExecute_ = true;
}
}
if (listener) {
listener->OnAbilityDisconnected();
}
std::unique_lock<ffrt::mutex> lock(callbackListMutex_);
for (auto &callback : callbackList_) {
callback->NotifyJS();
}
}
void AccessibleAbilityClientImpl::OnAccessibilityEvent(const AccessibilityEventInfo &eventInfo)
{
HILOG_DEBUG();
std::shared_ptr<AccessibleAbilityListener> listener = nullptr;
{
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
listener = listener_;
}
if (listener) {
listener->OnAccessibilityEvent(eventInfo);
}
}
void AccessibleAbilityClientImpl::OnKeyPressEvent(const MMI::KeyEvent &keyEvent, const int32_t sequence)
{
HILOG_DEBUG("sequence[%{public}d]", sequence);
std::shared_ptr<AccessibleAbilityListener> listener = nullptr;
std::shared_ptr<AccessibleAbilityChannelClient> channel = nullptr;
{
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
listener = listener_;
channel = channelClient_;
}
if (!channel) {
HILOG_ERROR("The channel is invalid.");
return;
}
bool handled = false;
if (listener) {
std::shared_ptr<MMI::KeyEvent> tmp = std::make_shared<MMI::KeyEvent>(keyEvent);
handled = listener->OnKeyPressEvent(tmp);
}
channel->SetOnKeyPressEventResult(handled, sequence);
}
RetError AccessibleAbilityClientImpl::GetFocus(
const int32_t focusType, AccessibilityElementInfo& elementInfo, bool systemApi)
{
HILOG_DEBUG("focusType[%{public}d]", focusType);
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
ApiReportHelper reporter("AccessibleAbilityClientImpl.GetFocus");
#endif
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if ((focusType != FOCUS_TYPE_INPUT) && (focusType != FOCUS_TYPE_ACCESSIBILITY)) {
HILOG_ERROR("focusType is not allowed.");
return RET_ERR_INVALID_PARAM;
}
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
Accessibility::RetError ret = channelClient_->FindFocusedElementInfo(
ANY_WINDOW_ID, ROOT_NODE_ID, focusType, elementInfo, systemApi);
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
reporter.setResult(ret);
#endif
return ret;
}
RetError AccessibleAbilityClientImpl::GetFocusByElementInfo(const AccessibilityElementInfo &sourceInfo,
const int32_t focusType, AccessibilityElementInfo &elementInfo)
{
HILOG_DEBUG("focusType[%{public}d]", focusType);
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
ApiReportHelper reporter("AccessibleAbilityClientImpl.GetFocusByElementInfo");
#endif
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if ((focusType != FOCUS_TYPE_INPUT) && (focusType != FOCUS_TYPE_ACCESSIBILITY)) {
HILOG_ERROR("focusType is not allowed.");
return RET_ERR_INVALID_PARAM;
}
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
int32_t windowId = sourceInfo.GetWindowId();
int64_t elementId = sourceInfo.GetAccessibilityId();
HILOG_DEBUG("windowId[%{public}d], elementId[%{public}" PRId64 "], focusType[%{public}d]",
windowId, elementId, focusType);
RetError ret = channelClient_->FindFocusedElementInfo(windowId, elementId, focusType, elementInfo);
if (ret == RET_OK) {
elementInfo.SetMainWindowId(sourceInfo.GetMainWindowId());
}
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
reporter.setResult(ret);
#endif
return ret;
}
RetError AccessibleAbilityClientImpl::InjectGesture(const std::shared_ptr<AccessibilityGestureInjectPath> &gesturePath)
{
HILOG_DEBUG();
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!gesturePath) {
HILOG_ERROR("The gesturePath is null.");
return RET_ERR_INVALID_PARAM;
}
std::vector<AccessibilityGesturePosition> positions = gesturePath->GetPositions();
if (positions.size() == 0) {
HILOG_ERROR("The number of gesture path position is not allowed.");
return RET_ERR_INVALID_PARAM;
}
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
return channelClient_->SendSimulateGesture(gesturePath);
}
RetError AccessibleAbilityClientImpl::GetRoot(AccessibilityElementInfo &elementInfo, bool systemApi)
{
HILOG_DEBUG();
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
ApiReportHelper reporter("AccessibleAbilityClientImpl.GetRoot");
#endif
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwServiceLock_);
if (CheckServiceProxy() == false) {
HILOG_ERROR("failed to connect to aams.");
return RET_ERR_SAMGR;
}
int32_t activeWindow = INVALID_WINDOW_ID;
RetError ret = systemApi ? static_cast<RetError>(serviceProxy_->GetActiveWindowEx(activeWindow))
: static_cast<RetError>(serviceProxy_->GetActiveWindow(activeWindow));
if (ret == RET_ERR_NO_PERMISSION) {
HILOG_ERROR("no permission");
return ret;
}
HILOG_DEBUG("activeWindow[%{public}d]", activeWindow);
if (GetCacheElementInfo(activeWindow, ROOT_NONE_ID, elementInfo)) {
HILOG_DEBUG("get element info from cache");
elementInfo.SetMainWindowId(activeWindow);
return RET_OK;
}
ret = SearchElementInfoFromAce(activeWindow, ROOT_NONE_ID, cacheMode_, elementInfo, systemApi);
if (ret == RET_OK) {
elementInfo.SetMainWindowId(activeWindow);
}
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
reporter.setResult(ret);
#endif
return ret;
}
RetError AccessibleAbilityClientImpl::GetRootByWindow(const AccessibilityWindowInfo &windowInfo,
AccessibilityElementInfo &elementInfo, bool systemApi)
{
HILOG_DEBUG();
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
int32_t windowId = windowInfo.GetWindowId();
HILOG_DEBUG("windowId[%{public}d]", windowId);
RetError ret = SearchElementInfoFromAce(windowId, ROOT_NONE_ID, cacheMode_, elementInfo, systemApi);
if (ret == RET_OK) {
elementInfo.SetMainWindowId(windowId);
}
return ret;
}
RetError AccessibleAbilityClientImpl::GetWindow(const int32_t windowId, AccessibilityWindowInfo &windowInfo)
{
HILOG_DEBUG("windowId[%{public}d]", windowId);
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
return channelClient_->GetWindow(windowId, windowInfo);
}
RetError AccessibleAbilityClientImpl::GetRootBatch(std::vector<AccessibilityElementInfo>& elementInfos)
{
HILOG_DEBUG();
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwServiceLock_);
if (CheckServiceProxy() == false) {
HILOG_ERROR("failed to connect to aams.");
return RET_ERR_SAMGR;
}
int32_t windowId = 0;
serviceProxy_->GetActiveWindowEx(windowId);
int64_t elementId = ROOT_NONE_ID;
RetError ret = SearchElementInfoRecursiveByWinid(windowId, elementId, PREFETCH_RECURSIVE_CHILDREN,
elementInfos, ROOT_TREE_ID);
if (ret != RET_OK) {
HILOG_ERROR("get window element failed.");
return ret;
}
for (auto &elementInfo : elementInfos) {
elementInfo.SetMainWindowId(windowId);
}
return RET_OK;
}
void AccessibleAbilityClientImpl::SortElementInfosIfNecessary(std::vector<AccessibilityElementInfo> &elementInfos)
{
HILOG_DEBUG();
if (elementInfos.empty()) {
HILOG_ERROR("elementInfos is empty");
return;
}
std::map<int64_t, std::shared_ptr<AccessibilityElementInfo>> elementInfosMap;
std::vector<AccessibilityElementInfo> sortedElementInfos;
int64_t nodeId = NODE_ID_MAX;
int32_t count = 1;
AccessibilityElementInfo virtualRoot = elementInfos.front();
if (virtualRoot.GetAccessibilityId() != NODE_ID_MAX) {
return;
}
elementInfos.erase(elementInfos.begin());
for (auto &element : elementInfos) {
if (element.GetAccessibilityId() == NODE_ID_MAX) {
nodeId = NODE_ID_MAX - count;
element.SetAccessibilityId(nodeId);
element.SetParent(NODE_ID_MAX);
virtualRoot.AddChild(nodeId);
count += 1;
}
nodeId = element.GetAccessibilityId();
elementInfosMap[nodeId] = std::make_shared<AccessibilityElementInfo>(element);
}
elementInfosMap[NODE_ID_MAX] = std::make_shared<AccessibilityElementInfo>(virtualRoot);
std::vector<int64_t> elementList;
elementList.push_back(NODE_ID_MAX);
uint32_t index = 0;
while (index < elementList.size()) {
auto iter = elementInfosMap.find(elementList[index]);
if (iter == elementInfosMap.end()) {
sortedElementInfos.clear();
elementInfos.insert(elementInfos.begin(), virtualRoot);
return;
}
sortedElementInfos.push_back(*(iter->second));
std::vector<int64_t> childNodeIds = iter->second->GetChildIds();
for (auto &id : childNodeIds) {
if (std::find(elementList.begin(), elementList.end(), id) == elementList.end()) {
elementList.push_back(id);
}
}
index++;
}
if (static_cast<int32_t>(sortedElementInfos.size()) > 0) {
elementInfos = sortedElementInfos;
}
elementInfosMap.clear();
}
RetError AccessibleAbilityClientImpl::GetRootByWindowBatch(const AccessibilityWindowInfo &windowInfo,
std::vector<AccessibilityElementInfo>& elementInfos, bool isFilter, bool needCut)
{
HILOG_DEBUG("GetRootByWindowBatch %{public}d", windowInfo.GetWindowId());
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
int32_t windowId = windowInfo.GetWindowId();
int64_t elementId = ROOT_NONE_ID;
int32_t mode = needCut ? PREFETCH_RECURSIVE_CHILDREN_REDUCED : PREFETCH_RECURSIVE_CHILDREN;
RetError ret = SearchElementInfoRecursiveByWinid(windowId, elementId,
mode, elementInfos, ROOT_TREE_ID, isFilter);
if (ret != RET_OK) {
HILOG_ERROR("get window element failed");
return ret;
}
SortElementInfosIfNecessary(elementInfos);
for (auto &elementInfo : elementInfos) {
elementInfo.SetMainWindowId(windowId);
}
return RET_OK;
}
RetError AccessibleAbilityClientImpl::GetWindows(std::vector<AccessibilityWindowInfo> &windows, bool systemApi)
{
HILOG_DEBUG();
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
ApiReportHelper reporter("AccessibleAbilityClientImpl.GetWindows");
#endif
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
Accessibility::RetError ret = channelClient_->GetWindows(windows, systemApi);
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
reporter.setResult(ret);
#endif
return ret;
}
RetError AccessibleAbilityClientImpl::GetWindows(const uint64_t displayId,
std::vector<AccessibilityWindowInfo> &windows, bool systemApi)
{
HILOG_DEBUG("displayId[%{public}" PRIu64 "]", displayId);
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
ApiReportHelper reporter("AccessibleAbilityClientImpl.GetWindows");
#endif
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
Accessibility::RetError ret = channelClient_->GetWindows(displayId, windows, systemApi);
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
reporter.setResult(ret);
#endif
return ret;
}
RetError AccessibleAbilityClientImpl::GetNext(const AccessibilityElementInfo& elementInfo,
const FocusMoveDirection direction, AccessibilityElementInfo& nextElementInfo, bool systemApi)
{
HILOG_DEBUG("windowId[%{public}d], elementId[%{public}" PRId64 "], direction[%{public}d]",
elementInfo.GetWindowId(), elementInfo.GetAccessibilityId(), direction);
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
ApiReportHelper reporter("AccessibleAbilityClientImpl.GetNext");
#endif
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
if (direction == DIRECTION_INVALID) {
HILOG_ERROR("direction is invalid.");
return RET_ERR_INVALID_PARAM;
}
RetError ret = channelClient_->FocusMoveSearch(elementInfo.GetWindowId(),
elementInfo.GetAccessibilityId(), direction, nextElementInfo, systemApi);
if (ret == RET_OK) {
nextElementInfo.SetMainWindowId(elementInfo.GetMainWindowId());
}
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
reporter.setResult(ret);
#endif
return ret;
}
RetError AccessibleAbilityClientImpl::GetChildElementInfo(const int32_t index, const AccessibilityElementInfo &parent,
AccessibilityElementInfo &child)
{
HILOG_DEBUG();
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
ApiReportHelper reporter("AccessibleAbilityClientImpl.GetChildElementInfo");
#endif
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
int32_t windowId = parent.GetWindowId();
int64_t childId = parent.GetChildId(index);
HILOG_DEBUG("windowId[%{public}d], childId[%{public}" PRId64 "]", windowId, childId);
if (childId == -1) {
HILOG_ERROR("childId[%{public}" PRId64 "] is invalid", childId);
return RET_ERR_INVALID_PARAM;
}
if (GetCacheElementInfo(windowId, childId, child)) {
HILOG_DEBUG("get element info from cache");
child.SetMainWindowId(parent.GetMainWindowId());
return RET_OK;
}
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
Accessibility::RetError ret = SearchElementInfoFromAce(windowId, childId, cacheMode_, child);
child.SetMainWindowId(parent.GetMainWindowId());
reporter.setResult(ret);
#endif
return ret;
}
RetError AccessibleAbilityClientImpl::GetChildren(const AccessibilityElementInfo &parent,
std::vector<AccessibilityElementInfo> &children, bool systemApi)
{
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
RetError ret = CheckConnection();
if (ret != RET_OK) {
return ret;
}
int32_t windowId = parent.GetWindowId();
std::vector<int64_t> childIds = parent.GetChildIds();
HILOG_DEBUG("windowId[%{public}d], childIds.size[%{public}zu] childTreeId:%{public}d",
windowId, childIds.size(), parent.GetChildTreeId());
std::vector<AccessibilityElementInfo> elementInfos {};
if ((childIds.size() == 0) && (parent.GetChildWindowId() > 0 || parent.GetChildTreeId() > 0)) {
if (parent.GetChildWindowId() > 0 && (parent.GetChildWindowId() != windowId)) {
ret = channelClient_->SearchElementInfosByAccessibilityId(parent.GetChildWindowId(), ROOT_NONE_ID,
GET_SOURCE_MODE, elementInfos, parent.GetChildTreeId(), false, systemApi);
} else if (parent.GetChildTreeId() > 0) {
ret = channelClient_->SearchElementInfosByAccessibilityId(parent.GetWindowId(), ROOT_NONE_ID,
GET_SOURCE_MODE, elementInfos, parent.GetChildTreeId(), false, systemApi);
}
if (ret != RET_OK) {
HILOG_ERROR("Get element info from ace failed");
return ret;
}
if (elementInfos.empty()) {
HILOG_ERROR("elementInfos from ace is empty");
return RET_ERR_INVALID_ELEMENT_INFO_FROM_ACE;
}
SortElementInfosIfNecessary(elementInfos);
children.emplace_back(elementInfos.front());
} else if (childIds.size() > 0 && parent.GetChildTreeId() > 0) {
ret = channelClient_->SearchElementInfosByAccessibilityId(parent.GetWindowId(), ROOT_NONE_ID,
GET_SOURCE_MODE, elementInfos, parent.GetChildTreeId(), false, systemApi);
if (ret != RET_OK) {
HILOG_ERROR("Get element info from ace failed");
return ret;
}
if (!elementInfos.empty()) {
children.emplace_back(elementInfos.front());
}
} else if (systemApi && childIds.size() < 1) {
ret = channelClient_->SearchElementInfosByAccessibilityId(parent.GetWindowId(), ROOT_NONE_ID,
GET_SOURCE_MODE, elementInfos, parent.GetChildTreeId(), false, systemApi);
if (ret == RET_ERR_NO_PERMISSION) {
return ret;
}
}
ret = GetChildrenWork(windowId, childIds, children, systemApi);
for (auto &elementInfo : children) {
elementInfo.SetMainWindowId(parent.GetMainWindowId());
}
return ret;
}
RetError AccessibleAbilityClientImpl::GetChildrenWork(const int32_t windowId, std::vector<int64_t> childIds,
std::vector<AccessibilityElementInfo> &children, bool systemApi)
{
int64_t crossSubtreeChildId = -1;
if (children.size() > 0) {
crossSubtreeChildId = children.front().GetAccessibilityId();
}
for (auto &childId : childIds) {
HILOG_DEBUG("childId[%{public}" PRId64 "]", childId);
if (childId == -1) {
HILOG_ERROR("childId is invalid");
return RET_ERR_INVALID_PARAM;
}
if (childId == crossSubtreeChildId) {
continue;
}
AccessibilityElementInfo child;
if (GetCacheElementInfo(windowId, childId, child)) {
HILOG_DEBUG("get element info from cache");
children.emplace_back(child);
continue;
}
RetError ret = SearchElementInfoFromAce(windowId, childId, cacheMode_, child, systemApi);
if (ret == RET_ERR_NO_PERMISSION) {
return ret;
}
if (ret != RET_OK) {
HILOG_ERROR("Get element info from ace failed");
continue;
}
children.emplace_back(child);
}
return RET_OK;
}
RetError AccessibleAbilityClientImpl::GetByContent(const AccessibilityElementInfo &elementInfo,
const std::string &text, std::vector<AccessibilityElementInfo> &elementInfos, bool systemApi)
{
HILOG_DEBUG();
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
int32_t windowId = elementInfo.GetWindowId();
int64_t elementId = elementInfo.GetAccessibilityId();
int32_t treeId = (static_cast<uint64_t>(elementId) >> ELEMENT_MOVE_BIT);
RetError ret = RET_ERR_FAILED;
if (text != "") {
ret = channelClient_->SearchElementInfosByText(windowId, elementId, text, elementInfos, systemApi);
if (ret == RET_ERR_NO_PERMISSION) {
HILOG_ERROR("no permission");
return ret;
}
if (elementInfos.empty()) {
int32_t activeWindowId = 0;
{
std::shared_lock<ffrt::shared_mutex> rServiceLock(rwServiceLock_);
if (!serviceProxy_) {
HILOG_ERROR("serviceProxy_ is nullptr");
return RET_ERR_NO_CONNECTION;
}
ret = systemApi ? static_cast<RetError>(serviceProxy_->GetActiveWindowEx(activeWindowId))
: static_cast<RetError>(serviceProxy_->GetActiveWindow(activeWindowId));
}
ret = SearchElementInfoRecursiveByContent(activeWindowId, elementId, GET_SOURCE_MODE, elementInfos, text,
ROOT_TREE_ID, systemApi);
}
} else {
ret = SearchElementInfoRecursiveByWinid(windowId, elementId, GET_SOURCE_MODE, elementInfos, treeId, systemApi);
}
if (!elementInfos.empty()) {
for (auto &element : elementInfos) {
element.SetMainWindowId(elementInfo.GetMainWindowId());
}
}
HILOG_INFO("ret:%{public}d, windowId:%{public}d, text:%{public}s", ret, windowId, text.c_str());
return ret;
}
RetError AccessibleAbilityClientImpl::SearchElementInfoRecursiveByContent(const int32_t windowId,
const int64_t elementId, uint32_t mode, std::vector<AccessibilityElementInfo> &elementInfos,
const std::string text, int32_t treeId, bool isFilter, bool systemApi)
{
HILOG_INFO("windowId %{public}d}, elementId %{public}" PRId64 "", windowId, elementId);
if (windowId <= 0) {
return RET_ERR_INVALID_ELEMENT_INFO_FROM_ACE;
}
std::vector<AccessibilityElementInfo> vecElementInfos = {};
std::vector<AccessibilityElementInfo> vecTextElementInfos = {};
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
RetError ret = channelClient_->SearchElementInfosByAccessibilityId(windowId, ROOT_NONE_ID,
mode, vecElementInfos, treeId, isFilter, systemApi);
if (ret != RET_OK) {
HILOG_ERROR("search element info failed. windowId %{public}d}", windowId);
return ret;
}
if (vecElementInfos.empty()) {
HILOG_ERROR("elementInfos from ace is empty");
return RET_ERR_INVALID_ELEMENT_INFO_FROM_ACE;
}
HILOG_DEBUG("vecElementInfos Search ok");
for (auto info : vecElementInfos) {
HILOG_DEBUG("search element info success. windowId %{public}d}",
info.GetChildWindowId());
if (info.GetParentNodeId() == ROOT_PARENT_ELEMENT_ID) {
ret = channelClient_->SearchElementInfosByText(windowId, info.GetAccessibilityId(),
text, vecTextElementInfos, systemApi);
if (ret != RET_OK) {
HILOG_ERROR("SearchElementInfosByText WindowId %{public}d} ret:%{public}d text:%{public}s",
windowId, ret, text.c_str());
return ret;
}
if (!vecTextElementInfos.empty()) {
elementInfos.insert(elementInfos.end(), vecTextElementInfos.begin(), vecTextElementInfos.end());
}
HILOG_DEBUG("SearchByText get result size:%{public}zu windowId %{public}d elementId %{public}" PRId64 "",
vecTextElementInfos.size(), windowId, info.GetAccessibilityId());
}
if (info.GetChildWindowId() > 0 && info.GetChildWindowId() != info.GetWindowId()) {
ret = SearchElementInfoRecursiveByContent(info.GetChildWindowId(),
elementId, mode, elementInfos, text, info.GetChildTreeId(), isFilter, systemApi);
} else if (info.GetChildTreeId() > 0) {
ret = SearchElementInfoRecursiveByContent(info.GetWindowId(),
elementId, mode, elementInfos, text, info.GetChildTreeId(), isFilter, systemApi);
}
if (ret != RET_OK) {
HILOG_ERROR("search element info failed.ChildWindowId %{public}d},ChildTreeId %{public}d},ret:%{public}d",
info.GetChildWindowId(), info.GetChildTreeId(), ret);
}
}
return RET_OK;
}
RetError AccessibleAbilityClientImpl::GetSource(const AccessibilityEventInfo &eventInfo,
AccessibilityElementInfo &elementInfo)
{
HILOG_DEBUG();
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
int32_t windowId = eventInfo.GetWindowId();
int64_t elementId = eventInfo.GetAccessibilityId();
HILOG_DEBUG("windowId[%{public}d], elementId[%{public}" PRId64 "]", windowId, elementId);
if (GetCacheElementInfo(windowId, elementId, elementInfo)) {
HILOG_DEBUG("get element info from cache");
elementInfo.SetMainWindowId(windowId);
return RET_OK;
}
auto ret = SearchElementInfoFromAce(windowId, elementId, cacheMode_, elementInfo);
elementInfo.SetMainWindowId(windowId);
return ret;
}
RetError AccessibleAbilityClientImpl::GetParentElementInfo(const AccessibilityElementInfo &child,
AccessibilityElementInfo &parent, bool systemApi)
{
HILOG_DEBUG("systemApi=%{public}d", systemApi);
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwServiceLock_);
int32_t windowId = child.GetWindowId();
int64_t parentElementId = child.GetParentNodeId();
int32_t parentWindowId = child.GetParentWindowId();
int32_t treeId = 0;
bool isInnerWindowRootElement = false;
HILOG_DEBUG("windowId[%{public}d], parentWindowId[%{public}d], parentId[%{public}" PRId64 "]",
windowId, parentWindowId, parentElementId);
if (serviceProxy_ == nullptr) {
HILOG_ERROR("serviceProxy_ is nullptr");
return RET_ERR_FAILED;
}
serviceProxy_->IsInnerWindowRootElement(child.GetAccessibilityId(), isInnerWindowRootElement);
if (windowId == SCENE_BOARD_WINDOW_ID && isInnerWindowRootElement) {
return RET_OK;
}
if (GetCacheElementInfo(windowId, parentElementId, parent)) {
HILOG_DEBUG("get element info from cache");
parent.SetMainWindowId(child.GetMainWindowId());
return RET_OK;
}
RetError ret = RET_ERR_FAILED;
if ((parentElementId == ROOT_PARENT_ELEMENT_ID) && (parentWindowId > 0)) {
treeId = (static_cast<uint64_t>(child.GetAccessibilityId()) >> ELEMENT_MOVE_BIT);
ret = systemApi ? static_cast<RetError>(serviceProxy_->GetRootParentIdEx(windowId, treeId, parentElementId))
: static_cast<RetError>(serviceProxy_->GetRootParentId(windowId, treeId, parentElementId));
if (ret == RET_ERR_NO_PERMISSION) {
HILOG_ERROR("no permission");
return ret;
}
if (parentElementId > 0) {
treeId = (static_cast<uint64_t>(parentElementId) >> ELEMENT_MOVE_BIT);
HILOG_DEBUG("find root parentId and search parentElementId [%{public}" PRId64 "] treeId[%{public}d]",
parentElementId, treeId);
ret = SearchElementInfoByElementId(
child.GetParentWindowId(), parentElementId, cacheMode_, parent, treeId, systemApi);
parent.SetMainWindowId(child.GetMainWindowId());
return ret;
} else {
HILOG_DEBUG("GetRootParentId faild, parentElement:%{public}" PRId64 "", parentElementId);
return RET_ERR_INVALID_ELEMENT_INFO_FROM_ACE;
}
}
treeId = (static_cast<uint64_t>(parentElementId) >> ELEMENT_MOVE_BIT);
ret = SearchElementInfoByElementId(windowId, parentElementId, cacheMode_, parent, treeId, systemApi);
parent.SetMainWindowId(child.GetMainWindowId());
return ret;
}
RetError AccessibleAbilityClientImpl::GetByElementId(const int64_t elementId, const int32_t windowId,
AccessibilityElementInfo &targetElementInfo, bool systemApi)
{
HILOG_DEBUG();
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
ApiReportHelper reporter("AccessibleAbilityClientImpl.GetByElementId");
#endif
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwServiceLock_);
if (CheckServiceProxy() == false) {
HILOG_ERROR("failed to connect to aams.");
return RET_ERR_SAMGR;
}
int32_t treeId = (static_cast<uint64_t>(elementId) >> ELEMENT_MOVE_BIT);
int32_t wid = 0;
RetError ret = systemApi ? static_cast<RetError>(serviceProxy_->GetActiveWindowEx(wid))
: static_cast<RetError>(serviceProxy_->GetActiveWindow(wid));
if (ret == RET_ERR_NO_PERMISSION) {
HILOG_ERROR("no permission");
return ret;
}
wid = windowId > 0 ? windowId : wid;
HILOG_DEBUG("window:[%{public}d],treeId:%{public}d,elementId:%{public}" PRId64 "",
wid, treeId, elementId);
if (GetCacheElementInfo(wid, elementId, targetElementInfo)) {
HILOG_DEBUG("get element info from cache");
targetElementInfo.SetMainWindowId(wid);
return RET_OK;
}
ret = SearchElementInfoByElementId(wid, elementId, cacheMode_, targetElementInfo, treeId, systemApi);
targetElementInfo.SetMainWindowId(wid);
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
reporter.setResult(ret);
#endif
return ret;
}
RetError AccessibleAbilityClientImpl::GetCursorPosition(const AccessibilityElementInfo &elementInfo, int32_t &position)
{
HILOG_DEBUG();
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
ApiReportHelper reporter("AccessibleAbilityClientImpl.GetCursorPosition");
#endif
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
int32_t windowId = elementInfo.GetWindowId();
int64_t elementId = elementInfo.GetAccessibilityId();
HILOG_DEBUG("windowId[%{public}d], elementId[%{public}" PRId64 "]d", windowId, elementId);
Accessibility::RetError ret = channelClient_->GetCursorPosition(windowId, elementId, position);
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
reporter.setResult(ret);
#endif
return ret;
}
RetError AccessibleAbilityClientImpl::CheckActionArguments(const ActionType action,
const std::map<std::string, std::string> &actionArguments)
{
if (action == ACCESSIBILITY_ACTION_CUSTOM) {
if (actionArguments.find("customAction") == actionArguments.end()) {
HILOG_ERROR("customAction is required for CUSTOM action.");
return RET_ERR_INVALID_PARAM;
}
}
return RET_OK;
}
RetError AccessibleAbilityClientImpl::ExecuteAction(const AccessibilityElementInfo &elementInfo,
const ActionType action, const std::map<std::string, std::string> &actionArguments)
{
HILOG_DEBUG();
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
ApiReportHelper reporter("AccessibleAbilityClientImpl.ExecuteAction");
#endif
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::unique_lock<ffrt::shared_mutex> wLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
if (action == ACCESSIBILITY_ACTION_INVALID) {
HILOG_ERROR("action is invalid.");
return RET_ERR_INVALID_PARAM;
}
RetError checkRet = CheckActionArguments(action, actionArguments);
if (checkRet != RET_OK) {
return checkRet;
}
int32_t windowId;
if (elementInfo.GetInnerWindowId() > 0) {
windowId = elementInfo.GetInnerWindowId();
} else if (elementInfo.GetMainWindowId() > 0) {
windowId = elementInfo.GetMainWindowId();
} else {
windowId = elementInfo.GetWindowId();
}
int64_t elementId = elementInfo.GetAccessibilityId();
const Rect rect = elementInfo.GetRectInScreen();
HILOG_DEBUG("windowId[%{public}d], elementId[%{public}" PRId64 "], action[%{public}d", windowId, elementId, action);
Accessibility::RetError ret = channelClient_->ExecuteAction(windowId, elementId, action,
const_cast<std::map<std::string, std::string> &>(actionArguments), rect);
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
reporter.setResult(ret);
#endif
return ret;
}
RetError AccessibleAbilityClientImpl::EnableScreenCurtain(bool isEnable)
{
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
ApiReportHelper reporter("AccessibleAbilityClientImpl.EnableScreenCurtain");
#endif
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
Accessibility::RetError ret = channelClient_->EnableScreenCurtain(isEnable);
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
reporter.setResult(ret);
#endif
return ret;
}
RetError AccessibleAbilityClientImpl::SetTargetBundleName(const std::vector<std::string> &targetBundleNames)
{
HILOG_DEBUG("targetBundleNames size[%{public}zu]", targetBundleNames.size());
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
ApiReportHelper reporter("AccessibleAbilityClientImpl.SetTargetBundleName");
#endif
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
Accessibility::RetError ret = channelClient_->SetTargetBundleName(targetBundleNames);
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
reporter.setResult(ret);
#endif
return ret;
}
void AccessibleAbilityClientImpl::AccessibleAbilityDeathRecipient::OnRemoteDied(const wptr<IRemoteObject>& remote)
{
HILOG_ERROR();
client_.ResetAAClient(remote);
}
void AccessibleAbilityClientImpl::AccessibilityServiceDeathRecipient::OnRemoteDied(const wptr<IRemoteObject>& remote)
{
HILOG_ERROR();
client_.NotifyServiceDied(remote);
}
void AccessibleAbilityClientImpl::NotifyServiceDied(const wptr<IRemoteObject> &remote)
{
std::shared_ptr<AccessibleAbilityListener> listener = nullptr;
{
std::unique_lock<ffrt::shared_mutex> wLock(rwServiceLock_);
if (!serviceProxy_) {
HILOG_ERROR("serviceProxy_ is nullptr");
return;
}
sptr<IRemoteObject> object = serviceProxy_->AsObject();
if (object && (remote == object)) {
object->RemoveDeathRecipient(accessibilityServiceDeathRecipient_);
serviceProxy_ = nullptr;
}
}
{
std::unique_lock<ffrt::shared_mutex> wLock(rwChannelLock_);
channelClient_ = nullptr;
listener = listener_;
listener_ = nullptr;
HILOG_INFO("NotifyServiceDied OK");
}
isConnected_ = false;
if (listener) {
listener->OnAbilityDisconnected();
}
}
void AccessibleAbilityClientImpl::ResetAAClient(const wptr<IRemoteObject> &remote)
{
HILOG_DEBUG();
std::unique_lock<ffrt::shared_mutex> wLock(rwChannelLock_);
if (channelClient_) {
sptr<IRemoteObject> object = channelClient_->GetRemote();
if (object && (remote == object)) {
object->RemoveDeathRecipient(deathRecipient_);
channelClient_ = nullptr;
HILOG_INFO("ResetAAClient OK");
}
}
isConnected_ = false;
}
RetError AccessibleAbilityClientImpl::SetCacheMode(const int32_t cacheMode)
{
HILOG_DEBUG("set cache mode: [%{public}d]", cacheMode);
cacheWindowId_ = -1;
cacheElementInfos_.Clear();
if (cacheMode < 0) {
cacheMode_ = 0;
} else {
uint32_t mode = static_cast<uint32_t>(cacheMode);
cacheMode_ = mode & static_cast<uint32_t>(GET_SOURCE_PREFETCH_MODE);
}
return RET_OK;
}
bool AccessibleAbilityClientImpl::GetCacheElementInfo(const int32_t windowId,
const int64_t elementId, AccessibilityElementInfo &elementInfo)
{
HILOG_DEBUG();
if (cacheWindowId_ == -1 || cacheWindowId_ != windowId) {
HILOG_DEBUG("cacheWindowId[%{public}d], windowId[%{public}d]", cacheWindowId_, windowId);
return false;
}
bool ret = cacheElementInfos_.Find(elementId, elementInfo);
return ret;
}
void AccessibleAbilityClientImpl::SetCacheElementInfo(const int32_t windowId,
const std::vector<OHOS::Accessibility::AccessibilityElementInfo> &elementInfos)
{
HILOG_DEBUG("windowId[%{public}d], elementInfos size[%{public}zu]", windowId, elementInfos.size());
cacheElementInfos_.Clear();
cacheWindowId_ = windowId;
for (auto &elementInfo : elementInfos) {
cacheElementInfos_.EnsureInsert(elementInfo.GetAccessibilityId(), elementInfo);
}
}
RetError AccessibleAbilityClientImpl::SearchElementInfoByElementId(const int32_t windowId, const int64_t elementId,
const uint32_t mode, AccessibilityElementInfo &info, int32_t treeId, bool systemApi)
{
std::shared_ptr<AccessibleAbilityChannelClient> channelClient = channelClient_;
if (channelClient == nullptr) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
HILOG_INFO("windowId %{public}d}, elementId %{public}" PRId64 "", windowId, elementId);
std::vector<AccessibilityElementInfo> elementInfos {};
RetError ret = channelClient->SearchElementInfosByAccessibilityId(
windowId, elementId, static_cast<int32_t>(mode), elementInfos, treeId, false, systemApi);
if (ret != RET_OK) {
HILOG_ERROR("SearchElementInfosByAccessibilityId failed. windowId[%{public}d] ", windowId);
return ret;
}
if (elementInfos.empty()) {
HILOG_ERROR("elementInfos from ace is empty");
return RET_ERR_INVALID_ELEMENT_INFO_FROM_ACE;
}
HILOG_DEBUG("element [elementSize:%{public}zu]", elementInfos.size());
SetCacheElementInfo(windowId, elementInfos);
info = elementInfos.front();
return RET_OK;
}
RetError AccessibleAbilityClientImpl::SearchElementInfoFromAce(const int32_t windowId, const int64_t elementId,
const uint32_t mode, AccessibilityElementInfo &info, bool systemApi)
{
std::shared_ptr<AccessibleAbilityChannelClient> channelClient = channelClient_;
if (channelClient == nullptr) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
HILOG_INFO("windowId %{public}d}, elementId %{public}" PRId64 "", windowId, elementId);
std::vector<AccessibilityElementInfo> elementInfos {};
int32_t treeId = 0;
if (elementId != ROOT_NONE_ID) {
treeId = (static_cast<uint64_t>(elementId) >> ELEMENT_MOVE_BIT);
}
RetError ret = channelClient->SearchElementInfosByAccessibilityId(windowId, elementId,
static_cast<int32_t>(mode), elementInfos, treeId, false, systemApi);
if (ret != RET_OK) {
HILOG_ERROR("search element info failed. windowId[%{public}d] elementId[%{public}" PRId64 "] mode[%{public}d]",
windowId, elementId, mode);
return ret;
}
if (!elementInfos.empty()) {
HILOG_DEBUG("element [elementSize:%{public}zu]", elementInfos.size());
SetCacheElementInfo(windowId, elementInfos);
info = elementInfos.front();
HILOG_DEBUG("elementId:%{public}" PRId64 ", windowId:%{public}d, treeId:%{public}d",
info.GetAccessibilityId(), info.GetWindowId(), info.GetBelongTreeId());
return RET_OK;
}
HILOG_DEBUG("elementInfos from ace is empty find all element");
ret = SearchElementInfoRecursiveByWinid(
windowId, ROOT_NONE_ID, GET_SOURCE_MODE, elementInfos, ROOT_TREE_ID, systemApi);
if (ret != RET_OK) {
HILOG_ERROR("SearchElementInfoRecursiveByWinid failed. windowId[%{public}d]", windowId);
return ret;
}
HILOG_DEBUG("SetCacheElementInfo windowId:%{public}d, element [elementSize:%{public}zu]", windowId,
elementInfos.size());
SetCacheElementInfo(windowId, elementInfos);
if (!GetCacheElementInfo(windowId, elementId, info)) {
return RET_ERR_INVALID_ELEMENT_INFO_FROM_ACE;
}
HILOG_DEBUG("elementId:%{public}" PRId64 ", windowId:%{public}d, treeId:%{public}d",
info.GetAccessibilityId(), info.GetWindowId(), info.GetBelongTreeId());
return RET_OK;
}
RetError AccessibleAbilityClientImpl::SearchElementInfoByInspectorKey(const std::string &inspectorKey,
AccessibilityElementInfo &elementInfo)
{
HILOG_DEBUG();
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rServiceLock(rwServiceLock_);
if (CheckServiceProxy() == false) {
HILOG_ERROR("failed to connect to aams.");
return RET_ERR_SAMGR;
}
int32_t windowId = 0;
serviceProxy_->GetActiveWindow(windowId);
HILOG_DEBUG("windowId[%{public}d]", windowId);
std::vector<AccessibilityElementInfo> infos {};
std::vector<AccessibilityElementInfo> elementInfos {};
SpecificPropertyParam param;
param.propertyTarget = inspectorKey;
param.propertyType = SEARCH_TYPE::CUSTOMID;
RetError ret = channelClient_->SearchElementInfosBySpecificProperty(windowId, ROOT_NONE_ID, param,
infos, elementInfos, ROOT_TREE_ID);
if (ret != RET_OK) {
HILOG_ERROR("search element info failed.");
return ret;
}
if (!infos.empty()) {
HILOG_INFO("find elementInfo by inspectorKey success in infos (single element), inspectorKey: %{public}s",
inspectorKey.c_str());
elementInfo = infos.front();
elementInfo.SetMainWindowId(windowId);
HILOG_DEBUG("DEBUG: returned elementInfo inspectorKey: %{public}s", elementInfo.GetInspectorKey().c_str());
return RET_OK;
}
if (!elementInfos.empty()) {
HILOG_DEBUG("Found elements in elementInfos, searching with recursive logic. Size: %{public}zu",
elementInfos.size());
for (auto& treeParentInfo : elementInfos) {
std::vector<AccessibilityElementInfo> newInfos {};
HILOG_DEBUG("SearchElementInfoRecursiveByWinid :search element info success. windowId %{public}d}",
treeParentInfo.GetChildWindowId());
if (treeParentInfo.GetChildTreeId() > 0) {
ret = SearchElementInfoRecursiveBySpecificProperty(treeParentInfo.GetChildWindowId(),
ROOT_NONE_ID, newInfos, treeParentInfo.GetChildTreeId(), 0, param);
HILOG_DEBUG("ChildWindowId %{public}d}. ret:%{public}d, GetChildTreeId %{public}d",
treeParentInfo.GetChildWindowId(), ret, treeParentInfo.GetChildTreeId());
if (!newInfos.empty()) {
HILOG_INFO("find elementInfo1 by inspectorKey success in infos, inspectorKey: %{public}s",
inspectorKey.c_str());
elementInfo = newInfos.front();
elementInfo.SetMainWindowId(windowId);
return RET_OK;
}
}
}
}
HILOG_INFO("SearchElementInfoByInspectorKey failed, inspectorKey: %{public}s", inspectorKey.c_str());
return RET_ERR_FAILED;
}
RetError AccessibleAbilityClientImpl::EnableUITestAbility(int32_t userId, int32_t& actualUserId)
{
HILOG_DEBUG();
std::shared_lock<ffrt::shared_mutex> rLock(rwServiceLock_);
if (CheckServiceProxy() == false) {
HILOG_ERROR("failed to connect to aams.");
return RET_ERR_SAMGR;
}
return static_cast<RetError>(serviceProxy_->EnableUITestAbility(this->AsObject(), userId, actualUserId));
}
RetError AccessibleAbilityClientImpl::DisableUITestAbility(int32_t userId)
{
HILOG_DEBUG();
std::shared_lock<ffrt::shared_mutex> rLock(rwServiceLock_);
if (CheckServiceProxy() == false) {
HILOG_ERROR("failed to connect to aams.");
return RET_ERR_SAMGR;
}
return static_cast<RetError>(serviceProxy_->DisableUITestAbility(userId));
}
void AccessibleAbilityClientImpl::SetConnectionState(bool state)
{
isConnected_ = state;
}
RetError AccessibleAbilityClientImpl::SearchElementInfoRecursive(int32_t windowId, int64_t elementId, uint32_t mode,
std::vector<AccessibilityElementInfo> &elementInfos, bool isFilter)
{
HILOG_INFO("windowId %{public}d}, elementId %{public}" PRId64 "", windowId, elementId);
std::shared_ptr<AccessibleAbilityChannelClient> channelClient = channelClient_;
if (channelClient == nullptr) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
RetError ret = channelClient->SearchElementInfosByAccessibilityId(windowId, elementId,
mode, elementInfos, ROOT_TREE_ID, isFilter);
if (ret != RET_OK) {
HILOG_ERROR("search element info failed. windowId %{public}d elementId %{public}" PRId64 "",
windowId, elementId);
return ret;
}
if (elementInfos.empty()) {
HILOG_ERROR("elementInfos from ace is empty");
return RET_ERR_INVALID_ELEMENT_INFO_FROM_ACE;
}
return RET_OK;
}
RetError AccessibleAbilityClientImpl::SearchElementInfoRecursiveByWinid(const int32_t windowId,
const int64_t elementId, uint32_t mode, std::vector<AccessibilityElementInfo> &elementInfos,
int32_t treeId, bool isFilter, uint64_t parentIndex, bool systemApi)
{
HILOG_INFO("windowId %{public}d}, elementId %{public}" PRId64 ", treeId %{public}d, mode %{public}d",
windowId, elementId, treeId, mode);
if (windowId <= 0) {
HILOG_ERROR("window Id is failed windowId %{public}d}", windowId);
return RET_ERR_INVALID_ELEMENT_INFO_FROM_ACE;
}
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
std::vector<AccessibilityElementInfo> vecElementInfos {};
std::shared_ptr<AccessibleAbilityChannelClient> channelClient = channelClient_;
if (channelClient == nullptr) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
RetError ret = channelClient->SearchElementInfosByAccessibilityId(windowId, elementId,
mode, vecElementInfos, treeId, isFilter, systemApi);
if (ret != RET_OK) {
HILOG_ERROR("search element info failed. windowId %{public}d}", windowId);
return ret;
}
if (vecElementInfos.empty()) {
HILOG_ERROR("elementInfos from ace is empty");
return RET_ERR_INVALID_ELEMENT_INFO_FROM_ACE;
}
HILOG_DEBUG("SearchElementInfoRecursiveByWinid : vecElementInfos Search ok");
SortElementInfosIfNecessary(vecElementInfos);
uint64_t elementInfosCountAdded = 0;
uint64_t elementInfosCount = elementInfos.size();
for (auto info : vecElementInfos) {
if (info.GetParentNodeId() == ROOT_PARENT_ELEMENT_ID && parentIndex >= 0 && parentIndex < elementInfos.size()) {
elementInfos[parentIndex].AddChild(info.GetAccessibilityId());
info.SetParent(elementInfos[parentIndex].GetAccessibilityId());
HILOG_DEBUG("Give the father a child. %{public}" PRId64 ",Give the child a father. %{public}" PRId64 "",
info.GetAccessibilityId(), elementInfos[parentIndex].GetAccessibilityId());
}
elementInfos.push_back(info);
elementInfosCountAdded++;
}
for (uint64_t i = elementInfosCount; i < elementInfosCount + elementInfosCountAdded; i++) {
HILOG_DEBUG("SearchElementInfoRecursiveByWinid :search element info success. windowId %{public}d}",
elementInfos[i].GetChildWindowId());
if ((elementInfos[i].GetChildWindowId() > 0) &&
(elementInfos[i].GetChildWindowId() != elementInfos[i].GetWindowId())) {
ret = SearchElementInfoRecursiveByWinid(elementInfos[i].GetChildWindowId(),
ROOT_NONE_ID, mode, elementInfos, elementInfos[i].GetChildTreeId(), isFilter, i, systemApi);
HILOG_INFO("ChildWindowId %{public}d}. ret:%{public}d, GetChildTreeId %{public}d",
elementInfos[i].GetChildWindowId(), ret, elementInfos[i].GetChildTreeId());
} else if (elementInfos[i].GetChildTreeId() > 0 && elementInfos[i].GetChildTreeId() != treeId) {
ret = SearchElementInfoRecursiveByWinid(elementInfos[i].GetWindowId(),
ROOT_NONE_ID, mode, elementInfos, elementInfos[i].GetChildTreeId(), isFilter, i, systemApi);
HILOG_INFO("windowId %{public}d}.treeId:%{public}d. ret:%{public}d",
elementInfos[i].GetWindowId(), elementInfos[i].GetChildTreeId(), ret);
}
}
return RET_OK;
}
RetError AccessibleAbilityClientImpl::SearchElementInfoByAccessibilityId(const int32_t windowId,
const int64_t elementId, const uint32_t mode, AccessibilityElementInfo &info, bool isFilter)
{
HILOG_DEBUG();
if (isConnected_ == false) {
HILOG_ERROR("connection is broken.");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (channelClient_ == nullptr) {
HILOG_ERROR("the channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
std::vector<AccessibilityElementInfo> elementInfos {};
int32_t treeId = 0;
if (elementId > 0) {
treeId = (static_cast<uint64_t>(elementId) >> ELEMENT_MOVE_BIT);
}
RetError ret = channelClient_->SearchElementInfosByAccessibilityId(windowId,
elementId, static_cast<int32_t>(mode), elementInfos, treeId, isFilter);
if (ret != RET_OK) {
HILOG_ERROR("search element info failed, ret = %{public}d.", ret);
return ret;
}
if (elementInfos.empty()) {
HILOG_ERROR("elementInfos from ace is empty.");
return RET_ERR_INVALID_ELEMENT_INFO_FROM_ACE;
}
SetCacheElementInfo(windowId, elementInfos);
info = elementInfos.front();
info.SetMainWindowId(windowId);
return RET_OK;
}
void AccessibleAbilityClientImpl::AccessibilityLoadCallback::OnLoadSystemAbilitySuccess(int32_t systemAbilityId,
const sptr<IRemoteObject> &remoteObject)
{
if (AccessibleAbilityClientImpl::GetAbilityClientImplement()) {
AccessibleAbilityClientImpl::GetAbilityClientImplement()->LoadSystemAbilitySuccess(remoteObject);
}
}
void AccessibleAbilityClientImpl::AccessibilityLoadCallback::OnLoadSystemAbilityFail(int32_t systemAbilityId)
{
if (AccessibleAbilityClientImpl::GetAbilityClientImplement()) {
AccessibleAbilityClientImpl::GetAbilityClientImplement()->LoadSystemAbilityFail();
}
}
RetError AccessibleAbilityClientImpl::GetElements(const int32_t windowId, const int64_t elementId,
std::vector<AccessibilityElementInfo> &elementInfos)
{
#ifdef OHOS_BUILD_ENABLE_HITRACE
HITRACE_METER_NAME(HITRACE_TAG_ACCESSIBILITY_MANAGER, "GetElements");
#endif
if (windowId <= 0 || elementId < -1) {
HILOG_ERROR("invalid param.");
return RET_ERR_INVALID_PARAM;
}
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
int32_t treeId = ROOT_TREE_ID;
if (elementId > 0) {
treeId = (static_cast<uint64_t>(elementId) >> ELEMENT_MOVE_BIT);
}
RetError ret = SearchElementInfoRecursiveByWinid(windowId, elementId, GET_SOURCE_MODE, elementInfos, treeId);
if (!elementInfos.empty() && elementInfos[0].GetAccessibilityId() == elementId) {
elementInfos.erase(elementInfos.begin());
}
for (auto &elementInfo : elementInfos) {
elementInfo.SetMainWindowId(windowId);
}
HILOG_INFO("windowId: %{public}d, elementId: %{public}" PRId64 ", ret: %{public}d, size: %{public}zu",
windowId, elementId, ret, elementInfos.size());
return ret;
}
RetError AccessibleAbilityClientImpl::GetDefaultFocusedElementIds(const int32_t windowId,
std::vector<AccessibilityElementInfo> &elementInfos)
{
HITRACE_METER_NAME(HITRACE_TAG_ACCESSIBILITY_MANAGER, "GetDefaultFocusedElementIds");
if (windowId <= 0) {
HILOG_ERROR("invalid param.");
return RET_ERR_INVALID_PARAM;
}
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
auto ret = channelClient_->SearchDefaultFocusedByWindowId(windowId, ROOT_NONE_ID,
GET_SOURCE_MODE, elementInfos, ROOT_TREE_ID);
for (auto &elementInfo : elementInfos) {
elementInfo.SetMainWindowId(windowId);
}
return ret;
}
RetError AccessibleAbilityClientImpl::HoldRunningLock()
{
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
ApiReportHelper reporter("AccessibleAbilityClientImpl.HoldRunningLock");
#endif
std::unique_lock<ffrt::shared_mutex> wLock(rwRunningLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
Accessibility::RetError ret = channelClient_->HoldRunningLock();
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
reporter.setResult(ret);
#endif
return ret;
}
RetError AccessibleAbilityClientImpl::UnholdRunningLock()
{
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
ApiReportHelper reporter("AccessibleAbilityClientImpl.UnholdRunningLock");
#endif
std::unique_lock<ffrt::shared_mutex> wLock(rwRunningLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
Accessibility::RetError ret = channelClient_->UnholdRunningLock();
#ifdef ACCESSIBILITY_EMULATOR_DEFINED
reporter.setResult(ret);
#endif
return ret;
}
RetError AccessibleAbilityClientImpl::RegisterDisconnectCallback(std::shared_ptr<DisconnectCallback> &callback)
{
HILOG_INFO();
if (callback == nullptr) {
HILOG_ERROR("callback is nullptr");
return RET_ERR_INVALID_PARAM;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (channelClient_ == nullptr) {
HILOG_ERROR("the channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
std::unique_lock<ffrt::mutex> lock(callbackListMutex_);
if (callbackList_.empty()) {
callbackList_.push_back(callback);
auto ret = channelClient_->SetIsRegisterDisconnectCallback(true);
if (ret != RET_OK) {
callbackList_.clear();
}
return ret;
}
bool exist = false;
for (auto &cb : callbackList_) {
if (cb == nullptr) {
continue;
}
if (*cb == *callback) {
exist = true;
}
}
if (!exist) {
callbackList_.push_back(callback);
}
return RET_OK;
}
RetError AccessibleAbilityClientImpl::UnRegisterDisconnectCallback(std::shared_ptr<DisconnectCallback> &callback)
{
HILOG_INFO();
std::unique_lock<ffrt::mutex> lock(callbackListMutex_);
if (!callback->IsValidRef()) {
callbackList_.clear();
} else {
for (auto it = callbackList_.begin(); it != callbackList_.end();) {
if (*it == nullptr) {
continue;
}
if (**it == *callback) {
HILOG_INFO("UnRegister exist callback");
it = callbackList_.erase(it);
} else {
++it;
}
}
}
if (callbackList_.empty()) {
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (channelClient_ == nullptr) {
HILOG_ERROR("the channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
return channelClient_->SetIsRegisterDisconnectCallback(false);
}
return RET_OK;
}
RetError AccessibleAbilityClientImpl::NotifyDisconnect()
{
HILOG_INFO();
{
std::unique_lock<ffrt::mutex> lock(callbackListMutex_);
if (callbackList_.empty()) {
HILOG_INFO("callbackList_ is empty");
return RET_OK;
}
}
if (!isDisconnectCallbackExecute_) {
HILOG_INFO("callback has not executed");
return RET_OK;
}
std::unique_lock<ffrt::shared_mutex> wLock(rwChannelLock_);
if (channelClient_ && channelClient_->GetRemote()) {
channelClient_->NotifyDisconnect();
HILOG_ERROR("Remove death recipient");
channelClient_->GetRemote()->RemoveDeathRecipient(deathRecipient_);
}
channelClient_ = nullptr;
return RET_OK;
}
RetError AccessibleAbilityClientImpl::SearchElementInfoRecursiveBySpecificProperty(const int32_t windowId,
const int64_t elementId, std::vector<AccessibilityElementInfo> &elementInfos,
int32_t treeId, uint64_t parentIndex, const SpecificPropertyParam& param)
{
HILOG_INFO("windowId %{public}d}, elementId %{public}" PRId64 ", treeId %{public}d", windowId, elementId, treeId);
if (windowId <= 0) {
HILOG_ERROR("window Id is failed windowId %{public}d}", windowId);
return RET_ERR_INVALID_ELEMENT_INFO_FROM_ACE;
}
std::vector<AccessibilityElementInfo> vecElementInfos {};
std::shared_ptr<AccessibleAbilityChannelClient> channelClient = channelClient_;
if (channelClient == nullptr) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
std::vector<AccessibilityElementInfo> infos;
RetError ret = channelClient->SearchElementInfosBySpecificProperty(windowId, elementId, param, infos,
vecElementInfos, treeId);
if (ret != RET_OK) {
HILOG_ERROR("search element info failed. windowId %{public}d}", windowId);
return ret;
}
if (!infos.empty()) {
HILOG_INFO("search element info find front");
infos.front().SetMainWindowId(windowId);
elementInfos.push_back(infos.front());
return RET_OK;
}
for (auto& treeParentInfo : vecElementInfos) {
std::vector<AccessibilityElementInfo> newInfos {};
HILOG_INFO("search element info success. windowId %{public}d}",
treeParentInfo.GetChildWindowId());
if (treeParentInfo.GetChildTreeId() > 0) {
ret = SearchElementInfoRecursiveBySpecificProperty(treeParentInfo.GetChildWindowId(),
ROOT_NONE_ID, newInfos, treeParentInfo.GetChildTreeId(), 0, param);
HILOG_INFO("ChildWindowId %{public}d}. ret:%{public}d, GetChildTreeId %{public}d",
treeParentInfo.GetChildWindowId(), ret, treeParentInfo.GetChildTreeId());
if (!newInfos.empty()) {
HILOG_INFO("search element info find: find front");
newInfos.front().SetMainWindowId(windowId);
elementInfos.push_back(newInfos.front());
return RET_OK;
}
}
}
return RET_ERR_FAILED;
}
RetError AccessibleAbilityClientImpl::ConfigureEvents(const std::vector<uint32_t> needEvents)
{
HILOG_DEBUG();
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
RetError ret = channelClient_->ConfigureEvents(needEvents);
if (ret != RET_OK) {
HILOG_ERROR("config need events failed");
return ret;
}
return RET_OK;
}
RetError AccessibleAbilityClientImpl::FocusMoveSearchWithCondition(const AccessibilityElementInfo &info,
AccessibilityFocusMoveParam param, std::vector<AccessibilityElementInfo> &infos, int32_t &moveSearchResult)
{
HILOG_DEBUG("start elementId: %{public} " PRId64 ", direction: %{public}d, condition: %{public}d,"
"windowId: %{public}d", info.GetAccessibilityId(), param.direction, param.condition, info.GetWindowId());
std::shared_ptr<AccessibleAbilityChannelClient> channelClient = channelClient_;
if (channelClient == nullptr) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
FocusMoveResult result;
RetError ret = channelClient->FocusMoveSearchWithCondition(info, param, infos, result);
if (info.GetWindowId() == SCENE_BOARD_WINDOW_ID) {
for (auto &elementInfo : infos) {
elementInfo.SetMainWindowId(info.GetMainWindowId());
}
}
moveSearchResult = result.resultType;
int32_t treeId = (static_cast<uint64_t>(info.GetAccessibilityId()) >> ELEMENT_MOVE_BIT);
if (ret != RET_OK || treeId <= 0 || moveSearchResult == FocusMoveResultType::SEARCH_FAIL_LOST_NODE) {
HILOG_DEBUG("ret: %{public}d, treeId: %{public}d, result: %{public}d", ret, treeId, moveSearchResult);
return ret;
}
param.detectParent = true;
std::vector<AccessibilityElementInfo> tmpInfos;
FocusMoveResult tmpResult;
if (param.direction == FocusMoveDirection::GET_FORWARD_SCROLL_ANCESTOR ||
param.direction == FocusMoveDirection::GET_BACKWARD_SCROLL_ANCESTOR ||
param.direction == FocusMoveDirection::GET_SCROLLABLE_ANCESTOR) {
AccessibilityElementInfo tmpInfo;
tmpInfo.SetBelongTreeId(treeId);
tmpInfo.SetWindowId(info.GetParentWindowId());
ret = channelClient->FocusMoveSearchWithCondition(tmpInfo, param, tmpInfos, tmpResult);
moveSearchResult = tmpResult.resultType;
if (ret != RET_OK || tmpResult.needTerminate) {
return ret;
}
if (tmpResult.resultType == FocusMoveResultType::SEARCH_SUCCESS) {
infos.insert(infos.end(), tmpInfos.begin(), tmpInfos.end());
}
moveSearchResult = infos.empty() ? FocusMoveResultType::SEARCH_FAIL : FocusMoveResultType::SEARCH_SUCCESS;
HILOG_INFO("get scroll result %{public}d", moveSearchResult);
} else if (param.direction == FocusMoveDirection::FORWARD || param.direction == BACKWARD) {
if ((infos.empty()) || (result.resultType != FocusMoveResultType::SEARCH_SUCCESS)) {
return ret;
}
param.direction = FocusMoveDirection::DETECT_FOCUSABLE_IN_FOCUS_MOVE;
ret = channelClient->FocusMoveSearchWithCondition(infos[0], param, tmpInfos, tmpResult);
moveSearchResult = tmpResult.resultType;
HILOG_INFO("send to parent result %{public}d", moveSearchResult);
}
return ret;
}
RetError AccessibleAbilityClientImpl::UpdateCustomAccessibilityProperty(const int64_t elementId,
const int32_t windowId, const AccessibilityVirtualNode& accessibilityVirtualNode, OperateVirtualNodeResult &result)
{
HILOG_INFO("elementId[%{public}" PRId64 "], windowId[%{public}d]", elementId, windowId);
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
return channelClient_->UpdateCustomAccessibilityProperty(elementId, windowId, accessibilityVirtualNode, result);
}
RetError AccessibleAbilityClientImpl::AddAccessibilityVirtualNode(const int64_t rootId,
const int32_t windowId, const std::vector<AccessibilityVirtualNode> &nodes, OperateVirtualNodeResult &result)
{
HILOG_INFO("rootId[%{public}" PRId64 "], windowId[%{public}d]", rootId, windowId);
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
return channelClient_->AddAccessibilityVirtualNode(rootId, windowId, nodes, result);
}
RetError AccessibleAbilityClientImpl::RemoveAccessibilityVirtualNode(const int64_t id,
const int32_t windowId, OperateVirtualNodeResult &result)
{
HILOG_INFO("id[%{public}" PRId64 "], windowId[%{public}d]", id, windowId);
if (!isConnected_) {
HILOG_ERROR("connection is broken");
return RET_ERR_NO_CONNECTION;
}
std::shared_lock<ffrt::shared_mutex> rLock(rwChannelLock_);
if (!channelClient_) {
HILOG_ERROR("The channel is invalid.");
return RET_ERR_NO_CONNECTION;
}
return channelClient_->RemoveAccessibilityVirtualNode(id, windowId, result);
}
}
}