1/*
2 * Copyright (c) 2022-2022 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
16#include "inputmethod_sysevent.h"
17
18#include <unistd.h>
19
20#include "common_timer_errors.h"
21#include "hisysevent.h"
22
23namespace OHOS {
24namespace MiscServices {
25namespace {
26using HiSysEventNameSpace = OHOS::HiviewDFX::HiSysEvent;
27} // namespace
28
29const std::unordered_map<int32_t, std::string> InputMethodSysEvent::operateInfo_ = {
30    { static_cast<int32_t>(OperateIMEInfoCode::IME_SHOW_ATTACH), "Attach: attach, bind and show soft keyboard." },
31    { static_cast<int32_t>(OperateIMEInfoCode::IME_SHOW_ENEDITABLE), "ShowTextInput: enter editable state, show soft "
32                                                                     "keyboard." },
33    { static_cast<int32_t>(OperateIMEInfoCode::IME_SHOW_NORMAL), "ShowSoftKeyboard: show soft keyboard." },
34    { static_cast<int32_t>(OperateIMEInfoCode::IME_UNBIND), "Close: unbind." },
35    { static_cast<int32_t>(OperateIMEInfoCode::IME_HIDE_UNBIND), "Close: hide soft keyboard, and unbind." },
36    { static_cast<int32_t>(OperateIMEInfoCode::IME_HIDE_UNEDITABLE), "HideTextInput: hide soft keyboard, quit "
37                                                                     "editable state." },
38    { static_cast<int32_t>(OperateIMEInfoCode::IME_HIDE_NORMAL), "HideSoftKeyboard, hide soft keyboard." },
39    { static_cast<int32_t>(OperateIMEInfoCode::IME_HIDE_UNFOCUSED), "OnUnfocused: unfocused, hide soft keyboard." },
40    { static_cast<int32_t>(OperateIMEInfoCode::IME_HIDE_SELF), "HideKeyboardSelf: hide soft keyboard self." },
41    { static_cast<int32_t>(OperateIMEInfoCode::IME_HIDE_FORCE), "HidePanel: force hide soft keyboard." }
42};
43
44std::map<int32_t, int32_t> InputMethodSysEvent::inputmethodBehaviour_ = {
45    { static_cast<int32_t>(IMEBehaviour::START_IME), 0 }, { static_cast<int32_t>(IMEBehaviour::CHANGE_IME), 0 }
46};
47
48InputMethodSysEvent::~InputMethodSysEvent()
49{
50    StopTimer();
51}
52
53InputMethodSysEvent &InputMethodSysEvent::GetInstance()
54{
55    static InputMethodSysEvent instance;
56    return instance;
57}
58
59void InputMethodSysEvent::ServiceFaultReporter(const std::string &componentName, int32_t errCode)
60{
61    IMSA_HILOGD("start.");
62    int32_t ret = HiSysEventWrite(HiSysEventNameSpace::Domain::INPUTMETHOD, "SERVICE_INIT_FAILED",
63        HiSysEventNameSpace::EventType::FAULT, "USER_ID", userId_, "COMPONENT_ID", componentName, "ERROR_CODE",
64        errCode);
65    if (ret != HiviewDFX::SUCCESS) {
66        IMSA_HILOGE("hisysevent ServiceFaultReporter failed! ret: %{public}d, errCode: %{public}d", ret, errCode);
67    }
68}
69
70void InputMethodSysEvent::InputmethodFaultReporter(int32_t errCode, const std::string &name, const std::string &info)
71{
72    IMSA_HILOGD("start.");
73    int32_t ret = HiSysEventWrite(HiSysEventNameSpace::Domain::INPUTMETHOD, "UNAVAILABLE_INPUTMETHOD",
74        HiSysEventNameSpace::EventType::FAULT, "USER_ID", userId_, "APP_NAME", name, "ERROR_CODE", errCode, "INFO",
75        info);
76    if (ret != HiviewDFX::SUCCESS) {
77        IMSA_HILOGE("hisysevent InputmethodFaultReporter failed! ret: %{public}d,errCode %{public}d", ret, errCode);
78    }
79}
80
81void InputMethodSysEvent::ImeUsageBehaviourReporter()
82{
83    IMSA_HILOGD("start.");
84    int ret = HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::INPUTMETHOD, "IME_USAGE",
85        HiSysEventNameSpace::EventType::STATISTIC, "IME_START",
86        inputmethodBehaviour_[static_cast<int32_t>(IMEBehaviour::START_IME)], "IME_CHANGE",
87        inputmethodBehaviour_[static_cast<int32_t>(IMEBehaviour::CHANGE_IME)]);
88    if (ret != HiviewDFX::SUCCESS) {
89        IMSA_HILOGE("hisysevent BehaviourReporter failed! ret: %{public}d", ret);
90    }
91    {
92        std::lock_guard<std::mutex> lock(behaviourMutex_);
93        inputmethodBehaviour_[static_cast<int32_t>(IMEBehaviour::START_IME)] = 0;
94        inputmethodBehaviour_[static_cast<int32_t>(IMEBehaviour::CHANGE_IME)] = 0;
95    }
96    StartTimerForReport();
97}
98
99void InputMethodSysEvent::RecordEvent(IMEBehaviour behaviour)
100{
101    IMSA_HILOGD("run in.");
102    std::lock_guard<std::mutex> lock(behaviourMutex_);
103    if (behaviour == IMEBehaviour::START_IME) {
104        ++inputmethodBehaviour_[static_cast<int32_t>(IMEBehaviour::START_IME)];
105    } else if (behaviour == IMEBehaviour::CHANGE_IME) {
106        ++inputmethodBehaviour_[static_cast<int32_t>(IMEBehaviour::CHANGE_IME)];
107    }
108}
109
110void InputMethodSysEvent::OperateSoftkeyboardBehaviour(OperateIMEInfoCode infoCode)
111{
112    IMSA_HILOGD("run in.");
113    int32_t ret = HiSysEventWrite(HiSysEventNameSpace::Domain::INPUTMETHOD, "OPERATE_SOFTKEYBOARD",
114        HiSysEventNameSpace::EventType::BEHAVIOR, "OPERATING", GetOperateAction(static_cast<int32_t>(infoCode)),
115        "OPERATE_INFO", GetOperateInfo(static_cast<int32_t>(infoCode)));
116    if (ret != HiviewDFX::SUCCESS) {
117        IMSA_HILOGE("Hisysevent: operate soft keyboard report failed! ret: %{public}d", ret);
118    }
119}
120
121void InputMethodSysEvent::ReportImeState(ImeState state, pid_t pid, const std::string &bundleName)
122{
123    IMSA_HILOGD("run in.");
124    int32_t ret = HiSysEventWrite(HiSysEventNameSpace::Domain::INPUTMETHOD, "IME_STATE_CHANGED",
125        HiSysEventNameSpace::EventType::BEHAVIOR, "STATE", static_cast<int32_t>(state), "PID", pid, "BUNDLE_NAME",
126        bundleName);
127    if (ret != HiviewDFX::SUCCESS) {
128        IMSA_HILOGE("ime: %{public}s state: %{public}d report failed! ret: %{public}d", bundleName.c_str(),
129            static_cast<int32_t>(state), ret);
130    }
131}
132
133const std::string InputMethodSysEvent::GetOperateInfo(int32_t infoCode)
134{
135    auto iter = operateInfo_.find(static_cast<int32_t>(infoCode));
136    if (iter != operateInfo_.end()) {
137        return iter->second;
138    }
139    return "unknow operating.";
140}
141
142std::string InputMethodSysEvent::GetOperateAction(int32_t infoCode)
143{
144    switch (infoCode) {
145        case static_cast<int32_t>(OperateIMEInfoCode::IME_SHOW_ATTACH):
146        case static_cast<int32_t>(OperateIMEInfoCode::IME_SHOW_ENEDITABLE):
147        case static_cast<int32_t>(OperateIMEInfoCode::IME_SHOW_NORMAL):
148            return "show";
149        case static_cast<int32_t>(OperateIMEInfoCode::IME_UNBIND):
150            return "unbind";
151        case static_cast<int32_t>(OperateIMEInfoCode::IME_HIDE_UNBIND):
152            return "hide and unbind";
153        case static_cast<int32_t>(OperateIMEInfoCode::IME_HIDE_UNEDITABLE):
154        case static_cast<int32_t>(OperateIMEInfoCode::IME_HIDE_NORMAL):
155        case static_cast<int32_t>(OperateIMEInfoCode::IME_HIDE_UNFOCUSED):
156        case static_cast<int32_t>(OperateIMEInfoCode::IME_HIDE_SELF):
157        case static_cast<int32_t>(OperateIMEInfoCode::IME_HIDE_FORCE):
158            return "hide";
159        default:
160            break;
161    }
162    return "unknow action.";
163}
164
165void InputMethodSysEvent::SetUserId(int32_t userId)
166{
167    userId_ = userId;
168}
169
170void InputMethodSysEvent::StopTimer()
171{
172    IMSA_HILOGD("start.");
173    std::lock_guard<std::mutex> lock(timerLock_);
174    if (timer_ == nullptr) {
175        IMSA_HILOGE("timer_ is nullptr.");
176        return;
177    }
178    timer_->Unregister(timerId_);
179    timer_->Shutdown();
180}
181
182bool InputMethodSysEvent::StartTimer(const TimerCallback &callback, uint32_t interval)
183{
184    IMSA_HILOGD("start.");
185    if (timer_ == nullptr) {
186        timer_ = std::make_shared<Utils::Timer>("OS_imfTimer");
187        uint32_t ret = timer_->Setup();
188        if (ret != Utils::TIMER_ERR_OK) {
189            IMSA_HILOGE("create Timer error.");
190            return false;
191        }
192        timerId_ = timer_->Register(callback, interval, true);
193    } else {
194        IMSA_HILOGD("timer_ is not nullptr, Update timer.");
195        timer_->Unregister(timerId_);
196        timerId_ = timer_->Register(callback, interval, false);
197    }
198    return true;
199}
200
201bool InputMethodSysEvent::StartTimerForReport()
202{
203    IMSA_HILOGD("start.");
204    auto reportCallback = [this]() { ImeUsageBehaviourReporter(); };
205    std::lock_guard<std::mutex> lock(timerLock_);
206    return StartTimer(reportCallback, ONE_DAY_IN_HOURS * ONE_HOUR_IN_SECONDS * SECONDS_TO_MILLISECONDS);
207}
208} // namespace MiscServices
209} // namespace OHOS