1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include "keys_input_device.h"
16
17#include <thread>
18#include "log/log.h"
19#include "updater_event.h"
20
21namespace Updater {
22enum KeyUpDownEvent {
23    EVENT_KEY_UP_VALUE,
24    EVENT_KEY_DOWN_VALUE
25};
26
27KeysInputDevice &KeysInputDevice::GetInstance()
28{
29    static KeysInputDevice instance;
30    return instance;
31}
32
33bool KeysInputDevice::Read(OHOS::DeviceData& data)
34{
35    data.keyId = lastKeyId_;
36    data.state = keyState_;
37    keyState_ = OHOS::INVALID_KEY_STATE;
38    return false;
39}
40
41void KeysInputDevice::OnLongKeyPressDown()
42{
43    static int downCount = 0;
44    ++downCount;
45    timerStop_ = false;
46    using namespace std::literals::chrono_literals;
47    std::thread t { [this, lastdownCount = downCount] () {
48        constexpr auto threshold = 2s;
49        std::this_thread::sleep_for(threshold);
50        // When the downCount of the last power key press changes,
51        // it means that the last press has been released before
52        // the timeout, then you can exit the callback directly
53        if (timerStop_ || lastdownCount != downCount) {
54            return;
55        }
56        UpdaterEvent::Invoke(UPDATER_POWER_VOLUME_DOWN_EVENT);
57    }};
58    t.detach();
59}
60
61void KeysInputDevice::OnLongKeyPressUp()
62{
63    // no need to judge whether in progress page,
64    // because may press power key in progress
65    // page and release power key in other page
66    timerStop_ = true;
67    UpdaterEvent::Invoke(UPDATER_POWER_VOLUME_UP_EVENT);
68}
69
70/*
71 * LONG_PRESS_POWER_ONLY_TYPE : press power key to show long press warning
72 * others : press power key and volume key to show long press warning
73 */
74void KeysInputDevice::SetLongPressType(const std::string &type)
75{
76    type_ = type;
77}
78
79void KeysInputDevice::PowerDownPress(const input_event &ev)
80{
81    if (ev.code != KEY_POWER) {
82        return;
83    }
84    bool down = ev.value == EVENT_KEY_DOWN_VALUE;
85    LOG(INFO) << "power down " << ev.code;
86    if (down) {
87        OnLongKeyPressDown();
88    } else {
89        OnLongKeyPressUp();
90    }
91}
92
93void KeysInputDevice::PowerVolumeDownPress(const input_event &ev)
94{
95    static bool powerDown = false;
96    static bool volumeDown = false;
97    bool down = ev.value == EVENT_KEY_DOWN_VALUE;
98    if (ev.code == KEY_POWER) {
99        powerDown = down;
100    } else if (ev.code == KEY_VOLUMEDOWN) {
101        volumeDown = down;
102    }
103    if (powerDown && volumeDown) {
104        OnLongKeyPressDown();
105    } else if (!down && (ev.code == KEY_POWER || ev.code == KEY_VOLUMEDOWN)) {
106        OnLongKeyPressUp();
107    }
108}
109
110int KeysInputDevice::HandleKeyEvent(const input_event &ev, uint32_t type)
111{
112    if (ev.type != EV_KEY || ev.code > KEY_MAX) {
113        return 0;
114    }
115    if (ev.code == BTN_TOUCH || ev.code == BTN_TOOL_FINGER) {
116        return 0;
117    }
118    if (ev.code == BTN_MOUSE || ev.code == BTN_LEFT || ev.code == BTN_RIGHT || ev.code == BTN_MIDDLE) {
119        return 0;
120    }
121
122    // KEY_VOLUMEDOWN = 114, KEY_VOLUMEUP = 115, KEY_POWER = 116
123    if (ev.code == KEY_VOLUMEDOWN || ev.code == KEY_VOLUMEUP || ev.code == KEY_POWER) {
124        keyState_ = (ev.value == EVENT_KEY_DOWN_VALUE) ?
125            OHOS::InputDevice::STATE_PRESS : OHOS::InputDevice::STATE_RELEASE;
126    } else {
127        keyState_ = ev.value;
128    }
129
130    lastKeyId_ = ev.code;
131    if (type_ == LONG_PRESS_POWER_ONLY_TYPE) {
132        PowerDownPress(ev);
133    } else {
134        PowerVolumeDownPress(ev);
135    }
136    return 0;
137}
138} // namespace Updater
139