问题:基于Android11关机动画,当关机动画显示为充满状态时,开机进入后发现状态栏或settings中电池的电量却为99%?
分析:这个问题和电池状态驱动节点有关系,电池的充电状态节点是*/*/status,status有1 2 3 4 5 五种状态值,当status==5即为FUll充满状态。部分项目status节点在当电量为99%时status即为full,造成了关机动画展示问题。
hardware/interfaces/health/1.0/type.hal
@export(name="", value_prefix="BATTERY_STATUS_")
enum BatteryStatus : int32_t {
UNKNOWN = 1,
CHARGING = 2,
DISCHARGING = 3,
/**
* Battery is *not* charging - special case when charger is present
* but battery isn't charging
*/
NOT_CHARGING = 4,
FULL = 5,
};
流程:关机动画电池节点status判断逻辑
system/core/healthd/healthd_mode_charger.cpp UpdateScreenState方法:
system/core/healthd/healthd_draw.cpp redraw_screen->draw_battery->draw_percent方法:
void Charger::UpdateScreenState(int64_t now) {
int disp_time;
if (!batt_anim_.run || now < next_screen_transition_) return;
// If battery level is not ready, keep checking in the defined time
if (health_info_.batteryLevel == 0 && health_info_.batteryStatus == BatteryStatus::UNKNOWN) {
if (wait_batt_level_timestamp_ == 0) {
// Set max delay time and skip drawing screen
wait_batt_level_timestamp_ = now + MAX_BATT_LEVEL_WAIT_TIME;
LOGV("[%" PRId64 "] wait for battery capacity ready\n", now);
return;
} else if (now <= wait_batt_level_timestamp_) {
// Do nothing, keep waiting
return;
}
// If timeout and battery level is still not ready, draw unknown battery
}
if (healthd_draw_ == nullptr) {
std::optional<bool> out_screen_on;
service()->shouldKeepScreenOn([&](Result res, bool screen_on) {
if (res == Result::SUCCESS) {
*out_screen_on = screen_on;
}
});
if (out_screen_on.has_value()) {
if (!*out_screen_on) {
LOGV("[%" PRId64 "] leave screen off\n", now);
batt_anim_.run = false;
next_screen_transition_ = -1;
if (charger_online()) request_suspend(true);
return;
}
}
healthd_draw_.reset(new HealthdDraw(&batt_anim_));
if (android::sysprop::ChargerProperties::disable_init_blank().value_or(false)) {
healthd_draw_->blank_screen(true);
screen_blanked_ = true;
}
}
/* animation is over, blank screen and leave */
if (batt_anim_.num_cycles > 0 && batt_anim_.cur_cycle == batt_anim_.num_cycles) {
reset_animation(&batt_anim_);
next_screen_transition_ = -1;
healthd_draw_->blank_screen(true);
screen_blanked_ = true;
LOGV("[%" PRId64 "] animation done\n", now);
if (charger_online()) request_suspend(true);
return;
}
disp_time = batt_anim_.frames[batt_anim_.cur_frame].disp_time;
/* unblank the screen on first cycle and first frame */
if (batt_anim_.cur_cycle == 0 && batt_anim_.cur_frame == 0) healthd_draw_->blank_screen(false);
if (screen_blanked_) {
healthd_draw_->blank_screen(false);
screen_blanked_ = false;
}
/* animation starting, set up the animation */
if (batt_anim_.cur_frame == 0) {
LOGV("[%" PRId64 "] animation starting\n", now);
batt_anim_.cur_level = health_info_.batteryLevel;
batt_anim_.cur_status = (int)health_info_.batteryStatus;
if (health_info_.batteryLevel >= 0 && batt_anim_.num_frames != 0) {
/* find first frame given current battery level */
for (int i = 0; i < batt_anim_.num_frames; i++) {
if (batt_anim_.cur_level >= batt_anim_.frames[i].min_level &&
batt_anim_.cur_level <= batt_anim_.frames[i].max_level) {
batt_anim_.cur_frame = i;
break;
}
}
if (charger_online()) {
// repeat the first frame first_frame_repeats times
disp_time = batt_anim_.frames[batt_anim_.cur_frame].disp_time *
batt_anim_.first_frame_repeats;
} else {
disp_time = UNPLUGGED_DISPLAY_TIME / batt_anim_.num_cycles;
}
LOGV("cur_frame=%d disp_time=%d\n", batt_anim_.cur_frame, disp_time);
}
}
//********代码位置*************
/* draw the new frame (@ cur_frame) */
healthd_draw_->redraw_screen(&batt_anim_, surf_unknown_);
/* if we don't have anim frames, we only have one image, so just bump
* the cycle counter and exit
*/
if (batt_anim_.num_frames == 0 || batt_anim_.cur_level < 0) {
LOGW("[%" PRId64 "] animation missing or unknown battery status\n", now);
next_screen_transition_ = now + BATTERY_UNKNOWN_TIME;
batt_anim_.cur_cycle++;
return;
}
/* schedule next screen transition */
next_screen_transition_ = curr_time_ms() + disp_time;
/* advance frame cntr to the next valid frame only if we are charging
* if necessary, advance cycle cntr, and reset frame cntr
*/
if (charger_online()) {
batt_anim_.cur_frame++;
while (batt_anim_.cur_frame < batt_anim_.num_frames &&
(batt_anim_.cur_level < batt_anim_.frames[batt_anim_.cur_frame].min_level ||
batt_anim_.cur_level > batt_anim_.frames[batt_anim_.cur_frame].max_level)) {
batt_anim_.cur_frame++;
}
if (batt_anim_.cur_frame >= batt_anim_.num_frames) {
batt_anim_.cur_cycle++;
batt_anim_.cur_frame = 0;
/* don't reset the cycle counter, since we use that as a signal
* in a test above to check if animation is over
*/
}
} else {
/* Stop animating if we're not charging.
* If we stop it immediately instead of going through this loop, then
* the animation would stop somewhere in the middle.
*/
batt_anim_.cur_frame = 0;
batt_anim_.cur_cycle++;
}
}
void HealthdDraw::draw_percent(const animation* anim) {
if (!graphics_available) return;
int cur_level = anim->cur_level;
//***代码修改处,添加level==100,当电量100才展示充满电ui***
if (anim->cur_status == BATTERY_STATUS_FULL && cur_level==100) {
cur_level = 100;
}
if (cur_level < 0) return;
const animation::text_field& field = anim->text_percent;
if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) {
return;
}
std::string str = base::StringPrintf("%d%%", cur_level);
int x, y;
determine_xy(field, str.size(), &x, &y);
LOGV("drawing percent %s %d %d\n", str.c_str(), x, y);
gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
draw_text(field.font, x, y, str.c_str());
}