Files
fastfetch/src/detection/battery/battery_android.c
T
2023-07-19 15:44:40 +08:00

129 lines
4.1 KiB
C

#include "fastfetch.h"
#include "battery.h"
#include "common/processing.h"
#include "common/properties.h"
#define FF_TERMUX_API_PATH FASTFETCH_TARGET_DIR_ROOT "/libexec/termux-api"
#define FF_TERMUX_API_PARAM "BatteryStatus"
static inline void wrapYyjsonFree(yyjson_doc** doc)
{
assert(doc);
if (*doc)
yyjson_doc_free(*doc);
}
static const char* parseTermuxApi(FFBatteryOptions* options, FFlist* results)
{
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
if(ffProcessAppendStdOut(&buffer, (char* const[]){
FF_TERMUX_API_PATH,
FF_TERMUX_API_PARAM,
NULL
}))
return "Starting `" FF_TERMUX_API_PATH " " FF_TERMUX_API_PARAM "` failed";
yyjson_doc* __attribute__((__cleanup__(wrapYyjsonFree))) doc = yyjson_read_opts(buffer.chars, buffer.length, 0, NULL, NULL);
if (!doc)
return "Failed to parse battery info";
yyjson_val* root = yyjson_doc_get_root(doc);
if (!yyjson_is_obj(root))
return "Battery info result is not a JSON object";
BatteryResult* battery = ffListAdd(results);
battery->temperature = FF_BATTERY_TEMP_UNSET;
ffStrbufInit(&battery->manufacturer);
ffStrbufInit(&battery->modelName);
ffStrbufInit(&battery->status);
ffStrbufInit(&battery->technology);
battery->capacity = yyjson_get_num(yyjson_obj_get(root, "percentage"));
ffStrbufAppendS(&battery->status, yyjson_get_str(yyjson_obj_get(root, "status")));
if(options->temp)
battery->temperature = yyjson_get_num(yyjson_obj_get(root, "temperature"));
return NULL;
}
static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
{
FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate();
if (ffProcessAppendStdOut(&buf, (char* []) {
"/system/bin/dumpsys",
"battery",
NULL,
}) != NULL || buf.length == 0)
return "Executing `/system/bin/dumpsys battery` failed"; // Only works in `adb shell`, or when rooted
if (!ffStrbufStartsWithS(&buf, "Current Battery Service state:\n"))
return "Invalid `/system/bin/dumpsys battery` result";
const char* start = buf.chars + strlen("Current Battery Service state:\n");
FF_STRBUF_AUTO_DESTROY temp = ffStrbufCreate();
if (!ffParsePropLines(start, "present: ", &temp) || !ffStrbufEqualS(&temp, "true"))
return NULL;
ffStrbufClear(&temp);
BatteryResult* battery = ffListAdd(results);
battery->temperature = FF_BATTERY_TEMP_UNSET;
ffStrbufInit(&battery->manufacturer);
ffStrbufInit(&battery->modelName);
ffStrbufInit(&battery->status);
ffStrbufInit(&battery->technology);
if (ffParsePropLines(start, "AC powered: ", &temp) && ffStrbufEqualS(&temp, "true"))
ffStrbufAppendS(&battery->status, "AC powered");
ffStrbufClear(&temp);
if (ffParsePropLines(start, "USB powered: ", &temp) && ffStrbufEqualS(&temp, "true"))
{
if (battery->status.length) ffStrbufAppendS(&battery->status, ", ");
ffStrbufAppendS(&battery->status, "USB powered");
}
ffStrbufClear(&temp);
if (ffParsePropLines(start, "Wireless powered: ", &temp) && ffStrbufEqualS(&temp, "true"))
{
if (battery->status.length) ffStrbufAppendS(&battery->status, ", ");
ffStrbufAppendS(&battery->status, "Wireless powered");
}
ffStrbufClear(&temp);
{
double level = 0, scale = 0;
if (ffParsePropLines(start, "level: ", &temp))
level = ffStrbufToDouble(&temp);
ffStrbufClear(&temp);
if (ffParsePropLines(start, "scale: ", &temp))
scale = ffStrbufToDouble(&temp);
ffStrbufClear(&temp);
if (level > 0 && scale > 0)
battery->capacity = level * 100 / scale;
}
if(options->temp)
{
if (ffParsePropLines(start, "temperature: ", &temp))
battery->temperature = ffStrbufToDouble(&temp);
ffStrbufClear(&temp);
}
ffParsePropLines(start, "technology: ", &battery->technology);
return NULL;
}
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
{
const char* error = parseTermuxApi(options, results);
if (error && parseDumpsys(options, results) == NULL)
return NULL;
return error;
}