/*---------------------------------------------------------------------------- * Copyright (c) TJD Technologies Co., Ltd. 2024. All rights reserved. * * Description: TjdUiWatchFaceCtrl.cpp * * Author: liuguanwu * * Create: 2024-10 *--------------------------------------------------------------------------*/ #include "fs_user_common.h" #include "sql_setting.h" #include "sys_config.h" #include "sys_typedef.h" #include #include #include #include #include #if ENABLE_MEMORY_CHECK #include "gfx_utils/mem_check.h" #endif #include "DialBinParser.h" #include "DialViewGroup.h" #include "TjdUiAppMainView.h" #include "TjdUiImageIds.h" #include "TjdUiWFPageCustom.h" #include "TjdUiWFPageFootball.h" #include "TjdUiWFPageFootballOne.h" #include "TjdUiWatchFaceCtrl.h" #include "cJSON.h" #include "graphic_service.h" #include "power_display_service.h" using namespace OHOS; namespace TJD { #define ENABLE_PRINT_INFO 1 #if ENABLE_PRINT_INFO #define static_print_info(...) sys_ui_log_i(__VA_ARGS__) //一般信息打印宏控制 #define static_print_warn(...) sys_ui_log_w(__VA_ARGS__) //警告信息打印一般常开 #define static_print_error(...) sys_ui_log_e(__VA_ARGS__) //错误信息打印一般常开 #define static_print_debug(...) sys_ui_log_d(__VA_ARGS__) #else #define static_print_info(...) #define static_print_warn(...) #define static_print_error(...) #define static_print_debug(...) #endif #define WF_NUMBER_MAX (20) //#define TJD_FS_DIR_WF "img_main_wf.bin" #define WF_BIN_PATH TJD_FS_DIR_WF struct WFIDCtrl { uint32_t CurId; uint32_t CurNumber; uint32_t WFIDList[WF_NUMBER_MAX]; }; static struct WFIDCtrl g_WFInfo = {}; struct WFViewMapper { uint32_t WFId; std::function func; std::string PreviewImgFullPath; uint32_t PreviewImgID; std::string WFName; }; /********************************************************************************************************************** * PUBLIC FUNCTIONS */ static TjdUiWfBase *InitNativeDial0(uint32_t id) { static_print_debug("InitNativeDial0"); TjdUiWfBase *cardPage = new TjdUiWFPageCustom(); if (cardPage == nullptr) { static_print_error("MainClockView new fail"); return nullptr; } return cardPage; } // static TjdUiWfBase *InitNativeDial1(uint32_t id) // { // static_print_debug("InitNativeDial1"); // TjdUiWfBase *cardPage = new TjdUiWFPageFootball(); // if (cardPage == nullptr) { // static_print_error("MainClockView new fail"); // return nullptr; // } // return cardPage; // } static TjdUiWfBase *InitNativeDial2(uint32_t id) { static_print_debug("InitNativeDial2"); TjdUiWfBase *cardPage = new TjdUiWFPageFootballOne(); if (cardPage == nullptr) { static_print_error("MainClockView new fail"); return nullptr; } return cardPage; } static const WFViewMapper g_wfViewNativeMapper_[] = { {0, &InitNativeDial0, "/user/tjd_res/img_wf_preview.bin", IMG_WF_PREVIEW_DEF_PREVIEW, "视频表盘"}, //{1, &InitNativeDial1, "/user/tjd_res/img_football.bin", IMG_FOOTBALL_PREVIEW}, {2, &InitNativeDial2, "/user/tjd_res/img_wf_preview.bin", IMG_WF_PREVIEW_FOOTBALL_PREVIEW, "足球表盘"}}; static TjdUiWfBase *InitNativeDial(uint32_t id) { TjdUiWfBase *cardPage{nullptr}; uint32_t count = sizeof(g_wfViewNativeMapper_) / sizeof(g_wfViewNativeMapper_[0]); for (uint32_t i = 0; i < count; i++) { static_print_debug("InitNativeDial for[%d][%d]]", i, id); if (g_wfViewNativeMapper_[i].WFId == id) { cardPage = g_wfViewNativeMapper_[i].func(id); return cardPage; } } return cardPage; } static TjdUiWfBase *InitClondDial(uint32_t id) { if (TjdUiWfGeTypebyID(id) != WF_FORMAT_CLOUD) { return nullptr; } std::string fullPath = ""; TjdUiWfGetFullPathbyID(id, &fullPath); FILE *fp = fopen(fullPath.c_str(), "rb"); if (!fp) { static_print_error("InitClondDial fopen error:[%s]", fullPath.c_str()); return nullptr; } fclose(fp); DialViewGroup *dial = new DialViewGroup(); TjdUiWfBase *basedial = new TjdUiWfBase(dial); dial->SetViewId("wf_main_baseCont_"); dial->SetDial(fullPath); dial->PreLoad(); dial->OnActive(); return basedial; } UICardPage *TjdUiWfCtrlInit(void) { uint32_t cur_id = sql_setting_get_watch_face_id(); static_print_debug("TjdUiWfCtrlInit:cur_id=%d", cur_id); TjdUiWfBase *cardPage{nullptr}; TjdUiWfSetCurID(cur_id); EnumWfFormat type = TjdUiWfGeTypebyID(cur_id); if (type == WF_FORMAT_NATIVE) { cardPage = InitNativeDial(cur_id); } else if (type == WF_FORMAT_CLOUD) { cardPage = InitClondDial(cur_id); } //使用默认表盘0 if (cardPage == nullptr) { cardPage = InitNativeDial(0); TjdUiWfSetCurID(0); sql_setting_set_watch_face_id(0); } TjdUiAppMainView::GetInstance()->GetWfCommon()->LoadWFAfter(cardPage); return dynamic_cast(cardPage); } void TjdUiWfSetCurID(uint32_t id) { g_WFInfo.CurNumber = id; } uint32_t TjdUiWfGetNumberMax(void) { return WF_NUMBER_MAX; } uint32_t TjdUiWfGetCurID(void) { return g_WFInfo.CurNumber; } EnumWfFormat TjdUiWfGeTypebyID(uint32_t id) //表盘格式 { uint32_t count = sizeof(g_wfViewNativeMapper_) / sizeof(g_wfViewNativeMapper_[0]); for (uint32_t i = 0; i < count; i++) { if (g_wfViewNativeMapper_[i].WFId == id) { return WF_FORMAT_NATIVE; } } return WF_FORMAT_CLOUD; if (id > WF_FORMAT_JS_MAX_ID) { return WF_FORMAT_CLOUD; } else if (id > WF_FORMAT_NATIVE_MAX_ID) { return WF_FORMAT_JS; } else { return WF_FORMAT_NATIVE; } } void TjdUiWfGetNamebyID(uint32_t id, std::string *StrName) //表盘名称 { StrName->clear(); StrName->append(std::to_string(id)); static_print_debug("TjdUiWfGetNamebyID[%s]", StrName->c_str()); } void TjdUiWfGetFullPathbyID(uint32_t id, std::string *StrPath) //表盘路径,仅云表盘使用 { StrPath->clear(); if (TjdUiWfGeTypebyID(id) == WF_FORMAT_CLOUD) { StrPath->append("/user/tjd_wf/hi_" + std::to_string(id) + ".bwf"); } } void TjdUiWfIDListClear(void) { for (uint32_t i = 0; i < WF_NUMBER_MAX; i++) { g_WFInfo.WFIDList[i] = 0; } g_WFInfo.CurNumber = 0; } void TjdUiWfIDListPush(uint32_t id) { g_WFInfo.WFIDList[g_WFInfo.CurNumber++] = id; } uint32_t *TjdUiWfGetIDList(uint32_t *len) { uint32_t TempID = 0; TjdUiWfIDListClear(); //本地表盘 uint32_t count = sizeof(g_wfViewNativeMapper_) / sizeof(g_wfViewNativeMapper_[0]); for (uint32_t i = 0; i < count; i++) { TjdUiWfIDListPush(g_wfViewNativeMapper_[i].WFId); static_print_debug("FindWfFile number: %d", g_wfViewNativeMapper_[i].WFId); } // 云表盘:打开目录 struct dirent *direntp; DIR *dirp = opendir(TJD_FS_DIR_WF); // 遍历文件 if (dirp != nullptr) { std::string DirPrePath(TJD_FS_DIR_WF); while ((direntp = readdir(dirp)) != nullptr) { std::string filename(direntp->d_name); if (filename.find(".bwf") != std::string::npos && filename.find("hi_") != std::string::npos) { std::string number; std::size_t pos1 = filename.find_last_of('_'); if (pos1 != std::string::npos) { // 查找 .bin 的位置 std::size_t pos2 = filename.find(".bwf", pos1); if (pos2 != std::string::npos) { // 提取下划线和 .bin 之间的子字符串 number = filename.substr(pos1 + 1, pos2 - pos1 - 1); static_print_debug("FindWfFile number: %s", number.c_str()); } } TempID = std::stoi(number); if (TempID > WF_FORMAT_JS_MAX_ID) { TjdUiWfIDListPush(TempID); } } } } // 关闭目录 closedir(dirp); *len = g_WFInfo.CurNumber; return &g_WFInfo.WFIDList[0]; } bool TjdUiGetWfSelectInfoByConfig(uint32_t id, WfSelectInfo *info) { //本地表盘json 分析 bool json_flag = false; std::string fullPath = "/user/tjd_wf/wf_config_0.json"; std::ifstream file(fullPath); if (file.is_open()) { // 使用 stringstream 读取文件内容 std::stringstream buffer; buffer << file.rdbuf(); // 将文件内容存储到字符串中 std::string fileContent = buffer.str(); static_print_debug("TjdUiGetWfSelectInfoDefault::%s file content:%s", __func__, fileContent.c_str()); cJSON *cjson_root = cJSON_Parse(fileContent.c_str()); if (cjson_root == NULL) { static_print_error("parse fail."); file.close(); return json_flag; } cJSON *cjsonType = cJSON_GetObjectItem(cjson_root, "wf_type"); cJSON *cjsonWfPath = cJSON_GetObjectItem(cjson_root, "wf_preview"); static_print_debug("TjdUiGetWfSelectInfoDefault:: wf_type:%d, wf_preview:%s", cjsonType->valueint, cJSON_GetStringValue(cjsonWfPath)); if (strlen(cJSON_GetStringValue(cjsonWfPath))) { info->wfId = id; switch (cjsonType->valueint) { case 2: info->name = "视频表盘"; break; default: info->name = "自定义表盘"; break; } info->PreviewImgFileOffset = -1; //单独文件标识 info->PreviewImgFullPath.clear(); info->PreviewImgFullPath.append(std::string(cJSON_GetStringValue(cjsonWfPath))); info->PreviewImgId = 0; json_flag = true; #if 0 std::size_t pos = info.path.find_last_of('/'); std::string filename; if (pos != std::string::npos) { info.name = info.path.substr(pos + 1); // std::size_t pos = info.name.find(".bin"); // if (pos != std::string::npos) { // info.name = info.name.substr(0, pos); // } } else { info.name = "wf_0.bwf"; } #endif // printf("TjdUiGetWfSelectInfoDefault::FindWfFile: %s", info->name.c_str()); } else { static_print_debug("TjdUiGetWfSelectInfoDefault:: fail:strlen:%d", strlen(cJSON_GetStringValue(cjsonWfPath))); } cJSON_Delete(cjson_root); } // 关闭文件 file.close(); return json_flag; } bool TjdUiWfGetSelectInfobyID(uint32_t id, WfSelectInfo *info) { static_print_debug("TjdUiGetWfSelectInfo: %d[%p]", id, info); if (id == 0) { if (TjdUiGetWfSelectInfoByConfig(id, info)) { return true; } } EnumWfFormat wfType = TjdUiWfGeTypebyID(id); info->wfId = id; if (wfType == WF_FORMAT_CLOUD) { TjdUiWfGetFullPathbyID(id, &info->PreviewImgFullPath); FILE *fp = fopen(info->PreviewImgFullPath.c_str(), "rb"); DialPreviewInfo preInfo{}; bool ret = DialBinParserManager::GetInstance()->GetDialPreviewInfo(fp, &preInfo); fclose(fp); info->name = preInfo.dialName; info->PreviewImgFileOffset = preInfo.offset; info->PreviewImgId = preInfo.imgId; return true; } if (wfType == WF_FORMAT_NATIVE) { uint32_t count = sizeof(g_wfViewNativeMapper_) / sizeof(g_wfViewNativeMapper_[0]); for (uint32_t i = 0; i <= count; i++) { if (g_wfViewNativeMapper_[i].WFId == id) { info->PreviewImgFileOffset = 0; info->PreviewImgFullPath = g_wfViewNativeMapper_[i].PreviewImgFullPath; info->PreviewImgId = g_wfViewNativeMapper_[i].PreviewImgID; info->name = g_wfViewNativeMapper_[i].WFName; return true; } } } return false; } bool TjdUiWfGeUninstallbyID(uint32_t id) { uint32_t count = sizeof(g_wfViewNativeMapper_) / sizeof(g_wfViewNativeMapper_[0]); for (uint32_t i = 0; i < count; i++) { if (g_wfViewNativeMapper_[i].WFId == id) { return false; } } return true; } #define LOCAL_WF_ID_1 50117 bool TjdUiWfIsLocalID(uint32_t id) { const int offset = id - LOCAL_WF_ID_1; if (offset < 0 || offset > 8) { return 0; } const unsigned int mask = 0x1F3; return (mask >> offset) & 1; } void TjdUIWfRename(std::string fullPath) { static_print_debug("TjdUIWfRename: %s", fullPath.c_str()); size_t lastDotPos = fullPath.find_last_of('.'); std::string newPath = fullPath.substr(0, lastDotPos) + ".bak"; if (access(newPath.c_str(), F_OK) == 0) { tjd_fs_api_unlink(fullPath.c_str()); } else { rename(fullPath.c_str(), newPath.c_str()); } } void TjdUiWfRecovery(void) { static_print_debug("TjdUiWfRecovery:"); // 云表盘:打开目录 uint32_t TempID = 0; struct dirent *direntp; DIR *dirp = opendir(TJD_FS_DIR_WF); // 遍历文件 if (dirp != nullptr) { std::string DirPrePath(TJD_FS_DIR_WF); while ((direntp = readdir(dirp)) != nullptr) { std::string filename(direntp->d_name); if (filename.find("hi_") != std::string::npos) { if (filename.find(".bak") != std::string::npos) { std::size_t pos = filename.find_last_of('.'); if (pos != std::string::npos) { std::string newName = filename.substr(0, pos) + ".bwf"; std::string newPath = DirPrePath + "/" + newName; std::string oldPath = DirPrePath + "/" + filename; if (access(newPath.c_str(), F_OK) == 0) { //先删除,再使用备份文件 tjd_fs_api_unlink(newPath.c_str()); } rename(oldPath.c_str(), newPath.c_str()); } } else if (filename.find(".bwf") != std::string::npos) { std::string number; std::size_t pos1 = filename.find_last_of('_'); if (pos1 != std::string::npos) { std::size_t pos2 = filename.find(".bwf", pos1); if (pos2 != std::string::npos) { // 提取下划线和 .bwf 之间的子字符串 number = filename.substr(pos1 + 1, pos2 - pos1 - 1); static_print_debug("FindWfFile number: %s", number.c_str()); } } TempID = std::stoi(number); std::string Path = DirPrePath + "/" + filename; if (TjdUiWfIsLocalID(TempID)) { std::size_t pos = filename.find_last_of('.'); if (pos != std::string::npos) { std::string bakName = filename.substr(0, pos) + ".bak"; std::string bakpath = DirPrePath + "/" + bakName; if (access(bakpath.c_str(), F_OK) == 0) { tjd_fs_api_unlink(Path.c_str()); } } } else { tjd_fs_api_unlink(Path.c_str()); } } } } } // 关闭目录 closedir(dirp); } bool TjdUiWfDeletebyID(uint32_t id) { std::string fullPath{nullptr}; TjdUiWfGetFullPathbyID(id, &fullPath); if (fullPath.size()) { if (TjdUiWfIsLocalID(id)) { TjdUIWfRename(fullPath); } else { tjd_fs_api_unlink(fullPath.c_str()); // int unlink(FAR const char *pathname) } } return true; } bool TjdUiWfInstallBeforNotify(uint32_t id) { return true; } static void TjdUiWfInstallAfterNotifyRun(void) { static_print_debug("TjdUiWfInstallAfterNotifyRun: "); if (power_display_svr_get_api()->get_screen_state() != SCREEN_ON) { power_display_svr_get_api()->turn_on_screen(); } power_display_svr_get_api()->set_auto_timeout_function(true); uint16_t current_slice_id = OHOS::NativeAbility::GetInstance().GetCurSliceId(); if (current_slice_id != TJD_APP_VIEW_MAIN) { // 主表盘 OHOS::NativeAbility::GetInstance().ChangeSlice(TJD_APP_VIEW_MAIN); } else { // 当前页面为主表盘的其他页面时,切换回主表盘页面 // TJD::TjdUiAppMainView::GetInstance()->ResetView(); // OHOS::NativeAbility::GetInstance().StopAbility(); // OHOS::NativeAbility::GetInstance().StartAbility(); OHOS::NativeAbility::GetInstance().ChangeSlice(TJD_APP_VIEW_OPEN_LOGO); OHOS::NativeAbility::GetInstance().ChangeSlice(TJD_APP_VIEW_MAIN); } } bool TjdUiWfInstallAfterNotify(uint32_t id) { static_print_debug("TjdUiWfInstallAfterNotify: %d", id); sql_setting_set_watch_face_id(id); GraphicService::GetInstance()->PostGraphicEvent([] { TjdUiWfInstallAfterNotifyRun(); }); return true; } bool TjdUiWfUninstallBeforNotify(uint32_t id) { return true; } static void TjdUiWfUninstallAfterNotifyRun(void) { static_print_debug("TjdUiWfUninstallAfterNotifyRun:"); uint16_t current_slice_id = OHOS::NativeAbility::GetInstance().GetCurSliceId(); if (current_slice_id == TJD_APP_VIEW_MAIN) { // 主表盘 if (power_display_svr_get_api()->get_screen_state() != SCREEN_ON) { power_display_svr_get_api()->turn_on_screen(); } power_display_svr_get_api()->set_auto_timeout_function(true); OHOS::NativeAbility::GetInstance().ChangeSlice(TJD_APP_VIEW_OPEN_LOGO); OHOS::NativeAbility::GetInstance().ChangeSlice(TJD_APP_VIEW_MAIN); } } bool TjdUiWfUninstallAfterNotify(uint32_t id) { static_print_debug("TjdUiWfUninstallAfterNotify: %d", id); if (id == 0) { return true; } if (id == sql_setting_get_watch_face_id()) { sql_setting_set_watch_face_id(0); GraphicService::GetInstance()->PostGraphicEvent([] { TjdUiWfUninstallAfterNotifyRun(); }); } return true; } } // namespace TJD