• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "key_command_manager.h"
17 #include "ability_manager_client.h"
18 #include "file_ex.h"
19 #include "mmi_log.h"
20 #include "ohos/aafwk/base/string_wrapper.h"
21 #include "timer_manager.h"
22 
23 namespace OHOS {
24 namespace MMI {
25     namespace {
26         constexpr int32_t MAX_PREKEYS_NUM = 4;
27         constexpr int32_t INVALID_VALUE = -1;
28         constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, MMI_LOG_DOMAIN, "KeyCommandManager" };
29     }
30 
KeyCommandManager()31 KeyCommandManager::KeyCommandManager()
32 {
33     const std::string configFile = GetConfigFilePath();
34     ResolveConfig(configFile);
35     Print();
36 }
37 
GenerateKey(const ShortcutKey & key)38 std::string KeyCommandManager::GenerateKey(const ShortcutKey& key)
39 {
40     std::set<int32_t> preKeys = key.preKeys;
41     std::stringstream oss;
42     for (const auto preKey: preKeys) {
43         oss << preKey << ",";
44     }
45     oss << key.finalKey << ",";
46     oss << key.triggerType;
47     return std::string(oss.str());
48 }
49 
GetConfigFilePath()50 std::string KeyCommandManager::GetConfigFilePath()
51 {
52     std::string defaultConfig = "/product/multimodalinput/ability_launch_config.json";
53     return FileExists(defaultConfig) ? defaultConfig : "/system/etc/multimodalinput/ability_launch_config.json";
54 }
55 
ResolveConfig(const std::string configFile)56 void KeyCommandManager::ResolveConfig(const std::string configFile)
57 {
58     if (!FileExists(configFile)) {
59         MMI_LOGE("config file %{public}s not exist", configFile.c_str());
60         return;
61     }
62     MMI_LOGD("config file path:%{public}s", configFile.c_str());
63     std::ifstream reader(configFile);
64     if (!reader.is_open()) {
65         MMI_LOGE("config file open failed");
66         return;
67     }
68     json configJson;
69     reader >> configJson;
70     reader.close();
71     if (configJson.empty()) {
72         MMI_LOGE("config file is empty");
73         return;
74     }
75     json shortkeys = configJson["Shortkeys"];
76     if (!shortkeys.is_array() || shortkeys.empty()) {
77         MMI_LOGE("shortkeys in config file is empty");
78         return;
79     }
80     for (size_t i = 0; i < shortkeys.size(); i++) {
81         ShortcutKey shortcutKey;
82         if (!ConvertToShortcutKey(shortkeys[i], shortcutKey)) {
83             continue;
84         }
85         std::string key = GenerateKey(shortcutKey);
86         auto res = shortcutKeys_.find(key);
87         if (res == shortcutKeys_.end()) {
88             shortcutKeys_.emplace(key, shortcutKey);
89         }
90     }
91 }
92 
ConvertToShortcutKey(const json & jsonData,ShortcutKey & shortcutKey)93 bool KeyCommandManager::ConvertToShortcutKey(const json &jsonData, ShortcutKey &shortcutKey)
94 {
95     json preKey = jsonData["preKey"];
96     if (!preKey.is_array() || preKey.size() > MAX_PREKEYS_NUM) {
97         MMI_LOGE("preKey number must less and equal four");
98         return false;
99     }
100 
101     for (size_t i = 0; i < preKey.size(); i++) {
102         if (!preKey[i].is_number() || preKey[i] < 0) {
103             MMI_LOGE("preKey must be number and bigger and equal 0");
104             return false;
105         }
106         auto ret = shortcutKey.preKeys.emplace(preKey[i]);
107         if (!ret.second) {
108             MMI_LOGE("preKey must be unique");
109             return false;
110         }
111     }
112     if (!jsonData["finalKey"].is_number()) {
113         MMI_LOGE("finalKey must be number");
114         return false;
115     }
116     shortcutKey.finalKey = jsonData["finalKey"];
117     if ((!jsonData["trigger"].is_string()) ||
118         (jsonData["trigger"].get<std::string>() != "key_up" && jsonData["trigger"].get<std::string>() != "key_down")) {
119         MMI_LOGE("trigger must be one of [key_up, key_down]");
120         return false;
121     }
122     if (jsonData["trigger"].get<std::string>() == "key_up") {
123         shortcutKey.triggerType = KeyEvent::KEY_ACTION_UP;
124     } else {
125         shortcutKey.triggerType = KeyEvent::KEY_ACTION_DOWN;
126     }
127     if ((!jsonData["keyDownDuration"].is_number()) || (jsonData["keyDownDuration"] < 0)) {
128         MMI_LOGE("keyDownDuration must be number and bigger and equal zero");
129         return false;
130     }
131     shortcutKey.keyDownDuration = jsonData["keyDownDuration"];
132     if (!PackageAbility(jsonData["ability"], shortcutKey.ability)) {
133         MMI_LOGE("package ability failed!");
134         return false;
135     }
136     return true;
137 }
138 
PackageAbility(const json & jsonAbility,Ability & ability)139 bool KeyCommandManager::PackageAbility(const json &jsonAbility, Ability &ability)
140 {
141     if (!jsonAbility.is_object()) {
142         MMI_LOGE("ability must be object");
143         return false;
144     }
145     if (!jsonAbility["entities"].is_array()) {
146         MMI_LOGE("entities must be array!");
147         return false;
148     }
149     if (!jsonAbility["params"].is_array()) {
150         MMI_LOGE("params must be array!");
151         return false;
152     }
153     ability.bundleName = jsonAbility["bundleName"];
154     ability.abilityName = jsonAbility["abilityName"];
155     ability.action = jsonAbility["action"];
156     ability.type = jsonAbility["type"];
157     ability.deviceId = jsonAbility["deviceId"];
158     ability.uri = jsonAbility["uri"];
159     for (size_t i = 0; i < jsonAbility["entities"].size(); i++) {
160         ability.entities.push_back(jsonAbility["entities"][i]);
161     }
162     json params = jsonAbility["params"];
163     for (size_t i = 0; i < params.size(); i++) {
164         if (!params[i].is_object()) {
165             MMI_LOGE("param must be object");
166             return false;
167         }
168         ability.params.emplace(params[i]["key"], params[i]["value"]);
169     }
170     return true;
171 }
172 
Print()173 void KeyCommandManager::Print()
174 {
175     uint32_t count = shortcutKeys_.size();
176     MMI_LOGD("shortcutKey count:%{public}u", count);
177     for (const auto &item : shortcutKeys_) {
178         auto &shortcutKey = item.second;
179         for (auto prekey: shortcutKey.preKeys) {
180             MMI_LOGD("preKey:%{public}d", prekey);
181         }
182         MMI_LOGD("finalKey:%{public}d,keyDownDuration:%{public}d,triggerType:%{public}d,"
183             " bundleName:%{public}s,abilityName:%{public}s", shortcutKey.finalKey,
184             shortcutKey.keyDownDuration, shortcutKey.triggerType,
185             shortcutKey.ability.bundleName.c_str(), shortcutKey.ability.abilityName.c_str());
186     }
187 }
188 
HandlerEvent(const std::shared_ptr<KeyEvent> event)189 bool KeyCommandManager::HandlerEvent(const std::shared_ptr<KeyEvent> event)
190 {
191     MMI_LOGD("enter");
192     if (IsKeyMatch(lastMatchedKey_, event)) {
193         MMI_LOGE("The same event is waiting timeout, skip");
194         return true;
195     }
196     if (lastMatchedKey_.timerId >= 0) {
197         MMI_LOGE("remove timer timeid:%{public}d", lastMatchedKey_.timerId);
198         TimerMgr->RemoveTimer(lastMatchedKey_.timerId);
199     }
200     ResetLastMatchedKey();
201     for (auto iter = shortcutKeys_.begin(); iter != shortcutKeys_.end(); ++iter) {
202         ShortcutKey &shortcutKey = iter->second;
203         if (!IsKeyMatch(shortcutKey, event)) {
204             MMI_LOGD("not matched, next");
205             continue;
206         }
207         for (const auto &prekey: shortcutKey.preKeys) {
208             MMI_LOGD("eventkey matched, preKey:%{public}d", prekey);
209         }
210         MMI_LOGD("eventkey matched, finalKey:%{public}d,bundleName:%{public}s",
211             shortcutKey.finalKey, shortcutKey.ability.bundleName.c_str());
212         if (shortcutKey.triggerType == KeyEvent::KEY_ACTION_DOWN) {
213             return HandleKeyDown(shortcutKey);
214         } else if (shortcutKey.triggerType == KeyEvent::KEY_ACTION_UP) {
215             return HandleKeyUp(event, shortcutKey);
216         } else {
217             return HandleKeyCancel(shortcutKey);
218         }
219     }
220     MMI_LOGD("leave");
221     return false;
222 }
223 
IsKeyMatch(const ShortcutKey & shortcutKey,const std::shared_ptr<KeyEvent> & key)224 bool KeyCommandManager::IsKeyMatch(const ShortcutKey &shortcutKey, const std::shared_ptr<KeyEvent> &key)
225 {
226     MMI_LOGD("enter");
227     if (key->GetKeyCode() != shortcutKey.finalKey || shortcutKey.triggerType != key->GetKeyAction()) {
228         return false;
229     }
230     if ((shortcutKey.preKeys.size()) != (key->GetKeyItems().size() - 1)) {  // KeyItems contain finalkey, so decrease 1
231         return false;
232     }
233     for (const auto &item : key->GetKeyItems()) {
234         int32_t keyCode = item.GetKeyCode();
235         if (keyCode == key->GetKeyCode()) {
236             continue;
237         }
238         auto res = shortcutKey.preKeys.find(keyCode);
239         if (res == shortcutKey.preKeys.end()) {
240             return false;
241         }
242     }
243     MMI_LOGD("matched...");
244     return true;
245 }
246 
HandleKeyDown(ShortcutKey & shortcutKey)247 bool KeyCommandManager::HandleKeyDown(ShortcutKey &shortcutKey)
248 {
249     MMI_LOGD("enter");
250     if (shortcutKey.keyDownDuration == 0) {
251         MMI_LOGD("Start launch ability immediately");
252         LaunchAbility(shortcutKey);
253     } else {
254         shortcutKey.timerId = TimerMgr->AddTimer(shortcutKey.keyDownDuration, 1, [this, shortcutKey] () {
255             MMI_LOGD("Timer callback");
256             LaunchAbility(shortcutKey);
257         });
258         if (shortcutKey.timerId < 0) {
259             MMI_LOGE("Timer add failed");
260             return false;
261         }
262         MMI_LOGD("add timer success, timeid:%{public}d", shortcutKey.timerId);
263         lastMatchedKey_ = shortcutKey;
264     }
265     return true;
266 }
267 
HandleKeyUp(const std::shared_ptr<KeyEvent> & keyEvent,const ShortcutKey & shortcutKey)268 bool KeyCommandManager::HandleKeyUp(const std::shared_ptr<KeyEvent> &keyEvent, const ShortcutKey &shortcutKey)
269 {
270     MMI_LOGD("enter");
271     if (shortcutKey.keyDownDuration == 0) {
272         MMI_LOGD("Start launch ability immediately");
273         LaunchAbility(shortcutKey);
274         return true;
275     } else {
276         const KeyEvent::KeyItem* keyItem = keyEvent->GetKeyItem();
277         CHKPF(keyItem);
278         auto upTime = keyEvent->GetActionTime();
279         auto downTime = keyItem->GetDownTime();
280         MMI_LOGD("UpTime:%{public}" PRId64 ",downTime:%{public}" PRId64 ",keyDownDuration:%{public}d",
281             upTime, downTime, shortcutKey.keyDownDuration);
282         if (upTime - downTime >= static_cast<int64_t>(shortcutKey.keyDownDuration) * 1000) {
283             MMI_LOGD("Skip, upTime - downTime >= duration");
284             return false;
285         }
286         MMI_LOGD("Start launch ability immediately");
287         LaunchAbility(shortcutKey);
288         return true;
289     }
290 }
291 
HandleKeyCancel(ShortcutKey & shortcutKey)292 bool KeyCommandManager::HandleKeyCancel(ShortcutKey &shortcutKey)
293 {
294     MMI_LOGD("enter");
295     if (shortcutKey.timerId < 0) {
296         MMI_LOGE("Skip, timerid < 0");
297     }
298     auto timerId = shortcutKey.timerId;
299     shortcutKey.timerId = -1;
300     TimerMgr->RemoveTimer(timerId);
301     MMI_LOGD("Leave, timerId: %{public}d", timerId);
302     return false;
303 }
304 
LaunchAbility(ShortcutKey key)305 void KeyCommandManager::LaunchAbility(ShortcutKey key)
306 {
307     AAFwk::Want want;
308     want.SetElementName(key.ability.deviceId, key.ability.bundleName, key.ability.abilityName);
309     want.SetAction(key.ability.action);
310     want.SetUri(key.ability.uri);
311     want.SetType(key.ability.uri);
312     for (const auto &entity : key.ability.entities) {
313         want.AddEntity(entity);
314     }
315     AAFwk::WantParams wParams;
316     for (const auto &item : key.ability.params) {
317         wParams.SetParam(item.first, AAFwk::String::Box(item.second));
318     }
319     want.SetParams(wParams);
320     MMI_LOGD("Start launch ability, bundleName:%{public}s", key.ability.bundleName.c_str());
321     ErrCode err = AAFwk::AbilityManagerClient::GetInstance()->StartAbility(want);
322     if (err != ERR_OK) {
323         MMI_LOGE("LaunchAbility failed, bundleName:%{public}s,err:%{public}d", key.ability.bundleName.c_str(), err);
324     }
325     ResetLastMatchedKey();
326     MMI_LOGD("End launch ability, bundleName:%{public}s", key.ability.bundleName.c_str());
327 }
328 
ResetLastMatchedKey()329 void KeyCommandManager::ResetLastMatchedKey()
330 {
331     lastMatchedKey_.preKeys.clear();
332     lastMatchedKey_.finalKey = INVALID_VALUE;
333     lastMatchedKey_.timerId = INVALID_VALUE;
334 }
335 
GetInstance()336 std::shared_ptr<IKeyCommandManager> IKeyCommandManager::GetInstance()
337 {
338     if (keyCommand_ == nullptr) {
339         keyCommand_ = std::make_shared<KeyCommandManager>();
340     }
341     return keyCommand_;
342 }
343 } // namespace MMI
344 } // namespace OHOS