• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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_shortcut_manager.h"
17 
18 #include "app_state_observer.h"
19 #include "json_parser.h"
20 #include "key_command_handler_util.h"
21 
22 #undef MMI_LOG_DOMAIN
23 #define MMI_LOG_DOMAIN MMI_LOG_HANDLER
24 #undef MMI_LOG_TAG
25 #define MMI_LOG_TAG "KeyShortcutManager"
26 
27 namespace OHOS {
28 namespace MMI {
29 namespace {
30 constexpr size_t SINGLE_MODIFIER { 1 };
31 constexpr size_t MAX_N_PRINTABLE_ITEMS { 3 };
32 constexpr int32_t MAXIMUM_LONG_PRESS_TIME { 60000 }; // 60s
33 constexpr int32_t REPEAT_ONCE { 1 };
34 }
35 
36 std::mutex KeyShortcutManager::mutex_;
37 std::shared_ptr<KeyShortcutManager> KeyShortcutManager::instance_;
38 
39 const std::map<int32_t, uint32_t> KeyShortcutManager::modifiers_ {
40     { KeyEvent::KEYCODE_ALT_LEFT, SHORTCUT_MODIFIER_ALT },
41     { KeyEvent::KEYCODE_ALT_RIGHT, SHORTCUT_MODIFIER_ALT },
42     { KeyEvent::KEYCODE_SHIFT_LEFT, SHORTCUT_MODIFIER_SHIFT },
43     { KeyEvent::KEYCODE_SHIFT_RIGHT, SHORTCUT_MODIFIER_SHIFT },
44     { KeyEvent::KEYCODE_CTRL_LEFT, SHORTCUT_MODIFIER_CTRL },
45     { KeyEvent::KEYCODE_CTRL_RIGHT, SHORTCUT_MODIFIER_CTRL },
46     { KeyEvent::KEYCODE_META_LEFT, SHORTCUT_MODIFIER_LOGO },
47     { KeyEvent::KEYCODE_META_RIGHT, SHORTCUT_MODIFIER_LOGO }
48 };
49 
operator <(const SystemKey & other) const50 bool KeyShortcutManager::SystemKey::operator<(const SystemKey &other) const
51 {
52     uint32_t modifier1 = (modifiers & SHORTCUT_MODIFIER_MASK);
53     uint32_t modifier2 = (other.modifiers & SHORTCUT_MODIFIER_MASK);
54     if (modifier1 != modifier2) {
55         return (modifier1 < modifier2);
56     }
57     return (finalKey < other.finalKey);
58 }
59 
operator <(const ExceptionalSystemKey & other) const60 bool KeyShortcutManager::ExceptionalSystemKey::operator<(const ExceptionalSystemKey &other) const
61 {
62     if (finalKey != other.finalKey) {
63         return (finalKey < other.finalKey);
64     }
65     if (longPressTime != other.longPressTime) {
66         return (longPressTime < other.longPressTime);
67     }
68     if (triggerType != other.triggerType) {
69         return (triggerType < other.triggerType);
70     }
71     return (preKeys < other.preKeys);
72 }
73 
operator <(const SystemHotkey & other) const74 bool KeyShortcutManager::SystemHotkey::operator<(const SystemHotkey &other) const
75 {
76     if (finalKey != other.finalKey) {
77         return (finalKey < other.finalKey);
78     }
79     return (preKeys < other.preKeys);
80 }
81 
GetInstance()82 std::shared_ptr<KeyShortcutManager> KeyShortcutManager::GetInstance()
83 {
84     if (instance_ == nullptr) {
85         std::lock_guard<std::mutex> guard(mutex_);
86         if (instance_ == nullptr) {
87             instance_ = std::make_shared<KeyShortcutManager>();
88         }
89     }
90     return instance_;
91 }
92 
KeyShortcutManager()93 KeyShortcutManager::KeyShortcutManager()
94 {
95     LoadSystemKeys();
96     LoadExceptionalSystemKeys();
97     LoadHotkeys();
98 }
99 
RegisterSystemKey(const SystemShortcutKey & key)100 int32_t KeyShortcutManager::RegisterSystemKey(const SystemShortcutKey &key)
101 {
102     KeyShortcut shortcut {};
103     ExceptionalSystemKey eSysKey {
104         .preKeys = key.modifiers,
105         .finalKey = key.finalKey,
106         .longPressTime = key.longPressTime,
107         .triggerType = key.triggerType,
108     };
109 
110     if (!CheckSystemKey(key, shortcut)) {
111         MMI_HILOGE("Not system key ([%{private}s],FinalKey:%{private}d,PressTime:%{public}d,TriggerType:%{public}d)",
112             FormatModifiers(key.modifiers).c_str(), key.finalKey, key.longPressTime, key.triggerType);
113         if (IsExceptionalSystemKey(eSysKey)) {
114             auto shortcutId = GenerateId();
115             MMI_HILOGI("Register exceptional system key [No.%{public}d]"
116                 "([%{private}s],FinalKey:%{private}d,PressTime:%{public}d,TriggerType:%{public}d)",
117                 shortcutId, FormatModifiers(key.modifiers).c_str(), key.finalKey, key.longPressTime, key.triggerType);
118             return shortcutId;
119         }
120         return KEY_SHORTCUT_ERROR_COMBINATION_KEY;
121     }
122     if (!IsReservedSystemKey(shortcut)) {
123         if (IsExceptionalSystemKey(eSysKey)) {
124             auto shortcutId = GenerateId();
125             MMI_HILOGI("Register exceptional system key [No.%{public}d]"
126                 "([%{private}s],FinalKey:%{private}d,PressTime:%{public}d,TriggerType:%{public}d)",
127                 shortcutId, FormatModifiers(key.modifiers).c_str(), key.finalKey, key.longPressTime, key.triggerType);
128             return shortcutId;
129         }
130         MMI_HILOGE("The system application can only subscribe to reserved shortcuts");
131         return KEY_SHORTCUT_ERROR_COMBINATION_KEY;
132     }
133     auto [iter, _] = shortcuts_.emplace(GenerateId(), shortcut);
134     MMI_HILOGI("Register system key [No.%{public}d](0x%{private}x,%{private}d,%{public}d,%{public}d,%{public}d)",
135         iter->first, shortcut.modifiers, shortcut.finalKey, shortcut.longPressTime,
136         shortcut.triggerType, shortcut.session);
137     return iter->first;
138 }
139 
UnregisterSystemKey(int32_t shortcutId)140 void KeyShortcutManager::UnregisterSystemKey(int32_t shortcutId)
141 {
142     auto iter = shortcuts_.find(shortcutId);
143     if (iter == shortcuts_.end()) {
144         MMI_HILOGI("There is no system key(%{public}d)", shortcutId);
145         return;
146     }
147     const KeyShortcut &key = iter->second;
148     MMI_HILOGI("Unregister system key(0x%{private}x,%{private}d,%{public}d,%{public}d,SESSION:%{public}d)",
149         key.modifiers, key.finalKey, key.longPressTime, key.triggerType, key.session);
150     ResetTriggering(shortcutId);
151     shortcuts_.erase(iter);
152 }
153 
RegisterHotKey(const HotKey & key)154 int32_t KeyShortcutManager::RegisterHotKey(const HotKey &key)
155 {
156     KeyShortcut globalKey {};
157 
158     if (!CheckGlobalKey(key, globalKey)) {
159         MMI_HILOGE("Not global shortcut key");
160         return KEY_SHORTCUT_ERROR_COMBINATION_KEY;
161     }
162     if (HaveRegisteredGlobalKey(globalKey)) {
163         MMI_HILOGE("Global key (0x%{private}x, %{private}d) has been taken", globalKey.modifiers, globalKey.finalKey);
164         return KEY_SHORTCUT_ERROR_TAKEN;
165     }
166     if (IsReservedSystemKey(globalKey)) {
167         MMI_HILOGE("Can not register reserved system key ([%{private}s],%{private}d)",
168             FormatModifiers(key.modifiers).c_str(), key.finalKey);
169         return KEY_SHORTCUT_ERROR_COMBINATION_KEY;
170     }
171     auto [iter, _] = shortcuts_.emplace(GenerateId(), globalKey);
172     MMI_HILOGI("Register global key [No.%{public}d](0x%{private}x,%{private}d,SESSION:%{public}d)",
173         iter->first, globalKey.modifiers, globalKey.finalKey, globalKey.session);
174     return iter->first;
175 }
176 
UnregisterHotKey(int32_t shortcutId)177 void KeyShortcutManager::UnregisterHotKey(int32_t shortcutId)
178 {
179     auto iter = shortcuts_.find(shortcutId);
180     if (iter == shortcuts_.end()) {
181         MMI_HILOGI("There is no global key(%{public}d)", shortcutId);
182         return;
183     }
184     const KeyShortcut &key = iter->second;
185     MMI_HILOGI("Unregister global key(0x%{private}x,%{private}d,SESSION:%{public}d)",
186         key.modifiers, key.finalKey, key.session);
187     shortcuts_.erase(iter);
188 }
189 
HandleEvent(std::shared_ptr<KeyEvent> keyEvent)190 bool KeyShortcutManager::HandleEvent(std::shared_ptr<KeyEvent> keyEvent)
191 {
192     CHKPF(keyEvent);
193     MMI_HILOGI("Handle key event(No.%{public}d,KC:%{private}d,KA:%{public}d,PressedKeys:[%{private}s])",
194         keyEvent->GetId(), keyEvent->GetKeyCode(), keyEvent->GetKeyAction(), FormatPressedKeys(keyEvent).c_str());
195     ResetTriggering(keyEvent);
196     if (keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_DOWN) {
197         return HandleKeyDown(keyEvent);
198     } else if (keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_UP) {
199         return HandleKeyUp(keyEvent);
200     } else if (keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_CANCEL) {
201         return HandleKeyCancel(keyEvent);
202     }
203     return false;
204 }
205 
LoadSystemKeys()206 void KeyShortcutManager::LoadSystemKeys()
207 {
208     char cfgName[] { "etc/multimodalinput/system_keys_config.json" };
209     char buf[MAX_PATH_LEN] {};
210     char *cfgPath = ::GetOneCfgFile(cfgName, buf, sizeof(buf));
211 
212     if (cfgPath == nullptr) {
213         MMI_HILOGE("No '%{private}s' was found", cfgName);
214         return;
215     }
216     MMI_HILOGI("Config of system keys:%{private}s", cfgPath);
217     ReadSystemKeys(std::string(cfgPath));
218 }
219 
ReadSystemKeys(const std::string & cfgPath)220 void KeyShortcutManager::ReadSystemKeys(const std::string &cfgPath)
221 {
222     std::string cfg = ReadJsonFile(cfgPath);
223     JsonParser parser(cfg.c_str());
224     if (!cJSON_IsObject(parser.Get())) {
225         MMI_HILOGE("Not json format");
226         return;
227     }
228     cJSON* jsonSysKeys = cJSON_GetObjectItemCaseSensitive(parser.Get(), "SystemKeys");
229     CHKPV(jsonSysKeys);
230     if (!cJSON_IsArray(jsonSysKeys)) {
231         MMI_HILOGE("The system keys is not array");
232         return;
233     }
234     int32_t nSysKeys = cJSON_GetArraySize(jsonSysKeys);
235     for (int32_t index = 0; index < nSysKeys; ++index) {
236         cJSON *jsonSysKey = cJSON_GetArrayItem(jsonSysKeys, index);
237         CHKPC(jsonSysKey);
238         ReadSystemKey(jsonSysKey);
239     }
240 }
241 
ReadSystemKey(cJSON * jsonSysKey)242 int32_t KeyShortcutManager::ReadSystemKey(cJSON *jsonSysKey)
243 {
244     if (!cJSON_IsObject(jsonSysKey)) {
245         MMI_HILOGE("Not json object");
246         return KEY_SHORTCUT_ERROR_CONFIG;
247     }
248     cJSON *jsonPreKeys = cJSON_GetObjectItem(jsonSysKey, "preKeys");
249     if (!cJSON_IsArray(jsonPreKeys)) {
250         MMI_HILOGE("Expect array for PreKeys");
251         return KEY_SHORTCUT_ERROR_CONFIG;
252     }
253     std::set<int32_t> preKeys;
254     int32_t nPreKeys = cJSON_GetArraySize(jsonPreKeys);
255 
256     for (int32_t index = 0; index < nPreKeys; ++index) {
257         cJSON *jsonPreKey = cJSON_GetArrayItem(jsonPreKeys, index);
258         if (!cJSON_IsNumber(jsonPreKey)) {
259             MMI_HILOGE("Expect number for PreKey");
260             return KEY_SHORTCUT_ERROR_CONFIG;
261         }
262         preKeys.insert(static_cast<int32_t>(cJSON_GetNumberValue(jsonPreKey)));
263     }
264     cJSON *jsonFinalKey = cJSON_GetObjectItem(jsonSysKey, "finalKey");
265     if (!cJSON_IsNumber(jsonFinalKey)) {
266         MMI_HILOGE("Expect number for FinalKey");
267         return KEY_SHORTCUT_ERROR_CONFIG;
268     }
269     int32_t finalKey = static_cast<int32_t>(cJSON_GetNumberValue(jsonFinalKey));
270     return AddSystemKey(preKeys, finalKey);
271 }
272 
AddSystemKey(const std::set<int32_t> & preKeys,int32_t finalKey)273 int32_t KeyShortcutManager::AddSystemKey(const std::set<int32_t> &preKeys, int32_t finalKey)
274 {
275     SystemShortcutKey sysKey {
276         .modifiers = preKeys,
277         .finalKey = finalKey,
278     };
279     KeyShortcut shortcut {};
280 
281     if (!CheckSystemKey(sysKey, shortcut)) {
282         MMI_HILOGE("Not system key ([%{private}s],%{private}d)", FormatModifiers(preKeys).c_str(), finalKey);
283         return KEY_SHORTCUT_ERROR_COMBINATION_KEY;
284     }
285     systemKeys_.emplace(SystemKey {
286         .modifiers = shortcut.modifiers,
287         .finalKey = shortcut.finalKey,
288     });
289     return RET_OK;
290 }
291 
LoadExceptionalSystemKeys()292 void KeyShortcutManager::LoadExceptionalSystemKeys()
293 {
294     char cfgName[] { "etc/multimodalinput/exceptional_system_keys_config.json" };
295     char buf[MAX_PATH_LEN] {};
296     char *cfgPath = ::GetOneCfgFile(cfgName, buf, sizeof(buf));
297 
298     if (cfgPath == nullptr) {
299         MMI_HILOGE("GetoneCfgFile failed");
300         return;
301     }
302     MMI_HILOGI("Config of exceptional system keys:%{private}s", cfgPath);
303     ReadExceptionalSystemKeys(std::string(cfgPath));
304 }
305 
ReadExceptionalSystemKeys(const std::string & cfgPath)306 void KeyShortcutManager::ReadExceptionalSystemKeys(const std::string &cfgPath)
307 {
308     std::string cfg = ReadJsonFile(cfgPath);
309     JsonParser parser(cfg.c_str());
310     if (!cJSON_IsObject(parser.Get())) {
311         MMI_HILOGE("Not json format");
312         return;
313     }
314     cJSON* jsonSysKeys = cJSON_GetObjectItemCaseSensitive(parser.Get(), "ExceptionalSystemKeys");
315     if (!cJSON_IsArray(jsonSysKeys)) {
316         MMI_HILOGE("The exceptional system keys is not array");
317         return;
318     }
319     int32_t nSysKeys = cJSON_GetArraySize(jsonSysKeys);
320     for (int32_t index = 0; index < nSysKeys; ++index) {
321         cJSON *jsonSysKey = cJSON_GetArrayItem(jsonSysKeys, index);
322         ReadExceptionalSystemKey(jsonSysKey);
323     }
324 }
325 
ReadExceptionalSystemKey(cJSON * jsonSysKey)326 int32_t KeyShortcutManager::ReadExceptionalSystemKey(cJSON *jsonSysKey)
327 {
328     if (!cJSON_IsObject(jsonSysKey)) {
329         MMI_HILOGE("Not json object");
330         return KEY_SHORTCUT_ERROR_CONFIG;
331     }
332     ExceptionalSystemKey sysKey {};
333     cJSON *jsonPreKeys = cJSON_GetObjectItem(jsonSysKey, "preKeys");
334     if (!cJSON_IsArray(jsonPreKeys)) {
335         MMI_HILOGE("Expect array for PreKeys");
336         return KEY_SHORTCUT_ERROR_CONFIG;
337     }
338     int32_t nPreKeys = cJSON_GetArraySize(jsonPreKeys);
339 
340     for (int32_t index = 0; index < nPreKeys; ++index) {
341         cJSON *jsonPreKey = cJSON_GetArrayItem(jsonPreKeys, index);
342         if (!cJSON_IsNumber(jsonPreKey)) {
343             MMI_HILOGE("Expect number for PreKey");
344             return KEY_SHORTCUT_ERROR_CONFIG;
345         }
346         sysKey.preKeys.insert(static_cast<int32_t>(cJSON_GetNumberValue(jsonPreKey)));
347     }
348     cJSON *jsonFinalKey = cJSON_GetObjectItem(jsonSysKey, "finalKey");
349     if (!cJSON_IsNumber(jsonFinalKey)) {
350         MMI_HILOGE("Expect number for FinalKey");
351         return KEY_SHORTCUT_ERROR_CONFIG;
352     }
353     sysKey.finalKey = static_cast<int32_t>(cJSON_GetNumberValue(jsonFinalKey));
354 
355     cJSON *jsonPressTime = cJSON_GetObjectItem(jsonSysKey, "longPressTime");
356     if (!cJSON_IsNumber(jsonPressTime)) {
357         MMI_HILOGE("Expect number for LongPressTime");
358         return KEY_SHORTCUT_ERROR_CONFIG;
359     }
360     sysKey.longPressTime = static_cast<int32_t>(cJSON_GetNumberValue(jsonPressTime));
361 
362     cJSON *jsonTriggerType = cJSON_GetObjectItem(jsonSysKey, "triggerType");
363     char *triggerType = cJSON_GetStringValue(jsonTriggerType);
364     if ((triggerType == nullptr) ||
365         ((std::strcmp(triggerType, "down") != 0) && (std::strcmp(triggerType, "up") != 0))) {
366         MMI_HILOGE("Expect down/up for TriggerType");
367         return KEY_SHORTCUT_ERROR_CONFIG;
368     }
369     sysKey.triggerType = (std::strcmp(triggerType, "down") == 0 ?
370                           SHORTCUT_TRIGGER_TYPE_DOWN : SHORTCUT_TRIGGER_TYPE_UP);
371 
372     AddExceptionalSystemKey(sysKey);
373     return RET_OK;
374 }
375 
AddExceptionalSystemKey(const ExceptionalSystemKey & sysKey)376 void KeyShortcutManager::AddExceptionalSystemKey(const ExceptionalSystemKey &sysKey)
377 {
378     MMI_HILOGI("Add exceptional system key ([%{private}s],FinalKey:%{private}d,PressTime:%{public}d,%{public}s)",
379         FormatModifiers(sysKey.preKeys).c_str(), sysKey.finalKey, sysKey.longPressTime,
380         (sysKey.triggerType == SHORTCUT_TRIGGER_TYPE_DOWN ? "down" : "up"));
381     exceptSysKeys_.emplace(sysKey);
382 }
383 
FormatModifiers(const std::set<int32_t> & modifiers) const384 std::string KeyShortcutManager::FormatModifiers(const std::set<int32_t> &modifiers) const
385 {
386     std::ostringstream sModifiers;
387     size_t nModifiers = 0;
388 
389     if (auto iter = modifiers.cbegin(); iter != modifiers.cend()) {
390         sModifiers << *iter;
391         ++nModifiers;
392 
393         for (++iter; iter != modifiers.cend(); ++iter) {
394             if (nModifiers > MAX_N_PRINTABLE_ITEMS) {
395                 sModifiers << ",...";
396                 break;
397             }
398             sModifiers << "," << *iter;
399             ++nModifiers;
400         }
401     }
402     return sModifiers.str();
403 }
404 
GenerateId() const405 int32_t KeyShortcutManager::GenerateId() const
406 {
407     static int32_t baseId {};
408     return ++baseId;
409 }
410 
IsExceptionalSystemKey(const ExceptionalSystemKey & sysKey) const411 bool KeyShortcutManager::IsExceptionalSystemKey(const ExceptionalSystemKey &sysKey) const
412 {
413     return (exceptSysKeys_.find(sysKey) != exceptSysKeys_.cend());
414 }
415 
IsModifier(int32_t keyCode)416 bool KeyShortcutManager::IsModifier(int32_t keyCode)
417 {
418     return (modifiers_.find(keyCode) != modifiers_.cend());
419 }
420 
IsValid(const ShortcutTriggerType triggerType) const421 bool KeyShortcutManager::IsValid(const ShortcutTriggerType triggerType) const
422 {
423     return ((triggerType == SHORTCUT_TRIGGER_TYPE_DOWN) ||
424             (triggerType == SHORTCUT_TRIGGER_TYPE_UP));
425 }
426 
IsReservedSystemKey(const KeyShortcut & shortcut) const427 bool KeyShortcutManager::IsReservedSystemKey(const KeyShortcut &shortcut) const
428 {
429     return (systemKeys_.find(SystemKey {
430         .modifiers = shortcut.modifiers,
431         .finalKey = shortcut.finalKey,
432     }) != systemKeys_.cend());
433 }
434 
CheckSystemKey(const SystemShortcutKey & key,KeyShortcut & shortcut) const435 bool KeyShortcutManager::CheckSystemKey(const SystemShortcutKey &key, KeyShortcut &shortcut) const
436 {
437     size_t nModifiers = 0;
438     uint32_t modifiers = 0U;
439 
440     for (auto keyCode : key.modifiers) {
441         auto iter = modifiers_.find(keyCode);
442         if (iter == modifiers_.end()) {
443             MMI_HILOGE("Key code (%{private}d) is not modifier", keyCode);
444             return false;
445         }
446         if ((modifiers & iter->second) != iter->second) {
447             modifiers |= iter->second;
448             ++nModifiers;
449         }
450     }
451     if (nModifiers < SINGLE_MODIFIER) {
452         MMI_HILOGD("Require modifier(s)");
453         return false;
454     }
455     if (key.finalKey == SHORTCUT_PURE_MODIFIERS) {
456         if ((nModifiers == SINGLE_MODIFIER) && (modifiers != SHORTCUT_MODIFIER_LOGO)) {
457             MMI_HILOGE("Only 'Logo' can be one-key shortcut");
458             return false;
459         }
460     } else if (IsModifier(key.finalKey)) {
461         MMI_HILOGE("Modifier as final key");
462         return false;
463     }
464     if (!IsValid(key.triggerType)) {
465         MMI_HILOGE("Invalid trigger type(%{public}d)", key.triggerType);
466         return false;
467     }
468     if ((key.longPressTime < 0) || (key.longPressTime > MAXIMUM_LONG_PRESS_TIME)) {
469         MMI_HILOGE("Long-press time(%{public}d) is out of range [0,%{public}d]",
470             key.longPressTime, MAXIMUM_LONG_PRESS_TIME);
471         return false;
472     }
473     shortcut = KeyShortcut {
474         .modifiers = modifiers,
475         .finalKey = key.finalKey,
476         .longPressTime = key.longPressTime,
477         .triggerType = key.triggerType,
478         .session = key.session,
479         .callback = key.callback,
480     };
481     return true;
482 }
483 
CheckGlobalKey(const HotKey & key,KeyShortcut & shortcut) const484 bool KeyShortcutManager::CheckGlobalKey(const HotKey &key, KeyShortcut &shortcut) const
485 {
486     size_t nModifiers = 0;
487     uint32_t modifiers = 0U;
488 
489     for (auto keyCode : key.modifiers) {
490         auto iter = modifiers_.find(keyCode);
491         if (iter == modifiers_.end()) {
492             MMI_HILOGE("Key code (%{private}d) is not modifier", keyCode);
493             return false;
494         }
495         if ((modifiers & iter->second) != iter->second) {
496             modifiers |= iter->second;
497             ++nModifiers;
498         }
499     }
500     if (IsModifier(key.finalKey)) {
501         MMI_HILOGE("FinalKey(%{private}d) should not be modifier", key.finalKey);
502         return false;
503     }
504     if (key.finalKey == SHORTCUT_PURE_MODIFIERS) {
505         MMI_HILOGE("Expect FinalKey");
506         return false;
507     }
508     if (modifiers & SHORTCUT_MODIFIER_LOGO) {
509         MMI_HILOGE("'LOGO' is not allowed for GlobalKey");
510         return false;
511     }
512     if (nModifiers < SINGLE_MODIFIER) {
513         MMI_HILOGE("Require modifier(s)");
514         return false;
515     }
516     shortcut = KeyShortcut {
517         .modifiers = modifiers,
518         .finalKey = key.finalKey,
519         .triggerType = SHORTCUT_TRIGGER_TYPE_DOWN,
520         .session = key.session,
521         .callback = key.callback,
522     };
523     return true;
524 }
525 
HaveRegisteredGlobalKey(const KeyShortcut & key) const526 bool KeyShortcutManager::HaveRegisteredGlobalKey(const KeyShortcut &key) const
527 {
528     auto iter = std::find_if(shortcuts_.cbegin(), shortcuts_.cend(),
529         [&key](const auto &item) {
530             return ((item.second.modifiers == key.modifiers) &&
531                     (item.second.finalKey == key.finalKey));
532         });
533     // We met the problem: key-shortcut does not differentiate left/right CTRL/SHIFT/ALT/LOGO.
534     // but the implementation of key-shortcut reuse the logic of key-subscription, which
535     // treat left/right CTRL/SHIFT/ALT/LOGO as different keys. That means, for 'CTRL+A' etc
536     // to work as expected, we have to subscribe both 'LEFT-CTRL+A' and 'RIGHT-CTRL+A'.
537     // But duplicate global key registration will fail according to key-shortcut rules.
538     // We relax this retriction here to allow duplicate global key registration from same application.
539     return (iter != shortcuts_.cend() ? (iter->second.session != key.session) : false);
540 }
541 
FormatPressedKeys(std::shared_ptr<KeyEvent> keyEvent) const542 std::string KeyShortcutManager::FormatPressedKeys(std::shared_ptr<KeyEvent> keyEvent) const
543 {
544     auto pressedKeys = keyEvent->GetPressedKeys();
545     std::ostringstream sPressedKeys;
546     size_t nPressedKeys = 0;
547 
548     if (auto iter = pressedKeys.cbegin(); iter != pressedKeys.cend()) {
549         sPressedKeys << *iter;
550         ++nPressedKeys;
551 
552         for (++iter; iter != pressedKeys.cend(); ++iter) {
553             if (nPressedKeys > MAX_N_PRINTABLE_ITEMS) {
554                 sPressedKeys << ",...";
555                 break;
556             }
557             sPressedKeys << "," << *iter;
558             ++nPressedKeys;
559         }
560     }
561     return sPressedKeys.str();
562 }
563 
GetForegroundPids() const564 std::set<int32_t> KeyShortcutManager::GetForegroundPids() const
565 {
566     std::vector<AppExecFwk::AppStateData> foregroundApps = APP_OBSERVER_MGR->GetForegroundAppData();
567     std::set<int32_t> foregroundPids;
568 
569     for (auto &item : foregroundApps) {
570         foregroundPids.insert(item.pid);
571     }
572     std::set<int32_t> tForegroundPids;
573 
574     for (const auto &shortcut : shortcuts_) {
575         if (foregroundPids.find(shortcut.second.session) != foregroundPids.cend()) {
576             tForegroundPids.insert(shortcut.second.session);
577         }
578     }
579     std::ostringstream sPids;
580 
581     if (auto iter = tForegroundPids.cbegin(); iter != tForegroundPids.cend()) {
582         sPids << *iter;
583         for (++iter; iter != tForegroundPids.cend(); ++iter) {
584             sPids << "," << *iter;
585         }
586     }
587     MMI_HILOGI("Foreground pids: [%{public}s]", sPids.str().c_str());
588     return tForegroundPids;
589 }
590 
HandleKeyDown(std::shared_ptr<KeyEvent> keyEvent)591 bool KeyShortcutManager::HandleKeyDown(std::shared_ptr<KeyEvent> keyEvent)
592 {
593     bool handled = false;
594     std::set<int32_t> foregroundPids = GetForegroundPids();
595 
596     for (auto &item : shortcuts_) {
597         KeyShortcut &shortcut = item.second;
598         if (shortcut.triggerType != SHORTCUT_TRIGGER_TYPE_DOWN) {
599             continue;
600         }
601         if (!foregroundPids.empty() &&
602             (foregroundPids.find(shortcut.session) == foregroundPids.cend())) {
603             continue;
604         }
605         if (!CheckCombination(keyEvent, shortcut)) {
606             continue;
607         }
608         MMI_HILOGI("Matched shortcut[No.%{public}d]"
609             "(0x%{private}x,%{private}d,%{public}d,%{public}d,SESSION:%{public}d)",
610             item.first, shortcut.modifiers, shortcut.finalKey, shortcut.longPressTime,
611             shortcut.triggerType, shortcut.session);
612         TriggerDown(keyEvent, item.first, shortcut);
613         handled = true;
614     }
615     return handled;
616 }
617 
HandleKeyUp(std::shared_ptr<KeyEvent> keyEvent)618 bool KeyShortcutManager::HandleKeyUp(std::shared_ptr<KeyEvent> keyEvent)
619 {
620     bool handled = false;
621     std::set<int32_t> foregroundPids = GetForegroundPids();
622 
623     for (auto &item : shortcuts_) {
624         KeyShortcut &shortcut = item.second;
625         if (shortcut.triggerType != SHORTCUT_TRIGGER_TYPE_UP) {
626             continue;
627         }
628         if (!foregroundPids.empty() &&
629             (foregroundPids.find(shortcut.session) == foregroundPids.cend())) {
630             continue;
631         }
632         if (!CheckCombination(keyEvent, shortcut)) {
633             continue;
634         }
635         MMI_HILOGI("Matched shortcut(0x%{private}x,%{private}d,%{public}d,%{public}d,SESSION:%{public}d)",
636             shortcut.modifiers, shortcut.finalKey, shortcut.longPressTime, shortcut.triggerType, shortcut.session);
637         TriggerUp(keyEvent, item.first, shortcut);
638         handled = true;
639     }
640     return handled;
641 }
642 
HandleKeyCancel(std::shared_ptr<KeyEvent> keyEvent)643 bool KeyShortcutManager::HandleKeyCancel(std::shared_ptr<KeyEvent> keyEvent)
644 {
645     ResetAll();
646     return false;
647 }
648 
CheckCombination(std::shared_ptr<KeyEvent> keyEvent,const KeyShortcut & shortcut) const649 bool KeyShortcutManager::CheckCombination(std::shared_ptr<KeyEvent> keyEvent, const KeyShortcut &shortcut) const
650 {
651     return (((shortcut.finalKey == SHORTCUT_PURE_MODIFIERS) && CheckPureModifiers(keyEvent, shortcut)) ||
652             ((shortcut.finalKey == keyEvent->GetKeyCode()) && CheckModifiers(keyEvent, shortcut)));
653 }
654 
CheckPureModifiers(std::shared_ptr<KeyEvent> keyEvent,const KeyShortcut & shortcut) const655 bool KeyShortcutManager::CheckPureModifiers(std::shared_ptr<KeyEvent> keyEvent, const KeyShortcut &shortcut) const
656 {
657     auto iter = modifiers_.find(keyEvent->GetKeyCode());
658     if (iter == modifiers_.cend()) {
659         return false;
660     }
661     uint32_t modifiers = (shortcut.modifiers & ~iter->second);
662     auto pressedKeys = keyEvent->GetPressedKeys();
663 
664     for (auto keyCode : pressedKeys) {
665         if (auto iter = modifiers_.find(keyCode); iter != modifiers_.cend()) {
666             modifiers &= ~iter->second;
667         }
668     }
669     return (modifiers == 0U);
670 }
671 
CheckModifiers(std::shared_ptr<KeyEvent> keyEvent,const KeyShortcut & shortcut) const672 bool KeyShortcutManager::CheckModifiers(std::shared_ptr<KeyEvent> keyEvent, const KeyShortcut &shortcut) const
673 {
674     uint32_t modifiers = shortcut.modifiers;
675     auto pressedKeys = keyEvent->GetPressedKeys();
676 
677     for (auto keyCode : pressedKeys) {
678         if (auto iter = modifiers_.find(keyCode); iter != modifiers_.cend()) {
679             modifiers &= ~iter->second;
680         }
681     }
682     return (modifiers == 0U);
683 }
684 
TriggerDown(std::shared_ptr<KeyEvent> keyEvent,int32_t shortcutId,const KeyShortcut & shortcut)685 void KeyShortcutManager::TriggerDown(
686     std::shared_ptr<KeyEvent> keyEvent, int32_t shortcutId, const KeyShortcut &shortcut)
687 {
688     if (shortcut.longPressTime <= 0) {
689         MMI_HILOGI("Run shortcut[No.%{public}d]", shortcutId);
690         if (shortcut.callback != nullptr) {
691             shortcut.callback(keyEvent);
692         }
693     } else {
694         if (triggering_.find(shortcutId) != triggering_.cend()) {
695             MMI_HILOGI("Shortcut[No.%{public}d]"
696                 "(0x%{private}x,%{private}d,%{public}d,%{public}d,SESSION:%{public}d) is pending",
697                 shortcutId, shortcut.modifiers, shortcut.finalKey, shortcut.longPressTime,
698                 shortcut.triggerType, shortcut.session);
699             return;
700         }
701         auto timerId = TimerMgr->AddTimer(shortcut.longPressTime, REPEAT_ONCE,
702             [this, tKeyEvent = KeyEvent::Clone(keyEvent), shortcutId]() {
703                 triggering_.erase(shortcutId);
704                 RunShortcut(tKeyEvent, shortcutId);
705             });
706         if (timerId < 0) {
707             MMI_HILOGE("AddTimer fail");
708             return;
709         }
710         triggering_.emplace(shortcutId, timerId);
711     }
712 }
713 
RunShortcut(std::shared_ptr<KeyEvent> keyEvent,int32_t shortcutId)714 void KeyShortcutManager::RunShortcut(std::shared_ptr<KeyEvent> keyEvent, int32_t shortcutId)
715 {
716     if (auto iter = shortcuts_.find(shortcutId); iter != shortcuts_.end()) {
717         std::set<int32_t> foregroundPids = GetForegroundPids();
718         if (!foregroundPids.empty() &&
719             (foregroundPids.find(iter->second.session) == foregroundPids.cend())) {
720             MMI_HILOGI("Session(%{public}d) is not foreground, skip running shortcut[%{public}d]",
721                 iter->second.session, shortcutId);
722             return;
723         }
724         MMI_HILOGI("Run shortcut[No.%{public}d]", shortcutId);
725         if (iter->second.callback != nullptr) {
726             iter->second.callback(keyEvent);
727         }
728     }
729 }
730 
TriggerUp(std::shared_ptr<KeyEvent> keyEvent,int32_t shortcutId,const KeyShortcut & shortcut)731 void KeyShortcutManager::TriggerUp(
732     std::shared_ptr<KeyEvent> keyEvent, int32_t shortcutId, const KeyShortcut &shortcut)
733 {
734     if (shortcut.longPressTime > 0) {
735         std::optional<KeyEvent::KeyItem> keyItem = keyEvent->GetKeyItem();
736         if (!keyItem) {
737             MMI_HILOGE("Corrupted key event");
738             return;
739         }
740         auto upTime = keyEvent->GetActionTime();
741         auto downTime = keyItem->GetDownTime();
742         if (upTime - downTime < MS2US(shortcut.longPressTime)) {
743             MMI_HILOGE("upTime - downTime < duration");
744             return;
745         }
746     }
747     if (shortcut.callback != nullptr) {
748         shortcut.callback(keyEvent);
749     }
750 }
751 
ResetAll()752 void KeyShortcutManager::ResetAll()
753 {
754     for (auto &item : triggering_) {
755         TimerMgr->RemoveTimer(item.second);
756     }
757     triggering_.clear();
758 }
759 
ResetCheckState()760 void KeyShortcutManager::ResetCheckState()
761 {
762     isCheckShortcut_ = true;
763 }
764 
765 static const std::vector<int32_t> specialKeyCodes = {
766     KeyEvent::KEYCODE_ALT_LEFT,
767     KeyEvent::KEYCODE_ALT_RIGHT,
768     KeyEvent::KEYCODE_TAB,
769     KeyEvent::KEYCODE_VOLUME_UP,
770     KeyEvent::KEYCODE_VOLUME_DOWN,
771     KeyEvent::KEYCODE_POWER,
772     KeyEvent::KEYCODE_HEADSETHOOK,
773     KeyEvent::KEYCODE_HOME,
774     KeyEvent::KEYCODE_MENU,
775     KeyEvent::KEYCODE_VOICE_ASSISTANT,
776     KeyEvent::KEYCODE_KEY_PEN_AIR_MOUSE,
777     KeyEvent::KEYCODE_KEY_PEN_LIGHT_PINCH,
778     KeyEvent::KEYCODE_KEY_PEN_AI,
779     KeyEvent::KEYCODE_KEY_PEN_END_CLICK,
780     KeyEvent::KEYCODE_KEY_PEN_END_DOUBLE_CLICK,
781     KeyEvent::KEYCODE_KEY_PEN_MODE_SWITCH,
782     KeyEvent::KEYCODE_REMOTE_POWER
783 };
784 
IsCheckUpShortcut(const std::shared_ptr<KeyEvent> & keyEvent)785 bool KeyShortcutManager::IsCheckUpShortcut(const std::shared_ptr<KeyEvent> &keyEvent)
786 {
787     auto it = std::find(specialKeyCodes.begin(), specialKeyCodes.end(), keyEvent->GetKeyCode());
788     if (it != specialKeyCodes.end() && keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_UP) {
789         return true;
790     }
791     if (isCheckShortcut_) {
792         isCheckShortcut_ = false;
793         return true;
794     }
795     return false;
796 }
797 
HaveShortcutConsumed(std::shared_ptr<KeyEvent> keyEvent)798 bool KeyShortcutManager::HaveShortcutConsumed(std::shared_ptr<KeyEvent> keyEvent)
799 {
800     auto it = std::find(specialKeyCodes.begin(), specialKeyCodes.end(), keyEvent->GetKeyCode());
801     if (it != specialKeyCodes.end() && keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_UP) {
802         return false;
803     }
804     return (shortcutConsumed_.find(keyEvent->GetKeyCode()) != shortcutConsumed_.cend());
805 }
806 
UpdateShortcutConsumed(std::shared_ptr<KeyEvent> keyEvent)807 void KeyShortcutManager::UpdateShortcutConsumed(std::shared_ptr<KeyEvent> keyEvent)
808 {
809     if (keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_UP) {
810         shortcutConsumed_.erase(keyEvent->GetKeyCode());
811     }
812 }
813 
MarkShortcutConsumed(const ShortcutKey & shortcut)814 void KeyShortcutManager::MarkShortcutConsumed(const ShortcutKey &shortcut)
815 {
816     std::for_each(shortcut.preKeys.cbegin(), shortcut.preKeys.cend(),
817         [this](auto keyCode) {
818             shortcutConsumed_.emplace(keyCode);
819         });
820     if (shortcut.triggerType == KeyEvent::KEY_ACTION_DOWN) {
821         shortcutConsumed_.emplace(shortcut.finalKey);
822     }
823     isCheckShortcut_ = false;
824 }
825 
MarkShortcutConsumed(const KeyOption & shortcut)826 void KeyShortcutManager::MarkShortcutConsumed(const KeyOption &shortcut)
827 {
828     auto preKeys = shortcut.GetPreKeys();
829 
830     std::for_each(preKeys.cbegin(), preKeys.cend(),
831         [this](auto keyCode) {
832             shortcutConsumed_.emplace(keyCode);
833         });
834     if (shortcut.IsFinalKeyDown()) {
835         shortcutConsumed_.emplace(shortcut.GetFinalKey());
836     }
837     shortcutConsumed_.erase(KeyEvent::KEYCODE_VOLUME_UP);
838     shortcutConsumed_.erase(KeyEvent::KEYCODE_VOLUME_DOWN);
839     shortcutConsumed_.erase(KeyEvent::KEYCODE_POWER);
840     isCheckShortcut_ = false;
841 }
842 
ResetTriggering(std::shared_ptr<KeyEvent> keyEvent)843 void KeyShortcutManager::ResetTriggering(std::shared_ptr<KeyEvent> keyEvent)
844 {
845     if (keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_DOWN) {
846         for (auto iter = triggering_.cbegin(); iter != triggering_.cend();) {
847             auto shortcutIter = shortcuts_.find(iter->first);
848             if ((shortcutIter != shortcuts_.cend()) &&
849                 WillResetOnKeyDown(keyEvent->GetKeyCode(), shortcutIter->second)) {
850                 MMI_HILOGI("Reset triggering shortcut[%{public}d]", iter->first);
851                 TimerMgr->RemoveTimer(iter->second);
852                 iter = triggering_.erase(iter);
853             } else {
854                 ++iter;
855             }
856         }
857     } else {
858         for (auto iter = triggering_.cbegin(); iter != triggering_.cend();) {
859             auto shortcutIter = shortcuts_.find(iter->first);
860             if ((shortcutIter != shortcuts_.cend()) &&
861                 WillResetOnKeyUp(keyEvent->GetKeyCode(), shortcutIter->second)) {
862                 MMI_HILOGI("Reset triggering shortcut[%{public}d]", iter->first);
863                 TimerMgr->RemoveTimer(iter->second);
864                 iter = triggering_.erase(iter);
865             } else {
866                 ++iter;
867             }
868         }
869     }
870 }
871 
WillResetOnKeyDown(int32_t keyCode,const KeyShortcut & shortcut) const872 bool KeyShortcutManager::WillResetOnKeyDown(int32_t keyCode, const KeyShortcut &shortcut) const
873 {
874     if (keyCode == shortcut.finalKey) {
875         return false;
876     }
877     auto modIter = modifiers_.find(keyCode);
878     return ((modIter == modifiers_.cend()) || ((modIter->second & shortcut.modifiers) == 0U));
879 }
880 
WillResetOnKeyUp(int32_t keyCode,const KeyShortcut & shortcut) const881 bool KeyShortcutManager::WillResetOnKeyUp(int32_t keyCode, const KeyShortcut &shortcut) const
882 {
883     if (keyCode == shortcut.finalKey) {
884         return true;
885     }
886     auto modIter = modifiers_.find(keyCode);
887     return ((modIter != modifiers_.cend()) && ((modIter->second & shortcut.modifiers) != 0U));
888 }
889 
ResetTriggering(int32_t shortcutId)890 void KeyShortcutManager::ResetTriggering(int32_t shortcutId)
891 {
892     if (auto iter = triggering_.find(shortcutId); iter != triggering_.cend()) {
893         TimerMgr->RemoveTimer(iter->second);
894         triggering_.erase(iter);
895     }
896 }
897 
GetAllSystemHotkeys(std::vector<std::unique_ptr<KeyOption>> & sysKeys)898 int32_t KeyShortcutManager::GetAllSystemHotkeys(std::vector<std::unique_ptr<KeyOption>> &sysKeys)
899 {
900     CALL_DEBUG_ENTER;
901     for (const auto &item : hotkeys_) {
902         std::unique_ptr<KeyOption> keyOptionPtr = std::make_unique<KeyOption>();
903         keyOptionPtr->SetPreKeys(item.preKeys);
904         keyOptionPtr->SetFinalKey(item.finalKey);
905         sysKeys.push_back(std::move(keyOptionPtr));
906     }
907     return RET_OK;
908 }
909 
LoadHotkeys()910 void KeyShortcutManager::LoadHotkeys()
911 {
912     char cfgName[] { "etc/multimodalinput/system_hotkeys_config.json" };
913     char buf[MAX_PATH_LEN] {};
914     char *cfgPath = ::GetOneCfgFile(cfgName, buf, sizeof(buf));
915 
916     if ((cfgPath == nullptr) || (cfgPath[0] == '\0') || (strlen(cfgPath) > MAX_PATH_LEN)) {
917         MMI_HILOGE("No '%{private}s' was found", cfgPath);
918         return;
919     }
920     MMI_HILOGI("Config of hotkey:%{private}s", cfgPath);
921     ReadHotkeys(std::string(cfgPath));
922 }
923 
ReadHotkeys(const std::string & cfgPath)924 void KeyShortcutManager::ReadHotkeys(const std::string &cfgPath)
925 {
926     std::string cfg = ReadJsonFile(cfgPath);
927     JsonParser parser(cfg.c_str());
928     if (!cJSON_IsObject(parser.Get())) {
929         MMI_HILOGE("Not json format");
930         return;
931     }
932     cJSON* jsonHotkeys = cJSON_GetObjectItemCaseSensitive(parser.Get(), "Hotkeys");
933     if (!jsonHotkeys) {
934         MMI_HILOGE("JsonHotkeys is nullptr");
935         return;
936     }
937     if (!cJSON_IsArray(jsonHotkeys)) {
938         MMI_HILOGE("JsonHotkeys is not array");
939         return;
940     }
941     int32_t nSysKeys = cJSON_GetArraySize(jsonHotkeys);
942     for (int32_t index = 0; index < nSysKeys; ++index) {
943         cJSON *jsonHotkey = cJSON_GetArrayItem(jsonHotkeys, index);
944         if (!jsonHotkey) {
945             MMI_HILOGE("JsonHotkey is nullptr");
946             return;
947         }
948         if (ReadHotkey(jsonHotkey) != RET_OK) {
949             MMI_HILOGE("Read hotkey failed");
950             return;
951         }
952     }
953 }
954 
ReadHotkey(cJSON * jsonHotkey)955 int32_t KeyShortcutManager::ReadHotkey(cJSON *jsonHotkey)
956 {
957     if (!cJSON_IsObject(jsonHotkey)) {
958         MMI_HILOGE("Not json object");
959         return RET_ERR;
960     }
961     cJSON *jsonPreKeys = cJSON_GetObjectItem(jsonHotkey, "preKeys");
962     if (!jsonPreKeys) {
963         MMI_HILOGE("JsonPreKeys is nullptr");
964         return RET_ERR;
965     }
966     if (!cJSON_IsArray(jsonPreKeys)) {
967         MMI_HILOGE("Expect array for PreKeys");
968         return RET_ERR;
969     }
970     std::set<int32_t> preKeys;
971     int32_t nPreKeys = cJSON_GetArraySize(jsonPreKeys);
972 
973     for (int32_t index = 0; index < nPreKeys; ++index) {
974         cJSON *jsonPreKey = cJSON_GetArrayItem(jsonPreKeys, index);
975         if (!cJSON_IsNumber(jsonPreKey)) {
976             MMI_HILOGE("Expect number for PreKey");
977             return RET_ERR;
978         }
979         preKeys.insert(static_cast<int32_t>(cJSON_GetNumberValue(jsonPreKey)));
980     }
981     cJSON *jsonFinalKey = cJSON_GetObjectItem(jsonHotkey, "finalKey");
982     if (!jsonFinalKey) {
983         MMI_HILOGE("JsonFinalKey is nullptr");
984         return RET_ERR;
985     }
986     if (!cJSON_IsNumber(jsonFinalKey)) {
987         MMI_HILOGE("Expect number for FinalKey");
988         return RET_ERR;
989     }
990     int32_t finalKey = static_cast<int32_t>(cJSON_GetNumberValue(jsonFinalKey));
991     return AddHotkey(preKeys, finalKey);
992 }
993 
AddHotkey(const std::set<int32_t> & preKeys,int32_t finalKey)994 int32_t KeyShortcutManager::AddHotkey(const std::set<int32_t> &preKeys, int32_t finalKey)
995 {
996     SystemHotkey hotkey {
997         .preKeys = preKeys,
998         .finalKey = finalKey,
999     };
1000     for (const auto &item : hotkey.preKeys) {
1001         if ((modifiers_.find(item) == modifiers_.cend()) && (item != KeyEvent::KEYCODE_SYSRQ)) {
1002             MMI_HILOGE("Not hotkeys");
1003             return RET_ERR;
1004         }
1005     }
1006 
1007     if (IsModifier(hotkey.finalKey)) {
1008         MMI_HILOGE("FinalKey is modifier");
1009         return RET_ERR;
1010     }
1011     hotkeys_.emplace(hotkey);
1012     return RET_OK;
1013 }
1014 } // namespace MMI
1015 } // namespace OHOS
1016