charger: separate UI and HAL access.

Abstract all the HIDL-ness from charger so an AIDL HAL
can later replace the HIDL HAL.

Created libhealthd_charger_ui that is responsible for
UI stuff in charger. Then libhealthd_charger is now the
charger library backed by HIDL HAL.

Bug: 170338625
Bug: 203246116

Test: charger_test

Change-Id: I193bb76afa18b3367f24796ac53b1760650e8683
diff --git a/healthd/Android.bp b/healthd/Android.bp
index ec47f68..020a744 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -120,21 +120,22 @@
 }
 
 cc_library_static {
-    name: "libhealthd_charger",
-    local_include_dirs: ["include"],
-    export_include_dirs: [".", "include"],
+    name: "libhealthd_charger_ui",
+    export_include_dirs: [
+        "include",
+        "include_charger",
+    ],
 
     static_libs: [
-        "android.hardware.health@1.0-convert",
+        "android.hardware.health-V1-ndk",
+        "android.hardware.health-translate-ndk",
         "libcharger_sysprop",
         "libhealthd_draw",
         "libhealthloop",
-        "libhealth2impl",
         "libminui",
     ],
 
     shared_libs: [
-        "android.hardware.health@2.1",
         "libbase",
         "libcutils",
         "liblog",
@@ -143,14 +144,51 @@
         "libutils",
     ],
 
+    header_libs: [
+        "libhealthd_headers",
+    ],
+
+    export_static_lib_headers: [
+        "android.hardware.health-V1-ndk",
+    ],
+
     srcs: [
         "healthd_mode_charger.cpp",
         "AnimationParser.cpp",
     ],
 }
 
+cc_library_static {
+    name: "libhealthd_charger",
+    export_include_dirs: [
+        "include",
+        "include_charger",
+    ],
+
+    static_libs: [
+        "android.hardware.health@1.0-convert",
+        "libhealth2impl",
+        "libhealthd_charger_ui",
+    ],
+
+    shared_libs: [
+        "android.hardware.health@2.1",
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+
+    srcs: [
+        "healthd_mode_charger_hidl.cpp",
+    ],
+}
+
 cc_defaults {
     name: "charger_defaults",
+    local_include_dirs: [
+        "include_charger",
+    ],
 
     cflags: [
         "-Wall",
@@ -174,6 +212,7 @@
     static_libs: [
         // common
         "android.hardware.health@1.0-convert",
+        "android.hardware.health-V1-ndk",
         "libbatterymonitor",
         "libcharger_sysprop",
         "libhealthd_charger_nops",
@@ -183,6 +222,7 @@
         // system charger only
         "libhealthd_draw",
         "libhealthd_charger",
+        "libhealthd_charger_ui",
         "libminui",
         "libsuspend",
     ],
@@ -209,6 +249,7 @@
             exclude_static_libs: [
                 "libhealthd_draw",
                 "libhealthd_charger",
+                "libhealthd_charger_ui",
                 "libminui",
                 "libsuspend",
             ],
diff --git a/healthd/charger.cpp b/healthd/charger.cpp
index d03978d..73e04fe 100644
--- a/healthd/charger.cpp
+++ b/healthd/charger.cpp
@@ -15,9 +15,9 @@
  */
 
 #include <android-base/logging.h>
+#include <charger.sysprop.h>
 
-#include "charger.sysprop.h"
-#include "healthd_mode_charger.h"
+#include "healthd_mode_charger_hidl.h"
 #include "healthd_mode_charger_nops.h"
 
 #ifndef CHARGER_FORCE_NO_UI
diff --git a/healthd/charger_test.cpp b/healthd/charger_test.cpp
index e0bde68..dc5c459 100644
--- a/healthd/charger_test.cpp
+++ b/healthd/charger_test.cpp
@@ -31,7 +31,7 @@
 #include <health/utils.h>
 #include <health2impl/Health.h>
 
-#include "healthd_mode_charger.h"
+#include "healthd_mode_charger_hidl.h"
 
 using android::hardware::health::InitHealthdConfig;
 using android::hardware::health::V2_1::HealthInfo;
@@ -153,7 +153,7 @@
     sp<IHealth> passthrough = new TestHealth(std::move(config));
 
     std::thread bgThread([=] {
-        android::Charger charger(passthrough);
+        android::ChargerHidl charger(passthrough);
         charger.StartLoop();
     });
 
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 3ea90b0..645ac41 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "healthd_mode_charger.h"
+#include <charger/healthd_mode_charger.h>
 
 #include <dirent.h>
 #include <errno.h>
@@ -51,26 +51,16 @@
 
 #include "AnimationParser.h"
 #include "charger.sysprop.h"
-#include "charger_utils.h"
 #include "healthd_draw.h"
 
-#include <android/hardware/health/2.0/IHealthInfoCallback.h>
-#include <health/utils.h>
-#include <health2impl/HalHealthLoop.h>
-#include <health2impl/Health.h>
+#include <aidl/android/hardware/health/BatteryStatus.h>
+#include <health/HealthLoop.h>
 #include <healthd/healthd.h>
 
 using std::string_literals::operator""s;
 using namespace android;
-using android::hardware::Return;
-using android::hardware::health::GetHealthServiceOrDefault;
+using aidl::android::hardware::health::BatteryStatus;
 using android::hardware::health::HealthLoop;
-using android::hardware::health::V1_0::BatteryStatus;
-using android::hardware::health::V2_0::Result;
-using android::hardware::health::V2_1::IHealth;
-using IHealth_2_0 = android::hardware::health::V2_0::IHealth;
-using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
-using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
 
 // main healthd loop
 extern int healthd_main(void);
@@ -199,8 +189,8 @@
     };
 }
 
-Charger::Charger(const sp<IHealth>& service)
-    : HalHealthLoop("charger", service), batt_anim_(BASE_ANIMATION) {}
+Charger::Charger(ChargerConfigurationInterface* configuration)
+    : batt_anim_(BASE_ANIMATION), configuration_(configuration) {}
 
 Charger::~Charger() {}
 
@@ -291,7 +281,7 @@
     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 (health_info_.battery_level == 0 && health_info_.battery_status == 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;
@@ -305,18 +295,15 @@
     }
 
     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;
-            }
-        });
+        std::optional<bool> out_screen_on = configuration_->ChargerShouldKeepScreenOn();
         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);
+                if (configuration_->ChargerIsOnline()) {
+                    request_suspend(true);
+                }
                 return;
             }
         }
@@ -337,7 +324,9 @@
         healthd_draw_->blank_screen(true);
         screen_blanked_ = true;
         LOGV("[%" PRId64 "] animation done\n", now);
-        if (charger_online()) request_suspend(true);
+        if (configuration_->ChargerIsOnline()) {
+            request_suspend(true);
+        }
         return;
     }
 
@@ -351,9 +340,9 @@
     /* 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) {
+        batt_anim_.cur_level = health_info_.battery_level;
+        batt_anim_.cur_status = (int)health_info_.battery_status;
+        if (health_info_.battery_level >= 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 &&
@@ -363,7 +352,7 @@
                 }
             }
 
-            if (charger_online()) {
+            if (configuration_->ChargerIsOnline()) {
                 // repeat the first frame first_frame_repeats times
                 disp_time = batt_anim_.frames[batt_anim_.cur_frame].disp_time *
                             batt_anim_.first_frame_repeats;
@@ -394,7 +383,7 @@
     /* 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()) {
+    if (configuration_->ChargerIsOnline()) {
         batt_anim_.cur_frame++;
 
         while (batt_anim_.cur_frame < batt_anim_.num_frames &&
@@ -516,7 +505,7 @@
     int timer_shutdown = UNPLUGGED_SHUTDOWN_TIME;
     if (!have_battery_state_) return;
 
-    if (!charger_online()) {
+    if (!configuration_->ChargerIsOnline()) {
         request_suspend(false);
         if (next_pwr_check_ == -1) {
             /* Last cycle would have stopped at the extreme top of battery-icon
@@ -557,7 +546,7 @@
     }
 }
 
-void Charger::Heartbeat() {
+void Charger::OnHeartbeat() {
     // charger* charger = &charger_state;
     int64_t now = curr_time_ms();
 
@@ -570,9 +559,7 @@
     UpdateScreenState(now);
 }
 
-void Charger::OnHealthInfoChanged(const HealthInfo_2_1& health_info) {
-    set_charger_online(health_info);
-
+void Charger::OnHealthInfoChanged(const ChargerHealthInfo& health_info) {
     if (!have_battery_state_) {
         have_battery_state_ = true;
         next_screen_transition_ = curr_time_ms() - 1;
@@ -580,12 +567,10 @@
         reset_animation(&batt_anim_);
         kick_animation(&batt_anim_);
     }
-    health_info_ = health_info.legacy.legacy;
-
-    AdjustWakealarmPeriods(charger_online());
+    health_info_ = health_info;
 }
 
-int Charger::PrepareToWait(void) {
+int Charger::OnPrepareToWait(void) {
     int64_t now = curr_time_ms();
     int64_t next_event = INT64_MAX;
     int64_t timeout;
@@ -672,7 +657,7 @@
     }
 }
 
-void Charger::Init(struct healthd_config* config) {
+void Charger::OnInit(struct healthd_config* config) {
     int ret;
     int i;
     int epollfd;
@@ -685,7 +670,7 @@
             std::bind(&Charger::InputCallback, this, std::placeholders::_1, std::placeholders::_2));
     if (!ret) {
         epollfd = ev_get_epollfd();
-        RegisterEvent(epollfd, &charger_event_handler, EVENT_WAKEUP_FD);
+        configuration_->ChargerRegisterEvent(epollfd, &charger_event_handler, EVENT_WAKEUP_FD);
     }
 
     InitAnimation();
@@ -730,7 +715,7 @@
     wait_batt_level_timestamp_ = 0;
 
     // Retrieve healthd_config from the existing health HAL.
-    HalHealthLoop::Init(config);
+    configuration_->ChargerInitConfig(config);
 
     boot_min_cap_ = config->boot_min_cap;
 }
@@ -773,25 +758,3 @@
 }
 
 }  // namespace android
-
-int healthd_charger_main(int argc, char** argv) {
-    int ch;
-
-    while ((ch = getopt(argc, argv, "cr")) != -1) {
-        switch (ch) {
-            case 'c':
-                // -c is now a noop
-                break;
-            case 'r':
-                // -r is now a noop
-                break;
-            case '?':
-            default:
-                LOGE("Unrecognized charger option: %c\n", optopt);
-                exit(1);
-        }
-    }
-
-    Charger charger(GetHealthServiceOrDefault());
-    return charger.StartLoop();
-}
diff --git a/healthd/healthd_mode_charger.h b/healthd/healthd_mode_charger.h
deleted file mode 100644
index 6f9ae8c..0000000
--- a/healthd/healthd_mode_charger.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <linux/input.h>
-
-#include <memory>
-#include <vector>
-
-#include <android/hardware/health/2.0/IHealthInfoCallback.h>
-#include <android/hardware/health/2.1/IHealth.h>
-#include <health2impl/HalHealthLoop.h>
-
-#include "animation.h"
-
-class GRSurface;
-class HealthdDraw;
-
-namespace android {
-struct key_state {
-    bool pending;
-    bool down;
-    int64_t timestamp;
-};
-
-class Charger : public ::android::hardware::health::V2_1::implementation::HalHealthLoop {
-  public:
-    using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
-    using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
-
-    Charger(const sp<android::hardware::health::V2_1::IHealth>& service);
-    ~Charger();
-
-  protected:
-    // HealthLoop overrides.
-    void Heartbeat() override;
-    int PrepareToWait() override;
-    void Init(struct healthd_config* config) override;
-    // HalHealthLoop overrides
-    void OnHealthInfoChanged(const HealthInfo_2_1& health_info) override;
-
-    // Allowed to be mocked for testing.
-    virtual int CreateDisplaySurface(const std::string& name, GRSurface** surface);
-    virtual int CreateMultiDisplaySurface(const std::string& name, int* frames, int* fps,
-                                          GRSurface*** surface);
-
-  private:
-    void InitDefaultAnimationFrames();
-    void UpdateScreenState(int64_t now);
-    int SetKeyCallback(int code, int value);
-    void UpdateInputState(input_event* ev);
-    void SetNextKeyCheck(key_state* key, int64_t timeout);
-    void ProcessKey(int code, int64_t now);
-    void HandleInputState(int64_t now);
-    void HandlePowerSupplyState(int64_t now);
-    int InputCallback(int fd, unsigned int epevents);
-    void InitAnimation();
-
-    bool have_battery_state_ = false;
-    bool screen_blanked_ = false;
-    int64_t next_screen_transition_ = 0;
-    int64_t next_key_check_ = 0;
-    int64_t next_pwr_check_ = 0;
-    int64_t wait_batt_level_timestamp_ = 0;
-
-    key_state keys_[KEY_MAX + 1] = {};
-
-    animation batt_anim_;
-    GRSurface* surf_unknown_ = nullptr;
-    int boot_min_cap_ = 0;
-
-    HealthInfo_1_0 health_info_ = {};
-    std::unique_ptr<HealthdDraw> healthd_draw_;
-    std::vector<animation::frame> owned_frames_;
-};
-}  // namespace android
-
-int healthd_charger_main(int argc, char** argv);
diff --git a/healthd/healthd_mode_charger_hidl.cpp b/healthd/healthd_mode_charger_hidl.cpp
new file mode 100644
index 0000000..ae46b23
--- /dev/null
+++ b/healthd/healthd_mode_charger_hidl.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "healthd_mode_charger_hidl.h"
+
+#include <android/hardware/health/2.0/types.h>
+#include <cutils/klog.h>
+
+#include "charger_utils.h"
+
+using android::hardware::health::GetHealthServiceOrDefault;
+using android::hardware::health::V2_0::Result;
+
+namespace android {
+
+ChargerHidl::ChargerHidl(const sp<android::hardware::health::V2_1::IHealth>& service)
+    : HalHealthLoop("charger", service), charger_(std::make_unique<Charger>(this)) {}
+
+void ChargerHidl::OnHealthInfoChanged(const HealthInfo_2_1& health_info) {
+    set_charger_online(health_info);
+
+    charger_->OnHealthInfoChanged(ChargerHealthInfo{
+            .battery_level = health_info.legacy.legacy.batteryLevel,
+            .battery_status = static_cast<::aidl::android::hardware::health::BatteryStatus>(
+                    health_info.legacy.legacy.batteryStatus),
+    });
+
+    AdjustWakealarmPeriods(charger_online());
+}
+
+std::optional<bool> ChargerHidl::ChargerShouldKeepScreenOn() {
+    std::optional<bool> out_screen_on;
+    service()->shouldKeepScreenOn([&](Result res, bool screen_on) {
+        if (res == Result::SUCCESS) {
+            *out_screen_on = screen_on;
+        }
+    });
+    return out_screen_on;
+}
+
+}  // namespace android
+
+int healthd_charger_main(int argc, char** argv) {
+    int ch;
+
+    while ((ch = getopt(argc, argv, "cr")) != -1) {
+        switch (ch) {
+            case 'c':
+                // -c is now a noop
+                break;
+            case 'r':
+                // -r is now a noop
+                break;
+            case '?':
+            default:
+                KLOG_ERROR("charger", "Unrecognized charger option: %c\n", optopt);
+                exit(1);
+        }
+    }
+
+    android::ChargerHidl charger(GetHealthServiceOrDefault());
+    return charger.StartLoop();
+}
diff --git a/healthd/healthd_mode_charger_hidl.h b/healthd/healthd_mode_charger_hidl.h
new file mode 100644
index 0000000..9e70c5a
--- /dev/null
+++ b/healthd/healthd_mode_charger_hidl.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <health2impl/HalHealthLoop.h>
+
+#include <charger/healthd_mode_charger.h>
+
+namespace android {
+
+// An implementation of Charger backed by HIDL implementation. Uses HIDL health
+// HAL's HalHealthLoop.
+class ChargerHidl : public ::android::ChargerConfigurationInterface,
+                    public ::android::hardware::health::V2_1::implementation::HalHealthLoop {
+    using HalHealthLoop = ::android::hardware::health::V2_1::implementation::HalHealthLoop;
+    using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;
+
+  public:
+    explicit ChargerHidl(const sp<android::hardware::health::V2_1::IHealth>& service);
+    std::optional<bool> ChargerShouldKeepScreenOn() override;
+    bool ChargerIsOnline() override { return HalHealthLoop::charger_online(); }
+    void ChargerInitConfig(healthd_config* config) override { return HalHealthLoop::Init(config); }
+    int ChargerRegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) override {
+        return HalHealthLoop::RegisterEvent(fd, func, wakeup);
+    }
+    // HealthLoop overrides
+    void Heartbeat() override { charger_->OnHeartbeat(); }
+    int PrepareToWait() override { return charger_->OnPrepareToWait(); }
+    void Init(struct healthd_config* config) override { charger_->OnInit(config); }
+    // HalHealthLoop overrides
+    void OnHealthInfoChanged(const HealthInfo_2_1& health_info) override;
+
+  private:
+    sp<android::hardware::health::V2_1::IHealth> service_;
+    std::unique_ptr<Charger> charger_;
+};
+
+}  // namespace android
+
+int healthd_charger_main(int argc, char** argv);
diff --git a/healthd/healthd_mode_charger_test.cpp b/healthd/healthd_mode_charger_test.cpp
index f444f66..b7aace3 100644
--- a/healthd/healthd_mode_charger_test.cpp
+++ b/healthd/healthd_mode_charger_test.cpp
@@ -23,11 +23,12 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/strings.h>
+#include <android/hardware/health/2.1/IHealth.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <health/utils.h>
 
-#include "healthd_mode_charger.h"
+#include "healthd_mode_charger_hidl.h"
 
 using android::hardware::Return;
 using android::hardware::health::InitHealthdConfig;
@@ -102,12 +103,12 @@
     MOCK_METHOD(Return<void>, shouldKeepScreenOn, (shouldKeepScreenOn_cb _hidl_cb));
 };
 
-class TestCharger : public Charger {
+class TestCharger : public ChargerHidl {
   public:
     // Inherit constructor.
-    using Charger::Charger;
+    using ChargerHidl::ChargerHidl;
     // Expose protected functions to be used in tests.
-    void Init(struct healthd_config* config) override { Charger::Init(config); }
+    void Init(struct healthd_config* config) override { ChargerHidl::Init(config); }
     MOCK_METHOD(int, CreateDisplaySurface, (const std::string& name, GRSurface** surface));
     MOCK_METHOD(int, CreateMultiDisplaySurface,
                 (const std::string& name, int* frames, int* fps, GRSurface*** surface));
diff --git a/healthd/include_charger/charger/healthd_mode_charger.h b/healthd/include_charger/charger/healthd_mode_charger.h
new file mode 100644
index 0000000..a555b0a
--- /dev/null
+++ b/healthd/include_charger/charger/healthd_mode_charger.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <linux/input.h>
+
+#include <memory>
+#include <optional>
+#include <vector>
+
+#include <aidl/android/hardware/health/BatteryStatus.h>
+#include <health/HealthLoop.h>
+#include <healthd/healthd.h>
+
+#include "animation.h"
+
+class GRSurface;
+class HealthdDraw;
+
+namespace android {
+struct key_state {
+    bool pending;
+    bool down;
+    int64_t timestamp;
+};
+
+// Health info that interests charger
+struct ChargerHealthInfo {
+    int32_t battery_level;
+    aidl::android::hardware::health::BatteryStatus battery_status;
+};
+
+// Configuration interface for charger. This includes:
+// - HalHealthLoop APIs that interests charger.
+// - configuration values that used to be provided by sysprops
+class ChargerConfigurationInterface {
+  public:
+    virtual ~ChargerConfigurationInterface() = default;
+    // HalHealthLoop related APIs
+    virtual std::optional<bool> ChargerShouldKeepScreenOn() = 0;
+    virtual bool ChargerIsOnline() = 0;
+    virtual void ChargerInitConfig(healthd_config* config) = 0;
+    using BoundFunction =
+            std::function<void(android::hardware::health::HealthLoop*, uint32_t /* epevents */)>;
+    virtual int ChargerRegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) = 0;
+
+    // Other configuration values
+};
+
+// charger UI
+class Charger {
+  public:
+    explicit Charger(ChargerConfigurationInterface* configuration);
+    virtual ~Charger();
+
+    // Hooks for ChargerConfigurationInterface
+    void OnHeartbeat();
+    int OnPrepareToWait();
+    // |cookie| is passed to ChargerConfigurationInterface::ChargerInitConfig
+    void OnInit(struct healthd_config* config);
+    void OnHealthInfoChanged(const ChargerHealthInfo& health_info);
+
+  protected:
+    // Allowed to be mocked for testing.
+    virtual int CreateDisplaySurface(const std::string& name, GRSurface** surface);
+    virtual int CreateMultiDisplaySurface(const std::string& name, int* frames, int* fps,
+                                          GRSurface*** surface);
+
+  private:
+    void InitDefaultAnimationFrames();
+    void UpdateScreenState(int64_t now);
+    int SetKeyCallback(int code, int value);
+    void UpdateInputState(input_event* ev);
+    void SetNextKeyCheck(key_state* key, int64_t timeout);
+    void ProcessKey(int code, int64_t now);
+    void HandleInputState(int64_t now);
+    void HandlePowerSupplyState(int64_t now);
+    int InputCallback(int fd, unsigned int epevents);
+    void InitAnimation();
+
+    bool have_battery_state_ = false;
+    bool screen_blanked_ = false;
+    int64_t next_screen_transition_ = 0;
+    int64_t next_key_check_ = 0;
+    int64_t next_pwr_check_ = 0;
+    int64_t wait_batt_level_timestamp_ = 0;
+
+    key_state keys_[KEY_MAX + 1] = {};
+
+    animation batt_anim_;
+    GRSurface* surf_unknown_ = nullptr;
+    int boot_min_cap_ = 0;
+
+    ChargerHealthInfo health_info_ = {};
+    std::unique_ptr<HealthdDraw> healthd_draw_;
+    std::vector<animation::frame> owned_frames_;
+
+    ChargerConfigurationInterface* configuration_;
+};
+}  // namespace android