1 /*
2 * Copyright (C) 2023 Huawei Technologies Co., Ltd.
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12
13 #include "tui_event.h"
14 #include <cctype>
15 #include <cstdint>
16 #include <cstring>
17 #include <ctime>
18 #include <cstdio>
19 #include <memory>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <securec.h>
23 #include <securectype.h>
24 #include <sys/ioctl.h>
25
26 #include "tee_log.h"
27 #include "tc_ns_client.h"
28 #include "power_mgr_client.h"
29 #include "display_info.h"
30 #include "cutout_info.h"
31 #include "call_manager_client.h"
32 #include "system_ability_definition.h"
33 #include "iservice_registry.h"
34 #include "tee_file.h"
35 #include "parameters.h"
36 #ifdef SCENE_BOARD_ENABLE
37 #include "display_manager_lite.h"
38 #include "display_lite.h"
39 #else
40 #include "display_manager.h"
41 #include "display.h"
42 #endif
43
44 #ifdef LOG_TAG
45 #undef LOG_TAG
46 #endif
47 #define LOG_TAG "tee_tui_daemon"
48
49 using namespace std;
50 using namespace OHOS::PowerMgr;
51 using namespace OHOS::Rosen;
52 using namespace OHOS::Telephony;
53 using namespace OHOS::system;
54
55 TUIEvent *TUIEvent::tuiInstance = nullptr;
56
57 static const uint32_t NOTCH_SIZE_MAX = 200;
58 static const double INCH_CM_FACTOR = 2.54;
59 static const uint32_t TUI_POLL_CANCEL = 7;
60 static const uint32_t TUI_POLL_NOTCH = 24;
61 static const uint32_t TUI_POLL_FOLD = 26;
62 static const uint32_t TUI_NEED_ROTATE = 256;
63
64 static const uint8_t TTF_HASH_SIZE = 32;
65 static const uint8_t TTF_STRING_SIZE = 64;
66 static const uint8_t HEX_BASE = 16;
67 static const uint8_t ASCII_DIGIT_GAP = 10;
68 static uint8_t g_ttfHash[TTF_HASH_SIZE];
69
70 static char g_hashVal[TTF_STRING_SIZE + 1] = {0};
71 static uint32_t g_hashLen = 0;
72 static bool g_tuiSendHashSuccess = false;
73 static bool g_tuiDisplayListenerRegisted = false;
74 static bool g_tuiCallBackRegisted = false;
75 static const int32_t RETRY_TIMES = 20;
76 static const uint32_t RETRY_SLEEP_TIME = 2;
77 static std::unique_ptr<TUICallManagerCallback> mTUITelephonyCallBack_ = nullptr;
78 static std::shared_ptr<OHOS::Telephony::CallManagerClient> callManagerClientPtr = nullptr;
79
TUISaveTTFHash(void)80 static void TUISaveTTFHash(void)
81 {
82 #ifndef FONT_HASH_VAL
83 tlogi("tui font hash not defined\n");
84 #else
85 const char *hashStr = FONT_HASH_VAL;
86 if (hashStr == NULL) {
87 tloge("get hashstr error\n");
88 return;
89 }
90
91 g_hashLen = (uint32_t)strlen(hashStr);
92 if (g_hashLen != TTF_STRING_SIZE) {
93 tloge("ttf hash invalid\n");
94 g_hashLen = 0;
95 return;
96 }
97 if (memcpy_s(g_hashVal, TTF_STRING_SIZE, hashStr, g_hashLen) != EOK) {
98 tloge("copy hash string failed\n");
99 g_hashLen = 0;
100 return;
101 }
102 #endif
103 return;
104 }
105
Ascii2Digit(char a)106 static uint8_t Ascii2Digit(char a)
107 {
108 uint8_t hex = 0;
109
110 if ((a >= '0') && (a <= '9')) {
111 hex = a - '0';
112 } else if ((a >= 'a') && (a <= 'f')) {
113 hex = (a - 'a') + ASCII_DIGIT_GAP;
114 } else if ((a >= 'A') && (a <= 'F')) {
115 hex = (a - 'A') + ASCII_DIGIT_GAP;
116 }
117
118 return hex;
119 }
120
TUISendEventToTz(TuiParameter * tuiParam)121 static bool TUISendEventToTz(TuiParameter *tuiParam)
122 {
123 int32_t fd = tee_open(TC_NS_CLIENT_DEV_NAME, O_RDWR, 0);
124 if (fd < 0) {
125 tloge("open tzdriver fd failed\n");
126 return false;
127 }
128 tlogd("TUISendEventToTz get fd = %" PUBLIC "d\n", fd);
129
130 int32_t ret = ioctl(fd, (int)TC_NS_CLIENT_IOCTL_TUI_EVENT, tuiParam);
131 tee_close(&fd);
132 if (ret != 0) {
133 tloge("Failed to send tui event[%" PUBLIC "d] to tzdriver, ret is %" PUBLIC "d \n",
134 tuiParam->eventType, ret);
135 return false;
136 }
137 return true;
138 }
139
TUISendTTFHashToTeeos(void)140 static void TUISendTTFHashToTeeos(void)
141 {
142 uint32_t i, j;
143 TuiParameter tuiParam = {.eventType = TUI_POLL_NOTCH};
144
145 if (g_tuiSendHashSuccess) {
146 return;
147 }
148
149 if (g_hashLen != TTF_STRING_SIZE) {
150 tloge("tui font hash len invalid\n");
151 g_hashLen = 0;
152 return;
153 }
154 tlogd("tui font hash is : %" PUBLIC "s \n", g_hashVal);
155
156 for (i = 0, j = 0; g_hashLen > 0 && i < (g_hashLen - 1) && j < sizeof(g_ttfHash); j++) {
157 g_ttfHash[j] = Ascii2Digit(g_hashVal[i++]) * HEX_BASE;
158 g_ttfHash[j] += Ascii2Digit(g_hashVal[i++]);
159 }
160
161 int rc = memcpy_s(&tuiParam.value,
162 sizeof(tuiParam) - sizeof(tuiParam.eventType),
163 g_ttfHash, sizeof(g_ttfHash));
164 if (rc == EOK) {
165 if (TUISendEventToTz(&tuiParam)) {
166 g_tuiSendHashSuccess = true;
167 } else {
168 tloge("send notch msg failed\n");
169 }
170 } else {
171 tloge("memcpy tui font hash failed");
172 }
173 }
174
TUISetStatus(bool status)175 void TUIEvent::TUISetStatus(bool status)
176 {
177 mTUIStatus = status;
178 }
179
TUIGetStatus()180 bool TUIEvent::TUIGetStatus()
181 {
182 return mTUIStatus;
183 }
184
TUIGetFoldableStatus()185 bool TUIEvent::TUIGetFoldableStatus()
186 {
187 return mTUIFoldable;
188 }
189
TUIGetNotch(OHOS::sptr<CutoutInfo> cutoutInfo,uint32_t displayMode)190 static uint32_t TUIGetNotch(OHOS::sptr<CutoutInfo> cutoutInfo, uint32_t displayMode)
191 {
192 tlogi("tui get cutoutinfo--->boundingRects for notch\n");
193 std::vector<OHOS::Rosen::DMRect> boundingRects = cutoutInfo->GetBoundingRects();
194 if (boundingRects.empty()) {
195 tlogi("get boundingRects failed\n");
196 return 0;
197 }
198 for (uint32_t i = 0; i < boundingRects.size(); i++) {
199 tlogi("tui print boundingRects[%" PUBLIC "d] info: \
200 posX[%" PUBLIC "d], posY[%" PUBLIC "d], width[%" PUBLIC "d], height[%" PUBLIC "d] \n",
201 i, boundingRects[i].posX_, boundingRects[i].posY_,
202 boundingRects[i].width_, boundingRects[i].height_);
203 }
204 /* calc notch, here is px, double height of the hole */
205 uint32_t notch = boundingRects[0].height_ + boundingRects[0].height_;
206 if (notch < 0 || notch > NOTCH_SIZE_MAX) {
207 /* 200 is too large for notch, just use 0 */
208 return 0;
209 }
210 return notch;
211 }
212
TUIGetDisplayMode(uint32_t foldState)213 static uint32_t TUIGetDisplayMode(uint32_t foldState)
214 {
215 if (foldState == FOLD_STATE_EXPANDED) {
216 return DISPLAY_MODE_FULL;
217 }
218
219 #ifdef SCENE_BOARD_ENABLE
220 uint32_t displayMode = static_cast<uint32_t>(OHOS::Rosen::DisplayManagerLite::GetInstance().GetFoldDisplayMode());
221 #else
222 uint32_t displayMode = static_cast<uint32_t>(OHOS::Rosen::DisplayManager::GetInstance().GetFoldDisplayMode());
223 #endif
224 if (displayMode < DISPLAY_MODE_MAX) {
225 return displayMode;
226 }
227
228 return DISPLAY_MODE_UNKNOWN; /* default mode */
229 }
230
CheckSAStarted(int32_t targetSAId)231 bool CheckSAStarted(int32_t targetSAId)
232 {
233 OHOS::sptr<OHOS::ISystemAbilityManager> systemAbilityManager =
234 OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
235 if (!systemAbilityManager) {
236 tlogi("Failed to get system ability mgr\n");
237 return false;
238 }
239
240 OHOS::sptr<OHOS::IRemoteObject> remoteObject = systemAbilityManager->GetSystemAbility(targetSAId);
241 if (!remoteObject) {
242 tlogi("SA service [targetID = %" PUBLIC "d] is not exist\n", targetSAId);
243 return false;
244 }
245
246 tlogd("get SA service, targetID = %" PUBLIC "d\n", targetSAId);
247 return true;
248 }
249
IsDisplaySAReady()250 static bool IsDisplaySAReady()
251 {
252 int32_t retry = 0;
253 #ifdef SCENE_BOARD_ENABLE
254 while (!CheckSAStarted(OHOS::WINDOW_MANAGER_SERVICE_ID)) {
255 #else
256 while (!CheckSAStarted(OHOS::DISPLAY_MANAGER_SERVICE_SA_ID)) {
257 #endif
258 if (retry++ >= RETRY_TIMES) {
259 tlogi("can not get display service now\n");
260 return false;
261 }
262 sleep(RETRY_SLEEP_TIME);
263 }
264
265 return true;
266 }
267
268 bool TUIEvent::TUIGetPannelInfo()
269 {
270 if (!IsDisplaySAReady()) {
271 return false;
272 }
273
274 #ifdef SCENE_BOARD_ENABLE
275 auto display = OHOS::Rosen::DisplayManagerLite::GetInstance().GetDefaultDisplay();
276 #else
277 auto display = OHOS::Rosen::DisplayManager::GetInstance().GetDefaultDisplay();
278 #endif
279 if (display == nullptr) {
280 tloge("GetDefaultDisplay: failed!\n");
281 return false;
282 }
283
284 OHOS::sptr<DisplayInfo> displayInfo = display->GetDisplayInfo();
285 if (displayInfo != nullptr) {
286 tlogi("get xdpi %" PUBLIC "f, ydpi %" PUBLIC "f, displaystate %" PUBLIC "u, DPI %" PUBLIC "d \n",
287 displayInfo->GetXDpi(), displayInfo->GetYDpi(),
288 (uint32_t)displayInfo->GetDisplayState(), displayInfo->GetDpi());
289 } else {
290 tloge("get displayInfo failed\n");
291 return false;
292 }
293
294 TUIGetFoldable();
295
296 mTUIPanelInfo.width = display->GetWidth();
297 mTUIPanelInfo.height = display->GetHeight();
298
299 if (displayInfo->GetXDpi() != 0 && displayInfo->GetYDpi() != 0) {
300 mTUIPanelInfo.phyWidth = mTUIPanelInfo.width * INCH_CM_FACTOR / displayInfo->GetXDpi();
301 mTUIPanelInfo.phyHeight = mTUIPanelInfo.height * INCH_CM_FACTOR / displayInfo->GetYDpi();
302 }
303
304 OHOS::sptr<CutoutInfo> cutoutInfo = display->GetCutoutInfo();
305 if (cutoutInfo == nullptr) {
306 tloge("get cutoutinfo failed\n");
307 } else {
308 mTUIPanelInfo.notch = TUIGetNotch(cutoutInfo, mTUIPanelInfo.displayMode);
309 }
310
311 tlogi("tui panelinfo: w %" PUBLIC "d, h %" PUBLIC "d, fold %" PUBLIC "u, "
312 "displayMode %" PUBLIC "u, notch %" PUBLIC "u\n",
313 mTUIPanelInfo.width, mTUIPanelInfo.height, mTUIPanelInfo.foldState,
314 mTUIPanelInfo.displayMode, mTUIPanelInfo.notch);
315
316 return true;
317 }
318
319 void TUIEvent::TUIGetFoldable()
320 {
321 #ifdef SCENE_BOARD_ENABLE
322 mTUIFoldable = OHOS::Rosen::DisplayManagerLite::GetInstance().IsFoldable();
323 #else
324 mTUIFoldable = OHOS::Rosen::DisplayManager::GetInstance().IsFoldable();
325 #endif
326 tlogi("TuiDaemonInit mTUIFoldable %" PUBLIC "d\n", mTUIFoldable);
327 if (mTUIFoldable) {
328 tlogi("tui get fold state\n");
329 #ifdef SCENE_BOARD_ENABLE
330 mTUIPanelInfo.foldState = static_cast<uint32_t>(OHOS::Rosen::DisplayManagerLite::GetInstance().GetFoldStatus());
331 #else
332 mTUIPanelInfo.foldState = static_cast<uint32_t>(OHOS::Rosen::DisplayManager::GetInstance().GetFoldStatus());
333 #endif
334 if (mTUIPanelInfo.foldState > FOLD_STATE_HALF_FOLDED) {
335 mTUIPanelInfo.foldState = FOLD_STATE_UNKNOWN; /* default state */
336 }
337 } else {
338 mTUIPanelInfo.foldState = FOLD_STATE_UNKNOWN;
339 }
340
341 mTUIPanelInfo.displayMode = TUIGetDisplayMode(mTUIPanelInfo.foldState);
342
343 std::string buildProduct = OHOS::system::GetParameter("const.build.product", "0");
344 if (buildProduct == "DEL") {
345 mTUIPanelInfo.displayMode = TUI_NEED_ROTATE;
346 }
347
348 if (buildProduct == "VDE") {
349 if (mTUIPanelInfo.foldState == FOLD_STATE_EXPANDED || mTUIPanelInfo.foldState == FOLD_STATE_HALF_FOLDED) {
350 mTUIPanelInfo.foldState = FOLD_STATE_UNKNOWN;
351 }
352 }
353
354 std::string foldScreenType = OHOS::system::GetParameter("const.window.foldscreen.type", "0");
355 // trifold phone
356 if (foldScreenType == "6,1,0,0") {
357 mTUIPanelInfo.foldState += TUI_NEED_ROTATE;
358 mTUIPanelInfo.displayMode = TUI_NEED_ROTATE;
359 }
360
361 if (mTUIPanelInfo.foldState == FOLD_STATE_EXPANDED || mTUIPanelInfo.foldState == FOLD_STATE_HALF_FOLDED) {
362 mTUIPanelInfo.foldState += TUI_NEED_ROTATE;
363 }
364
365 return;
366 }
367
368 void TUIEvent::TUIGetRunningLock()
369 {
370 if (mRunningLock_ == nullptr) {
371 auto &powerMgrClient = OHOS::PowerMgr::PowerMgrClient::GetInstance();
372 mRunningLock_ = powerMgrClient.CreateRunningLock("TuiDaemonRunningLock",
373 OHOS::PowerMgr::RunningLockType::RUNNINGLOCK_SCREEN);
374 }
375
376 if (mRunningLock_ != nullptr) {
377 mRunningLock_->Lock();
378 tlogi("TUI Get RunningLock\n");
379 }
380 return;
381 }
382
383 void TUIEvent::TUIReleaseRunningLock()
384 {
385 if (mRunningLock_ != nullptr) {
386 mRunningLock_->UnLock();
387 }
388
389 tlogi("TUI Release RunningLock\n");
390 return;
391 }
392
393 void TUIEvent::TuiEventInit()
394 {
395 mRunningLock_ = nullptr;
396
397 mTUIPanelInfo = { 0 };
398 mTUIStatus = false;
399 mTUIFoldable = false;
400
401 return;
402 }
403
404 bool TUIEvent::TUISendCmd(uint32_t tuiEvent)
405 {
406 TuiParameter tuiParam = {0};
407
408 if (tuiEvent == TUI_POLL_CANCEL) {
409 tuiParam.eventType = TUI_POLL_CANCEL;
410 tuiParam.value = 0;
411 } else {
412 (void)memcpy_s(&tuiParam, sizeof(tuiParam), &mTUIPanelInfo, sizeof(mTUIPanelInfo));
413 tuiParam.eventType = TUI_POLL_FOLD;
414 tuiParam.value = 0;
415 }
416
417 /* if not send hash success, try again */
418 TUISendTTFHashToTeeos();
419
420 if (TUISendEventToTz(&tuiParam) == false) {
421 tloge("tui send cmd failed\n");
422 return false;
423 }
424
425 return true;
426 }
427
428 void TUIEvent::TUIDealWithEvent(bool state)
429 {
430 if (state == false) {
431 /* not need send cmd to tzdriver */
432 TUIReleaseRunningLock();
433 TUISetStatus(false);
434 return;
435 }
436
437 TUIGetRunningLock();
438 TUIGetPannelInfo();
439 TUISetStatus(true);
440 TUISendCmd(TUI_POLL_FOLD);
441 }
442
443 void TUIDisplayListener::OnFoldStatusChanged(OHOS::Rosen::FoldStatus foldState)
444 {
445 if (foldState != OHOS::Rosen::FoldStatus::EXPAND && foldState != OHOS::Rosen::FoldStatus::FOLDED) {
446 tloge("foldState = %" PUBLIC "u invalid\n", static_cast<uint32_t>(foldState));
447 return;
448 }
449
450 /* if foldState changed, should:
451 * 1. get pannelinfo,
452 * 2. send infos to teeos,
453 * 3. cancel current running proc
454 */
455 auto tempTUIInstance = TUIEvent::GetInstance();
456 if (tempTUIInstance == nullptr) {
457 return;
458 }
459 tlogi("get TUIStatus is %" PUBLIC "x\n", tempTUIInstance->TUIGetStatus());
460 if (tempTUIInstance->TUIGetPannelInfo()) {
461 (void)tempTUIInstance->TUISendCmd(TUI_POLL_FOLD); /* EVENT TUI_POLL_FOLD */
462 }
463 if (tempTUIInstance->TUIGetStatus()) {
464 tlogi("foldState changed, need cancel TUI proc\n");
465 (void)tempTUIInstance->TUISendCmd(TUI_POLL_CANCEL); /* EVENT Exit */
466 }
467 }
468
469 int32_t TUICallManagerCallback::OnCallDetailsChange(const OHOS::Telephony::CallAttributeInfo &info)
470 {
471 tlogd("----------OnCallDetailsChange--------\n");
472 tlogd("callId: %" PUBLIC "x\n", info.callId);
473 tlogd("callType: %" PUBLIC "x\n", (int32_t)info.callType);
474 tlogd("callState: %" PUBLIC "x\n", (int32_t)info.callState);
475 tlogd("conferenceState: %" PUBLIC "x\n", (int32_t)info.conferenceState);
476 tlogd("accountNumber: %" PUBLIC "s\n", info.accountNumber);
477
478 if (info.callState == OHOS::Telephony::TelCallState::CALL_STATUS_INCOMING) {
479 auto tempTUIInstance = TUIEvent::GetInstance();
480 if (tempTUIInstance->TUIGetStatus()) {
481 tlogi("new call state CALL_STATUS_INCOMING, need send cmd to teeos to cancel TUI proc\n");
482 tempTUIInstance->TUISetStatus(false); /* change tuiStatus to false */
483 (void)tempTUIInstance->TUISendCmd(TUI_POLL_CANCEL); /* EVENT Exit */
484 }
485 tlogd("tui get new call state CALL_STATUS_INCOMING\n");
486 }
487 return 0;
488 }
489
490 void TUIDaemon::TuiRegisteCallBack()
491 {
492 if (g_tuiCallBackRegisted) {
493 return;
494 }
495
496 int32_t retry = 0;
497 while (CheckSAStarted(OHOS::TELEPHONY_CALL_MANAGER_SYS_ABILITY_ID) == false) {
498 sleep(RETRY_SLEEP_TIME);
499 retry++;
500 if (retry >= RETRY_TIMES) {
501 tlogi("can not get telephony service now\n");
502 return;
503 }
504 }
505
506 if (mTUITelephonyCallBack_ == nullptr) {
507 mTUITelephonyCallBack_ = std::make_unique<TUICallManagerCallback>();
508 if (mTUITelephonyCallBack_ == nullptr) {
509 tloge("init callback instance failed\n");
510 return;
511 }
512 }
513
514 if (callManagerClientPtr == nullptr) {
515 callManagerClientPtr = OHOS::DelayedSingleton<OHOS::Telephony::CallManagerClient>::GetInstance();
516 if (callManagerClientPtr == nullptr) {
517 tloge("get callManagerClientPtr failed\n");
518 return;
519 }
520 }
521
522 tlogi("callback get instance finish\n");
523 callManagerClientPtr->Init(OHOS::TELEPHONY_CALL_MANAGER_SYS_ABILITY_ID);
524 tlogi("callback init finish\n");
525 int32_t ret = callManagerClientPtr->RegisterCallBack(std::move(mTUITelephonyCallBack_));
526 if (ret != TEEC_SUCCESS) {
527 tloge("regist telephony callback failed ret = 0x%" PUBLIC "x\n", ret);
528 } else {
529 g_tuiCallBackRegisted = true;
530 tlogi("regist telephony callback done\n");
531 }
532 }
533
534 void TUIDaemon::TuiRegisteDisplayListener()
535 {
536 if (g_tuiDisplayListenerRegisted) {
537 return;
538 }
539
540 if (!IsDisplaySAReady()) {
541 return;
542 }
543
544 if (mTUIDisplayListener_ == nullptr) {
545 mTUIDisplayListener_ = new (std::nothrow) TUIDisplayListener();
546 if (mTUIDisplayListener_ == nullptr) {
547 tloge("create listener obj failed\n");
548 return;
549 }
550 }
551 #ifdef SCENE_BOARD_ENABLE
552 OHOS::Rosen::DisplayManagerLite &dmPtr = (OHOS::Rosen::DisplayManagerLite::GetInstance());
553 #else
554 OHOS::Rosen::DisplayManager &dmPtr = (OHOS::Rosen::DisplayManager::GetInstance());
555 #endif
556 int32_t result = (int32_t)dmPtr.RegisterFoldStatusListener(mTUIDisplayListener_);
557 if (result == TEEC_SUCCESS) {
558 g_tuiDisplayListenerRegisted = true;
559 tlogi("regist display listener done\n");
560 } else {
561 tloge("regist display listener failed\n");
562 }
563 }
564
565 void TUIDaemon::TuiDaemonInit(bool onlyConfigRes)
566 {
567 TUISaveTTFHash();
568 auto tuiEvent = TUIEvent::GetInstance();
569 tuiEvent->TuiEventInit();
570
571 if (!onlyConfigRes) {
572 TuiRegisteCallBack();
573 TuiRegisteDisplayListener();
574 }
575
576 tlogi("TUIDaemon init ok\n");
577 }
578
579 TUIDaemon::~TUIDaemon()
580 {
581 if (mTUIDisplayListener_ != nullptr) {
582 #ifdef SCENE_BOARD_ENABLE
583 OHOS::Rosen::DisplayManagerLite::GetInstance().UnregisterFoldStatusListener(mTUIDisplayListener_);
584 #else
585 OHOS::Rosen::DisplayManager::GetInstance().UnregisterFoldStatusListener(mTUIDisplayListener_);
586 #endif
587 mTUIDisplayListener_ = nullptr;
588 }
589
590 if (g_tuiCallBackRegisted) {
591 OHOS::DelayedSingleton<OHOS::Telephony::CallManagerClient>::GetInstance()->UnRegisterCallBack();
592 g_tuiCallBackRegisted = false;
593 }
594
595 tlogi("TUIDaemon released\n");
596 }
597