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 
21 namespace Updater {
22 enum KeyUpDownEvent {
23     EVENT_KEY_UP_VALUE,
24     EVENT_KEY_DOWN_VALUE
25 };
26 
GetInstance()27 KeysInputDevice &KeysInputDevice::GetInstance()
28 {
29     static KeysInputDevice instance;
30     return instance;
31 }
32 
Read(OHOS::DeviceData & data)33 bool 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 
OnLongKeyPressDown()41 void 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 
OnLongKeyPressUp()61 void 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  */
SetLongPressType(const std::string & type)74 void KeysInputDevice::SetLongPressType(const std::string &type)
75 {
76     type_ = type;
77 }
78 
PowerDownPress(const input_event & ev)79 void 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 
PowerVolumeDownPress(const input_event & ev)93 void 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 
HandleKeyEvent(const input_event & ev,uint32_t type)110 int 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