From 96a0dd803abfb13af8e87a1093919408cda13da8 Mon Sep 17 00:00:00 2001 From: Swift Kim Date: Thu, 7 Apr 2022 18:07:37 +0900 Subject: [PATCH 1/2] [battery_plus] Refactor the C++ code --- .../tizen/src/battery_plus_tizen_plugin.cc | 246 +++++++----------- .../battery_plus/tizen/src/device_battery.cc | 104 ++++++++ .../battery_plus/tizen/src/device_battery.h | 43 +++ 3 files changed, 236 insertions(+), 157 deletions(-) create mode 100644 packages/battery_plus/tizen/src/device_battery.cc create mode 100644 packages/battery_plus/tizen/src/device_battery.h diff --git a/packages/battery_plus/tizen/src/battery_plus_tizen_plugin.cc b/packages/battery_plus/tizen/src/battery_plus_tizen_plugin.cc index 03cca3fe3..43428fc01 100644 --- a/packages/battery_plus/tizen/src/battery_plus_tizen_plugin.cc +++ b/packages/battery_plus/tizen/src/battery_plus_tizen_plugin.cc @@ -4,199 +4,131 @@ #include "battery_plus_tizen_plugin.h" -#include -#include #include #include -#include +#include #include #include #include -#include +#include #include -#include "log.h" - -class BatteryPlusTizenPlugin : public flutter::Plugin { - public: - static void RegisterWithRegistrar(flutter::PluginRegistrar *registrar) { - LOG_DEBUG("RegisterWithRegistrar for BatteryPlusTizenPlugin"); - auto plugin = std::make_unique(); - plugin->SetupChannels(registrar); - registrar->AddPlugin(std::move(plugin)); +#include "device_battery.h" + +namespace { + +typedef flutter::EventChannel FlEventChannel; +typedef flutter::EventSink FlEventSink; +typedef flutter::MethodCall FlMethodCall; +typedef flutter::MethodResult FlMethodResult; +typedef flutter::MethodChannel FlMethodChannel; +typedef flutter::StreamHandler FlStreamHandler; +typedef flutter::StreamHandlerError + FlStreamHandlerError; + +std::string BatteryStatusToString(BatteryStatus status) { + switch (status) { + case BatteryStatus::kCharging: + return "charging"; + case BatteryStatus::kFull: + return "full"; + case BatteryStatus::kDischarging: + return "discharging"; + case BatteryStatus::kUnknown: + default: + return "unknown"; } +} - BatteryPlusTizenPlugin() {} - - virtual ~BatteryPlusTizenPlugin() {} - - void RegisterObserver( - std::unique_ptr> &&events) { +class BatteryStatusStreamHandler : public FlStreamHandler { + protected: + std::unique_ptr OnListenInternal( + const flutter::EncodableValue *arguments, + std::unique_ptr &&events) override { events_ = std::move(events); - // DEVICE_CALLBACK_BATTERY_CHARGING callback is called in only two cases - // like charging and discharing. When the charging status becomes "Full", - // discharging status event is called. So if it is full and disconnected - // from USB or AC charger, then any callbacks will not be called because the - // status already is the discharging status. To resolve this issue, - // DEVICE_CALLBACK_BATTERY_LEVEL callback is added. This callback can check - // whether it is disconnected in "Full" status. That is, when the battery - // status is full and disconnected, the level status will be changed from - // DEVICE_BATTERY_LEVEL_FULL to DEVICE_BATTERY_LEVEL_HIGH. - int ret = device_add_callback(DEVICE_CALLBACK_BATTERY_CHARGING, - BatteryChangedCB, this); - if (ret != DEVICE_ERROR_NONE) { - events_->Error("failed_to_add_callback", get_error_message(ret)); - return; + BatteryStatusCallback callback = [this](BatteryStatus status) -> void { + if (status != BatteryStatus::kError) { + events_->Success( + flutter::EncodableValue(BatteryStatusToString(status))); + } else { + events_->Error(std::to_string(battery_.GetLastError()), + battery_.GetLastErrorString()); + } + }; + if (!battery_.StartListen(callback)) { + return std::make_unique( + std::to_string(battery_.GetLastError()), + battery_.GetLastErrorString(), nullptr); } - ret = device_add_callback(DEVICE_CALLBACK_BATTERY_LEVEL, BatteryChangedCB, - this); - if (ret != DEVICE_ERROR_NONE) { - events_->Error("failed_to_add_callback", get_error_message(ret)); - return; - } + // Send an initial event once the stream has been set up. + callback(battery_.GetStatus()); - std::string status = GetBatteryStatus(); - if (status.empty()) { - events_->Error("invalid_status", "Charging status error"); - } else { - events_->Success(flutter::EncodableValue(status)); - } + return nullptr; } - void UnregisterObserver() { - int ret = device_remove_callback(DEVICE_CALLBACK_BATTERY_CHARGING, - BatteryChangedCB); - if (ret != DEVICE_ERROR_NONE) { - LOG_ERROR("Failed to run device_remove_callback (%d: %s)", ret, - get_error_message(ret)); - } - ret = - device_remove_callback(DEVICE_CALLBACK_BATTERY_LEVEL, BatteryChangedCB); - if (ret != DEVICE_ERROR_NONE) { - LOG_ERROR("Failed to run device_remove_callback (%d: %s)", ret, - get_error_message(ret)); - } - - events_ = nullptr; + std::unique_ptr OnCancelInternal( + const flutter::EncodableValue *arguments) override { + battery_.StopListen(); + events_.reset(); + return nullptr; } - static std::string GetBatteryStatus() { - device_battery_status_e status; - int ret = device_battery_get_status(&status); - if (ret != DEVICE_ERROR_NONE) { - LOG_ERROR("Failed to run device_battery_get_status (%d: %s)", ret, - get_error_message(ret)); - return ""; - } + private: + DeviceBattery battery_; + std::unique_ptr events_; +}; - std::string value; - if (status == DEVICE_BATTERY_STATUS_CHARGING) { - value = "charging"; - } else if (status == DEVICE_BATTERY_STATUS_FULL) { - value = "full"; - } else if (status == DEVICE_BATTERY_STATUS_DISCHARGING || - status == DEVICE_BATTERY_STATUS_NOT_CHARGING) { - value = "discharging"; - } - LOG_INFO("battery status [%s]", value.c_str()); - return value; - } +class BatteryPlusTizenPlugin : public flutter::Plugin { + public: + static void RegisterWithRegistrar(flutter::PluginRegistrar *registrar) { + auto plugin = std::make_unique(); - static void BatteryChangedCB(device_callback_e type, void *value, - void *user_data) { - if (!user_data) { - LOG_ERROR("Invalid user data"); - return; - } + auto method_channel = std::make_unique( + registrar->messenger(), "dev.fluttercommunity.plus/battery", + &flutter::StandardMethodCodec::GetInstance()); + method_channel->SetMethodCallHandler( + [plugin_pointer = plugin.get()](const auto &call, auto result) { + plugin_pointer->HandleMethodCall(call, std::move(result)); + }); - // DEVICE_CALLBACK_BATTERY_LEVEL callback is used only for checking whether - // the battery became a discharging status while it is full. - if (type == DEVICE_CALLBACK_BATTERY_LEVEL && - intptr_t(value) < DEVICE_BATTERY_LEVEL_HIGH) { - return; - } + auto event_channel = std::make_unique( + registrar->messenger(), "dev.fluttercommunity.plus/charging", + &flutter::StandardMethodCodec::GetInstance()); + event_channel->SetStreamHandler( + std::make_unique()); - BatteryPlusTizenPlugin *plugin_pointer = - (BatteryPlusTizenPlugin *)user_data; + registrar->AddPlugin(std::move(plugin)); + } - std::string status = GetBatteryStatus(); - bool is_full = status == "full"; - if (is_full && plugin_pointer->is_full_) { - // This function is called twice by registered callbacks when battery - // status is full. So, it needs to avoid the unnecessary second call. - return; - } - plugin_pointer->is_full_ = is_full; + BatteryPlusTizenPlugin() {} - if (status.empty()) { - plugin_pointer->events_->Error("invalid_status", "Charging status error"); - } else { - plugin_pointer->events_->Success(flutter::EncodableValue(status)); - } - } + virtual ~BatteryPlusTizenPlugin() {} - void HandleMethodCall( - const flutter::MethodCall &method_call, - std::unique_ptr> result) { + private: + void HandleMethodCall(const FlMethodCall &method_call, + std::unique_ptr result) { const auto &method_name = method_call.method_name(); if (method_name == "getBatteryLevel") { - int percentage; - int ret = device_battery_get_percent(&percentage); - if (ret != DEVICE_ERROR_NONE) { - result->Error("internal_error", get_error_message(ret)); + DeviceBattery battery; + int32_t level = battery.GetLevel(); + if (level >= 0) { + result->Success(flutter::EncodableValue(level)); + } else { + result->Error(std::to_string(battery.GetLastError()), + battery.GetLastErrorString()); } - LOG_INFO("battery percentage [%d]", percentage); - result->Success(flutter::EncodableValue(percentage)); } else { result->NotImplemented(); } } - - private: - void SetupChannels(flutter::PluginRegistrar *registrar) { - auto method_channel = - std::make_unique>( - registrar->messenger(), "dev.fluttercommunity.plus/battery", - &flutter::StandardMethodCodec::GetInstance()); - event_channel_ = - std::make_unique>( - registrar->messenger(), "dev.fluttercommunity.plus/charging", - &flutter::StandardMethodCodec::GetInstance()); - - auto method_channel_handler = [this](const auto &call, auto result) { - LOG_DEBUG("HandleMethodCall call"); - HandleMethodCall(call, std::move(result)); - }; - auto event_channel_handler = - std::make_unique>( - [this](const flutter::EncodableValue *arguments, - std::unique_ptr> &&events) - -> std::unique_ptr> { - LOG_DEBUG("OnListen"); - RegisterObserver(std::move(events)); - return nullptr; - }, - [this](const flutter::EncodableValue *arguments) - -> std::unique_ptr> { - LOG_DEBUG("OnCancel"); - UnregisterObserver(); - return nullptr; - }); - - method_channel->SetMethodCallHandler(method_channel_handler); - event_channel_->SetStreamHandler(std::move(event_channel_handler)); - } - - std::unique_ptr> - event_channel_; - std::unique_ptr> events_; - bool is_full_ = false; }; +} // namespace + void BatteryPlusTizenPluginRegisterWithRegistrar( FlutterDesktopPluginRegistrarRef registrar) { BatteryPlusTizenPlugin::RegisterWithRegistrar( diff --git a/packages/battery_plus/tizen/src/device_battery.cc b/packages/battery_plus/tizen/src/device_battery.cc new file mode 100644 index 000000000..f1a536f94 --- /dev/null +++ b/packages/battery_plus/tizen/src/device_battery.cc @@ -0,0 +1,104 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device_battery.h" + +#include + +#include "log.h" + +bool DeviceBattery::StartListen(BatteryStatusCallback callback) { + // DEVICE_CALLBACK_BATTERY_CHARGING callback is called in only two cases + // like charging and discharing. When the charging status becomes "Full", + // discharging status event is called. So if it is full and disconnected + // from USB or AC charger, then any callbacks will not be called because the + // status already is the discharging status. To resolve this issue, + // DEVICE_CALLBACK_BATTERY_LEVEL callback is added. This callback can check + // whether it is disconnected in "Full" status. That is, when the battery + // status is full and disconnected, the level status will be changed from + // DEVICE_BATTERY_LEVEL_FULL to DEVICE_BATTERY_LEVEL_HIGH. + int ret = device_add_callback(DEVICE_CALLBACK_BATTERY_CHARGING, + OnBatteryStatusChanged, this); + if (ret != DEVICE_ERROR_NONE) { + LOG_ERROR("Failed to add callback: %s", get_error_message(ret)); + return false; + } + + ret = device_add_callback(DEVICE_CALLBACK_BATTERY_LEVEL, + OnBatteryStatusChanged, this); + if (ret != DEVICE_ERROR_NONE) { + LOG_ERROR("Failed to add callback: %s", get_error_message(ret)); + return false; + } + + callback_ = callback; + return true; +} + +void DeviceBattery::StopListen() { + int ret = device_remove_callback(DEVICE_CALLBACK_BATTERY_CHARGING, + OnBatteryStatusChanged); + if (ret != DEVICE_ERROR_NONE) { + LOG_ERROR("Failed to remove callback: %s", get_error_message(ret)); + } + + ret = device_remove_callback(DEVICE_CALLBACK_BATTERY_LEVEL, + OnBatteryStatusChanged); + if (ret != DEVICE_ERROR_NONE) { + LOG_ERROR("Failed to remove callback: %s", get_error_message(ret)); + } +} + +int32_t DeviceBattery::GetLevel() { + int32_t level; + int ret = device_battery_get_percent(&level); + if (ret != DEVICE_ERROR_NONE) { + LOG_ERROR("Failed to get battery level: %s", get_error_message(ret)); + return -1; + } + return level; +} + +BatteryStatus DeviceBattery::GetStatus() { + device_battery_status_e status; + int ret = device_battery_get_status(&status); + if (ret != DEVICE_ERROR_NONE) { + LOG_ERROR("Failed to get battery status: %s", get_error_message(ret)); + return BatteryStatus::kError; + } + + switch (status) { + case DEVICE_BATTERY_STATUS_CHARGING: + return BatteryStatus::kCharging; + case DEVICE_BATTERY_STATUS_FULL: + return BatteryStatus::kFull; + case DEVICE_BATTERY_STATUS_DISCHARGING: + case DEVICE_BATTERY_STATUS_NOT_CHARGING: + return BatteryStatus::kDischarging; + default: + return BatteryStatus::kUnknown; + } +} + +void DeviceBattery::OnBatteryStatusChanged(device_callback_e type, void *value, + void *user_data) { + auto *self = static_cast(user_data); + + // DEVICE_CALLBACK_BATTERY_LEVEL callback is used only for checking whether + // the battery became a discharging status while it is full. + if (type == DEVICE_CALLBACK_BATTERY_LEVEL && + intptr_t(value) < DEVICE_BATTERY_LEVEL_HIGH) { + return; + } + + BatteryStatus status = self->GetStatus(); + if (status == BatteryStatus::kFull && self->is_full_) { + // This function is called twice by registered callbacks when battery + // status is full. So, it needs to avoid the unnecessary second call. + return; + } + self->is_full_ = status == BatteryStatus::kFull; + + self->callback_(status); +} diff --git a/packages/battery_plus/tizen/src/device_battery.h b/packages/battery_plus/tizen/src/device_battery.h new file mode 100644 index 000000000..bc65a5b1f --- /dev/null +++ b/packages/battery_plus/tizen/src/device_battery.h @@ -0,0 +1,43 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_PLUGIN_DEVICE_BATTERY_H_ +#define FLUTTER_PLUGIN_DEVICE_BATTERY_H_ + +#include +#include + +#include +#include + +enum class BatteryStatus { kFull, kCharging, kDischarging, kUnknown, kError }; + +typedef std::function BatteryStatusCallback; + +class DeviceBattery { + public: + DeviceBattery() {} + ~DeviceBattery() {} + + int GetLastError() { return get_last_result(); } + + std::string GetLastErrorString() { return get_error_message(GetLastError()); } + + bool StartListen(BatteryStatusCallback callback); + + void StopListen(); + + int32_t GetLevel(); + + BatteryStatus GetStatus(); + + private: + static void OnBatteryStatusChanged(device_callback_e type, void *value, + void *user_data); + + BatteryStatusCallback callback_ = nullptr; + bool is_full_ = false; +}; + +#endif // FLUTTER_PLUGIN_DEVICE_BATTERY_H_ From 785e4bd39e824b6b024c95ad679001501041520d Mon Sep 17 00:00:00 2001 From: Swift Kim Date: Mon, 11 Apr 2022 13:53:18 +0900 Subject: [PATCH 2/2] Set last_error_ explicitly --- packages/battery_plus/tizen/src/device_battery.cc | 6 ++++++ packages/battery_plus/tizen/src/device_battery.h | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/battery_plus/tizen/src/device_battery.cc b/packages/battery_plus/tizen/src/device_battery.cc index f1a536f94..611fcfe4e 100644 --- a/packages/battery_plus/tizen/src/device_battery.cc +++ b/packages/battery_plus/tizen/src/device_battery.cc @@ -22,6 +22,7 @@ bool DeviceBattery::StartListen(BatteryStatusCallback callback) { OnBatteryStatusChanged, this); if (ret != DEVICE_ERROR_NONE) { LOG_ERROR("Failed to add callback: %s", get_error_message(ret)); + last_error_ = ret; return false; } @@ -29,6 +30,7 @@ bool DeviceBattery::StartListen(BatteryStatusCallback callback) { OnBatteryStatusChanged, this); if (ret != DEVICE_ERROR_NONE) { LOG_ERROR("Failed to add callback: %s", get_error_message(ret)); + last_error_ = ret; return false; } @@ -41,12 +43,14 @@ void DeviceBattery::StopListen() { OnBatteryStatusChanged); if (ret != DEVICE_ERROR_NONE) { LOG_ERROR("Failed to remove callback: %s", get_error_message(ret)); + last_error_ = ret; } ret = device_remove_callback(DEVICE_CALLBACK_BATTERY_LEVEL, OnBatteryStatusChanged); if (ret != DEVICE_ERROR_NONE) { LOG_ERROR("Failed to remove callback: %s", get_error_message(ret)); + last_error_ = ret; } } @@ -55,6 +59,7 @@ int32_t DeviceBattery::GetLevel() { int ret = device_battery_get_percent(&level); if (ret != DEVICE_ERROR_NONE) { LOG_ERROR("Failed to get battery level: %s", get_error_message(ret)); + last_error_ = ret; return -1; } return level; @@ -65,6 +70,7 @@ BatteryStatus DeviceBattery::GetStatus() { int ret = device_battery_get_status(&status); if (ret != DEVICE_ERROR_NONE) { LOG_ERROR("Failed to get battery status: %s", get_error_message(ret)); + last_error_ = ret; return BatteryStatus::kError; } diff --git a/packages/battery_plus/tizen/src/device_battery.h b/packages/battery_plus/tizen/src/device_battery.h index bc65a5b1f..a6e302fb4 100644 --- a/packages/battery_plus/tizen/src/device_battery.h +++ b/packages/battery_plus/tizen/src/device_battery.h @@ -20,9 +20,9 @@ class DeviceBattery { DeviceBattery() {} ~DeviceBattery() {} - int GetLastError() { return get_last_result(); } + int GetLastError() { return last_error_; } - std::string GetLastErrorString() { return get_error_message(GetLastError()); } + std::string GetLastErrorString() { return get_error_message(last_error_); } bool StartListen(BatteryStatusCallback callback); @@ -36,6 +36,7 @@ class DeviceBattery { static void OnBatteryStatusChanged(device_callback_e type, void *value, void *user_data); + int last_error_ = TIZEN_ERROR_NONE; BatteryStatusCallback callback_ = nullptr; bool is_full_ = false; };