* Copyright (c) 2020-2021 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 "dock/rotate_input_device.h"
#include "gfx_utils/graphic_log.h"
#include "dock/focus_manager.h"
#if ENABLE_ROTATE_INPUT
namespace {
#ifdef _WIN32
constexpr int16_t ROTATE_INPUT_THRESHOLD = 1;
#else
constexpr int16_t ROTATE_INPUT_THRESHOLD = 10;
#endif
constexpr uint8_t ROTATE_END_ZERO_COUNT = 2;
}
namespace OHOS {
RotateInputDevice::RotateInputDevice()
: rotateStart_(false), threshold_(ROTATE_INPUT_THRESHOLD), cachedRotation_(0), zeroCount_(0)
{
}
void RotateInputDevice::DispatchEvent(const DeviceData& data)
{
bool cachedToRotate = false;
if (data.rotate == 0 || rotateStart_) {
cachedRotation_ = 0;
} else {
cachedRotation_ += data.rotate;
if (MATH_ABS(cachedRotation_) >= threshold_) {
cachedToRotate = true;
}
}
if (!cachedToRotate && !rotateStart_) {
return;
}
UIView* view = FocusManager::GetInstance()->GetFocusedView();
RotateManager& manager = RotateManager::GetInstance();
if (IsDispatchGlobalEvent(data, manager)) {
RotateEventRet ret = DispatchToGlobal(data, manager);
if (ret == ROTATE_ON_UNCONSUMED) {
if (IsViewValidAndVisible(view)) {
rotateStart_ = false;
DispatchToFocusedView(data, view);
}
}
if (ret == ROTATE_END_UNCONSUMED) {
if (IsViewValidAndVisible(view)) {
zeroCount_ = ROTATE_END_ZERO_COUNT;
rotateStart_ = true;
DispatchToFocusedView(data, view);
}
}
} else if (IsDispatchFocusedEvent(data, view)) {
DispatchToFocusedView(data, view);
}
}
RotateEventRet RotateInputDevice::DispatchToGlobal(const DeviceData& data, RotateManager& manager)
{
if (manager.GetRegisteredListeners().IsEmpty()) {
return GLOBAL_DISPATCH_FAILED;
}
RotateEvent rotateEvent(data.rotate, data.angularVelocity, data.rotateVelocity, data.rotateDegree, data.timestamp);
if (data.rotate == 0 && rotateStart_) {
zeroCount_++;
if (zeroCount_ >= ROTATE_END_ZERO_COUNT) {
zeroCount_ = 0;
rotateStart_ = false;
globalRotateEventStatus_ = false;
if (!(manager.OnRotateEnd(rotateEvent))) {
return ROTATE_END_UNCONSUMED;
}
}
return GLOBAL_DISPATCH_SUCCESS;
}
if (!rotateStart_) {
manager.OnRotateStart(rotateEvent);
}
rotateStart_ = true;
globalRotateEventStatus_ = true;
if (!(manager.OnRotate(rotateEvent))) {
return ROTATE_ON_UNCONSUMED;
}
return GLOBAL_DISPATCH_SUCCESS;
}
void RotateInputDevice::DispatchToFocusedView(const DeviceData& data, UIView* view)
{
if (view == nullptr) {
return;
}
RotateEvent rotateEvent(data.rotate, data.angularVelocity, data.rotateVelocity, data.rotateDegree, data.timestamp);
if (data.rotate == 0 && rotateStart_) {
zeroCount_++;
if (zeroCount_ >= ROTATE_END_ZERO_COUNT) {
view->OnRotateEndEvent(rotateEvent);
zeroCount_ = 0;
rotateStart_ = false;
focusEventStatus_ = false;
}
return;
}
if (!rotateStart_) {
view->OnRotateStartEvent(rotateEvent);
}
view->OnRotateEvent(rotateEvent);
rotateStart_ = true;
GRAPHIC_LOGI("RotateInputDevice dispatched rotate event, targetView Type = %{public}d,\
rotate value = %{public}d\n!", static_cast<uint8_t>(view->GetViewType()), data.rotate);
}
bool RotateInputDevice::IsViewValidAndVisible(UIView* view)
{
if (view == nullptr) {
return false;
}
UIView* parent = view;
while (parent != nullptr && parent->GetParent() != nullptr) {
if (!parent->IsVisible()) {
return false;
}
parent = parent->GetParent();
}
if (parent->GetViewType() != UI_ROOT_VIEW) {
GRAPHIC_LOGW("RotateInputDevice failed to dispatch event without target view attached!\n");
return false;
}
return true;
}
bool RotateInputDevice::IsDispatchFocusedEvent(const DeviceData& data, UIView* view)
{
if (globalRotateEventStatus_) {
return false;
}
if (!IsViewValidAndVisible(view)) {
if (focusEventStatus_) {
if (data.rotate == 0) {
zeroCount_ = 0;
focusEventStatus_ = false;
rotateStart_ = false;
}
}
return false;
}
focusEventStatus_ = true;
return true;
}
bool RotateInputDevice::IsDispatchGlobalEvent(const DeviceData& data, RotateManager& manager)
{
if (focusEventStatus_) {
return false;
}
if (manager.GetRegisteredListeners().IsEmpty()) {
if (globalRotateEventStatus_) {
if (data.rotate == 0) {
zeroCount_ = 0;
globalRotateEventStatus_ = false;
rotateStart_ = false;
}
}
return false;
}
return true;
}
}
#endif