mcu_hi3321_watch/tjd/ui/watch_face/TjdUiWatchFaceCtrl.cpp
2025-05-31 10:45:15 +08:00

538 lines
18 KiB
C++

/*----------------------------------------------------------------------------
* 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 <dirent.h>
#include <fstream>
#include <functional>
#include <iostream>
#include <sstream>
#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<TjdUiWfBase *(uint32_t id)> 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<UICardPage *>(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