MeowOS for HiBy R3 Pro II — 公共发布版本(历史已重置)

• 全新单提交:清除含敏感信息的旧历史(sudo 口令、内网 IP、SSH 密钥路径、热点 SSID、设备 MAC)
• 本地开发文档/测试记录/构建脚本全部移入 gitignored 的 devdocs/ 与 scripts/build/(不入库)
• 保留:MeowOS 源码(launcher/watchdog/bootmenu/meow_svcd/SDK)、项目规范文档、mips-repo
增补组件:SDK 统一日志+通知 API、meow_svcd 服务管理器、mips-repo 软件仓库
This commit is contained in:
MeowOS Dev committed 2026-08-30 01:12:34 +08:00
commit 245bee2946
136 files changed
+32730

No files matched your search

+231
View File
@@ -0,0 +1,231 @@
/*
* meow_ui_sys.c — SDK 内置系统状态读取器 + 全局状态栏(A-0 核心)。
*
* 职责:
* 1. 状态读取器:读 /sys/class/power_supply/(电量/充电)、WiFi operstate、
* 蓝牙实上电、音量(/usr/data/meow/settings.conf 的 audio.volume,与 launcher
* 同源单点);时钟在绘制时现取 localtime。1s 轻刷,蓝牙 30s 缓存。
* 2. 全局状态栏绘制:把时钟/电量/WiFi/蓝牙/音量画进 back_buf 顶部 MUI_SBAR_H 行;
* 由渲染后端 present() 前置调用(z 最顶),非全屏可见。
* 3. 显隐/全屏状态 + 公共 API(meow_ui_set_statusbar / set_fullscreen / ...)。
*
* 注意:所有读取在事件循环主线内做(无独立线程),1s 频率同步读取 sysfs/小文件,
* 开销可忽略;蓝牙 hciconfig 为 popen(spawn) 较贵,仅 30s 刷一次并缓存。
*/
#include "meow_ui_sys.h"
#include "meow_ui_internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#define MEOW_SETTINGS_FILE "/usr/data/meow/settings.conf"
#define VOL_DEFAULT 60
/* 蓝牙 powered 缓存刷新间隔(hciconfig 较贵) */
#define BT_REFRESH_MS 30000
static meow_sys_state g_sys;
static int g_sys_inited = 0;
/* 显隐/全屏状态(公共 API 与绘制/输入共用) */
static int g_statusbar_on = 1; /* 默认显示 */
static int g_fullscreen = 0; /* 默认非全屏 */
static int g_statusbar_force = 0; /* 1s 刷新后置位,强制重画顶部条 */
static uint64_t now_ms(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint64_t)ts.tv_sec * 1000u + (uint64_t)ts.tv_nsec / 1000000u;
}
/* 读一份 sysfs/文件字符串(剥尾随换行);失败回退 "" */
static void read_str(const char *path, char *buf, size_t n)
{
buf[0] = 0;
int fd = open(path, O_RDONLY);
if (fd < 0) return;
ssize_t r = read(fd, buf, n - 1);
close(fd);
if (r <= 0) { buf[0] = 0; return; }
buf[r] = 0;
while (r > 0 && (buf[r-1] == '\n' || buf[r-1] == '\r')) buf[--r] = 0;
}
static int read_int(const char *path)
{
char buf[24];
read_str(path, buf, sizeof buf);
if (!buf[0]) return -1;
return atoi(buf);
}
static int hci_powered(void)
{
FILE *p = popen("hciconfig -a hci0 2>/dev/null", "r");
if (!p) return 0;
int up = 0;
char buf[256];
while (fgets(buf, sizeof buf, p)) {
char *s = buf, *tok;
while ((tok = strsep(&s, " \t\r\n")) != NULL) {
if (!strcmp(tok, "UP")) { up = 1; break; }
}
}
pclose(p);
return up;
}
/* 音量:读 settings.conf 的 audio.volume(launcher 同源,watchdog 写同文件)。 */
static int settings_vol(void)
{
FILE *f = fopen(MEOW_SETTINGS_FILE, "r");
if (!f) return VOL_DEFAULT;
int vol = VOL_DEFAULT;
char buf[128];
while (fgets(buf, sizeof buf, f)) {
if (!strncmp(buf, "audio.volume=", 13)) {
int v = atoi(buf + 13);
if (v >= 0 && v <= 100) vol = v;
break;
}
}
fclose(f);
return vol;
}
int meow_ui_sys_init(void)
{
memset(&g_sys, 0, sizeof g_sys);
g_sys.batt = -1;
g_sys.vol = settings_vol();
g_statusbar_on = 1;
g_fullscreen = 0;
g_statusbar_force = 1;
meow_ui_sys_refresh();
g_sys_inited = 1;
return 0;
}
void meow_ui_sys_refresh(void)
{
g_sys.batt = read_int("/sys/class/power_supply/battery/capacity");
if (g_sys.batt < 0 || g_sys.batt > 100) g_sys.batt = -1;
char st[16];
read_str("/sys/class/power_supply/battery/status", st, sizeof st);
g_sys.charging = (strstr(st, "Charg") || strstr(st, "Full")) ? 1 : 0;
char op[16];
read_str("/sys/class/net/wlan0/operstate", op, sizeof op);
g_sys.wifi_on = !strcmp(op, "up") ? 1 : 0;
g_sys.vol = settings_vol();
/* 蓝牙:hci0 存在性检查便宜;上电状态贵(hciconfig spawn),30s 缓存。 */
static uint64_t last_bt_ms = 0;
uint64_t n = now_ms();
g_sys.bt_seen = access("/sys/class/bluetooth/hci0", F_OK) == 0;
if (!g_sys.bt_seen) {
g_sys.bt_on = 0;
last_bt_ms = n;
} else if (!last_bt_ms || (n - last_bt_ms) >= BT_REFRESH_MS) {
g_sys.bt_on = hci_powered();
last_bt_ms = n;
}
/* 时钟每秒变 → 强制顶条重画(时间在绘制时现取) */
g_statusbar_force = 1;
}
const meow_sys_state *meow_ui_sys_get(void) { return &g_sys; }
/* ---- 公共 API ---- */
void meow_ui_set_statusbar(int visible)
{
g_statusbar_on = visible ? 1 : 0;
g_statusbar_force = 1; /* 显隐切换也要重画顶条 */
}
int meow_ui_statusbar_visible(void)
{
return g_statusbar_on && !g_fullscreen;
}
void meow_ui_set_fullscreen(int on)
{
g_fullscreen = on ? 1 : 0;
g_statusbar_force = 1; /* 进出全屏立即反映(显示/隐藏顶条) */
}
int meow_ui_statusbar_height(void)
{
return meow_ui_sys_statusbar_active() ? MUI_SBAR_H : 0;
}
/* ---- 内部(gfx/input 用) ---- */
int meow_ui_sys_statusbar_active(void)
{
return g_statusbar_on && !g_fullscreen;
}
int meow_ui_sys_statusbar_height(void)
{
return meow_ui_sys_statusbar_active() ? MUI_SBAR_H : 0;
}
int meow_ui_sys_statusbar_force(void)
{
int f = g_statusbar_force;
g_statusbar_force = 0;
return f;
}
/* 状态栏右侧信息串:batt% WIFI 蓝牙/蓝牙 VOL nn%(同 launcher statusbar_right_str) */
static void statusbar_right_str(char *out, size_t n)
{
char batt[16] = "", wifi[16] = "", vol[20] = "", bt[16] = "";
if (g_sys.batt >= 0) snprintf(batt, sizeof batt, "%d%%", g_sys.batt);
if (g_sys.wifi_on) snprintf(wifi, sizeof wifi, "WIFI");
snprintf(vol, sizeof vol, "VOL %d%%", g_sys.vol);
if (g_sys.bt_seen && g_sys.bt_on)
snprintf(bt, sizeof bt, meow_gfx_mfont_ready() ? "蓝牙" : "BT");
out[0] = 0;
if (batt[0]) strcat(out, batt);
if (wifi[0]) { if (out[0]) strcat(out, " "); strcat(out, wifi); }
if (bt[0]) { if (out[0]) strcat(out, " "); strcat(out, bt); }
if (vol[0]) { if (out[0]) strcat(out, " "); strcat(out, vol); }
}
void meow_ui_sys_statusbar_render(void)
{
if (!meow_ui_sys_statusbar_active()) return;
const meow_theme *th = meow_theme_get();
int w = meow_ui_width();
int h = MUI_SBAR_H;
/* 整条清底:覆盖 app 可能画进顶行的内容(z 最顶) */
meow_ui_fill_rect(0, 0, w, h, th->bg);
/* 时钟(左):每秒现取 localtime */
char timebuf[16];
time_t t = time(NULL);
struct tm tm;
localtime_r(&t, &tm);
snprintf(timebuf, sizeof timebuf, "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec);
meow_ui_text(8, (h - meow_ui_text_height(MUI_SBAR_FONT)) / 2, timebuf, MUI_SBAR_FONT, th->fg);
/* 右侧信息串:batt% WIFI 蓝牙 VOL nn% */
char right[96];
statusbar_right_str(right, sizeof right);
if (right[0])
meow_ui_text_right(w - 8, (h - meow_ui_text_height(MUI_SBAR_FONT)) / 2, right, MUI_SBAR_FONT, th->fg);
/* 分隔线(栏内最底 1px,主题次要色);内容 inset=statusbar_height()=40 从 y=40 起即干净 */
meow_ui_fill_rect(0, h - 1, w, 1, th->dim);
g_statusbar_force = 0;
}