[Adaptive-Charging] Add notifications for Adaptive Charging
Adds a controller that show notification for adaptive charging. The actually use of this controller will be added in following CL(s). Screenshots of the strings added in this CL are here: go/strpic/2a8b80e5f34c93fd91001855358d84f2a16802d4 go/strpic/d08545ab42b37cbf26202964438abbd2435b188f BUG=b:216035329 Change-Id: I38cc9381d73579f744f88e594404b0b71a8bab90 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3613887 Reviewed-by: Michael Martis <martis@chromium.org> Reviewed-by: Evan Stade <estade@chromium.org> Reviewed-by: Alex Newcomer <newcomer@chromium.org> Commit-Queue: Thanh Nguyen <thanhdng@chromium.org> Cr-Commit-Position: refs/heads/main@{#998266}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
af15c0e008
commit
3a6f413371
ash
BUILD.gnash_strings.grd
ash_strings_grd
IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_FULLY_CHARGE_NOW_BUTTON_TEXT.png.sha1IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_MESSAGE_INDEFINITE.png.sha1IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_MESSAGE_TEMPORARY.png.sha1IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_TITLE.png.sha1
resources
vector_icons
system
@ -1454,6 +1454,8 @@ component("ash") {
|
||||
"system/phonehub/ui_constants.h",
|
||||
"system/power/adaptive_charging_controller.cc",
|
||||
"system/power/adaptive_charging_controller.h",
|
||||
"system/power/adaptive_charging_notification_controller.cc",
|
||||
"system/power/adaptive_charging_notification_controller.h",
|
||||
"system/power/adaptive_charging_nudge.cc",
|
||||
"system/power/adaptive_charging_nudge.h",
|
||||
"system/power/adaptive_charging_nudge_controller.cc",
|
||||
@ -2755,6 +2757,7 @@ test("ash_unittests") {
|
||||
"system/phonehub/silence_phone_quick_action_controller_unittest.cc",
|
||||
"system/phonehub/task_continuation_view_unittest.cc",
|
||||
"system/power/adaptive_charging_controller_unittest.cc",
|
||||
"system/power/adaptive_charging_notification_controller_unittest.cc",
|
||||
"system/power/adaptive_charging_nudge_controller_unittest.cc",
|
||||
"system/power/backlights_forced_off_setter_unittest.cc",
|
||||
"system/power/lock_on_leave_controller_unittest.cc",
|
||||
|
@ -4871,6 +4871,19 @@ New install
|
||||
<message name="IDS_ASH_ADAPTIVE_CHARGING_EDUCATIONAL_NUDGE_TEXT" desc="The body text explaining to the user that adaptive charging is on.">
|
||||
Adaptive charging is on. Your battery will stay at 80% to extend battery life, and fully charge when you need it.
|
||||
</message>
|
||||
<message name="IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_TITLE" desc="Title of adaptive charging notification explaining adpative charging is on.">
|
||||
Adaptive charging is on
|
||||
</message>
|
||||
<message name="IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_MESSAGE_INDEFINITE" desc="Notification message explaining the battery is kept at 80%.">
|
||||
Your battery is kept at 80% while plugged in to extend battery life.
|
||||
</message>
|
||||
<message name="IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_MESSAGE_TEMPORARY" desc="Notification message explaining the battery is temporarily at 80%. The message includes the predicted time at which charging will resume.">
|
||||
Your battery is temporarily at 80% while plugged in to extend battery life. Your battery will fully charge by <ph name="FULLY_CHARGE_TIME">$1<ex>7:30 AM</ex></ph>.
|
||||
</message>
|
||||
<message name="IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_FULLY_CHARGE_NOW_BUTTON_TEXT" desc="Text in notification button to fully charge the device.">
|
||||
Fully charge now
|
||||
</message>
|
||||
|
||||
</messages>
|
||||
</release>
|
||||
</grit>
|
||||
|
1
ash/ash_strings_grd/IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_FULLY_CHARGE_NOW_BUTTON_TEXT.png.sha1
Normal file
1
ash/ash_strings_grd/IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_FULLY_CHARGE_NOW_BUTTON_TEXT.png.sha1
Normal file
@ -0,0 +1 @@
|
||||
2a8b80e5f34c93fd91001855358d84f2a16802d4
|
1
ash/ash_strings_grd/IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_MESSAGE_INDEFINITE.png.sha1
Normal file
1
ash/ash_strings_grd/IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_MESSAGE_INDEFINITE.png.sha1
Normal file
@ -0,0 +1 @@
|
||||
d08545ab42b37cbf26202964438abbd2435b188f
|
@ -0,0 +1 @@
|
||||
2a8b80e5f34c93fd91001855358d84f2a16802d4
|
@ -0,0 +1 @@
|
||||
2a8b80e5f34c93fd91001855358d84f2a16802d4
|
@ -12,6 +12,7 @@ aggregate_vector_icons("ash_vector_icons") {
|
||||
icon_directory = "."
|
||||
|
||||
sources = [
|
||||
"adaptive_charging_battery.icon",
|
||||
"adaptive_charging_nudge_dark.icon",
|
||||
"adaptive_charging_nudge_light.icon",
|
||||
"add_cellular_network.icon",
|
||||
|
41
ash/resources/vector_icons/adaptive_charging_battery.icon
Normal file
41
ash/resources/vector_icons/adaptive_charging_battery.icon
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2022 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
CANVAS_DIMENSIONS, 20,
|
||||
R_MOVE_TO, 9.31f, 15.67f,
|
||||
R_LINE_TO, 2.76f, -5.52f,
|
||||
H_LINE_TO, 10.69f,
|
||||
V_LINE_TO, 6,
|
||||
R_LINE_TO, -2.76f, 5.52f,
|
||||
R_H_LINE_TO, 1.38f,
|
||||
R_V_LINE_TO, 4.14f,
|
||||
CLOSE,
|
||||
NEW_PATH,
|
||||
MOVE_TO, 12, 4.5f,
|
||||
R_H_LINE_TO, 1,
|
||||
R_CUBIC_TO, 0.5f, 0, 1, 0.5f, 1, 1,
|
||||
V_LINE_TO, 16,
|
||||
R_CUBIC_TO, 0, 0.5f, -0.5f, 1, -1, 1,
|
||||
H_LINE_TO, 7,
|
||||
R_CUBIC_TO, -0.5f, 0, -1, -0.5f, -1, -1,
|
||||
V_LINE_TO, 5.5f,
|
||||
R_CUBIC_TO, 0, -0.5f, 0.5f, -1, 1, -1,
|
||||
R_H_LINE_TO, 1,
|
||||
V_LINE_TO, 3,
|
||||
R_H_LINE_TO, 4,
|
||||
R_V_LINE_TO, 1.5f,
|
||||
CLOSE,
|
||||
R_MOVE_TO, -4.75f, 7.45f,
|
||||
R_ARC_TO, 0.8f, 0.8f, 0, 0, 1, -0.04f, -0.78f,
|
||||
R_LINE_TO, 2.76f, -5.52f,
|
||||
ARC_TO, 0.8f, 0.8f, 0, 0, 1, 11.49f, 6,
|
||||
R_V_LINE_TO, 3.34f,
|
||||
R_H_LINE_TO, 0.58f,
|
||||
R_ARC_TO, 0.8f, 0.8f, 0, 0, 1, 0.72f, 1.16f,
|
||||
R_LINE_TO, -2.76f, 5.52f,
|
||||
R_ARC_TO, 0.8f, 0.8f, 0, 0, 1, -1.51f, -0.36f,
|
||||
R_V_LINE_TO, -3.34f,
|
||||
R_H_LINE_TO, -0.58f,
|
||||
R_ARC_TO, 0.8f, 0.8f, 0, 0, 1, -0.68f, -0.38f,
|
||||
CLOSE
|
@ -0,0 +1,93 @@
|
||||
// Copyright 2022 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "ash/system/power/adaptive_charging_notification_controller.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ash/constants/ash_pref_names.h"
|
||||
#include "ash/public/cpp/notification_utils.h"
|
||||
#include "ash/resources/vector_icons/vector_icons.h"
|
||||
#include "ash/session/session_controller_impl.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/strings/grit/ash_strings.h"
|
||||
#include "base/i18n/time_formatting.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/message_center/message_center.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr char kNotifierId[] = "adaptive-charging-notify";
|
||||
constexpr char kInfoNotificationId[] = "adaptive-charging-notify-info";
|
||||
|
||||
} // namespace
|
||||
|
||||
AdaptiveChargingNotificationController::
|
||||
AdaptiveChargingNotificationController() = default;
|
||||
|
||||
AdaptiveChargingNotificationController::
|
||||
~AdaptiveChargingNotificationController() = default;
|
||||
|
||||
void AdaptiveChargingNotificationController::ShowAdaptiveChargingNotification(
|
||||
absl::optional<int> hours_to_full) {
|
||||
if (!ShouldShowNotification())
|
||||
return;
|
||||
|
||||
std::u16string notification_message;
|
||||
if (hours_to_full.has_value()) {
|
||||
DCHECK_GE(hours_to_full.value(), 0);
|
||||
notification_message = l10n_util::GetStringFUTF16(
|
||||
IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_MESSAGE_TEMPORARY,
|
||||
base::TimeFormatTimeOfDayWithHourClockType(
|
||||
base::Time::Now() + base::Hours(hours_to_full.value()),
|
||||
base::GetHourClockType(), base::kKeepAmPm));
|
||||
} else {
|
||||
notification_message = l10n_util::GetStringUTF16(
|
||||
IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_MESSAGE_INDEFINITE);
|
||||
}
|
||||
|
||||
message_center::RichNotificationData notification_data;
|
||||
notification_data.buttons.push_back(
|
||||
message_center::ButtonInfo(l10n_util::GetStringUTF16(
|
||||
IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_FULLY_CHARGE_NOW_BUTTON_TEXT)));
|
||||
auto notification = CreateSystemNotification(
|
||||
message_center::NOTIFICATION_TYPE_SIMPLE, kInfoNotificationId,
|
||||
l10n_util::GetStringUTF16(IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_TITLE),
|
||||
notification_message,
|
||||
/*display_source=*/std::u16string(), /*origin_url=*/GURL(),
|
||||
message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
|
||||
kNotifierId),
|
||||
notification_data,
|
||||
base::MakeRefCounted<message_center::ThunkNotificationDelegate>(
|
||||
weak_ptr_factory_.GetWeakPtr()),
|
||||
kAdaptiveChargingBatteryIcon,
|
||||
message_center::SystemNotificationWarningLevel::NORMAL);
|
||||
|
||||
if (hours_to_full.has_value())
|
||||
notification->set_priority(message_center::SYSTEM_PRIORITY);
|
||||
|
||||
message_center::MessageCenter::Get()->AddNotification(
|
||||
std::move(notification));
|
||||
}
|
||||
|
||||
bool AdaptiveChargingNotificationController::ShouldShowNotification() {
|
||||
PrefService* pref_service =
|
||||
Shell::Get()->session_controller()->GetActivePrefService();
|
||||
|
||||
return pref_service &&
|
||||
pref_service->GetBoolean(ash::prefs::kPowerAdaptiveChargingEnabled);
|
||||
}
|
||||
|
||||
void AdaptiveChargingNotificationController::Click(
|
||||
const absl::optional<int>& button_index,
|
||||
const absl::optional<std::u16string>& reply) {
|
||||
// TODO(b/216035329): Add logic to this function when "Charge now" function is
|
||||
// available.
|
||||
}
|
||||
|
||||
} // namespace ash
|
50
ash/system/power/adaptive_charging_notification_controller.h
Normal file
50
ash/system/power/adaptive_charging_notification_controller.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2022 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ASH_SYSTEM_POWER_ADAPTIVE_CHARGING_NOTIFICATION_CONTROLLER_H_
|
||||
#define ASH_SYSTEM_POWER_ADAPTIVE_CHARGING_NOTIFICATION_CONTROLLER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ash/ash_export.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
#include "ui/message_center/public/cpp/notification_delegate.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
class ASH_EXPORT AdaptiveChargingNotificationController
|
||||
: public message_center::NotificationObserver {
|
||||
public:
|
||||
AdaptiveChargingNotificationController();
|
||||
AdaptiveChargingNotificationController(
|
||||
const AdaptiveChargingNotificationController&) = delete;
|
||||
AdaptiveChargingNotificationController& operator=(
|
||||
const AdaptiveChargingNotificationController&) = delete;
|
||||
virtual ~AdaptiveChargingNotificationController();
|
||||
|
||||
// Show the adaptive charging notification. There are two possible
|
||||
// scenarios:
|
||||
// 1. When the battery is kept at 80% indefinitely (i.e. no value of
|
||||
// |hours_to_full| is provided), the notification is a
|
||||
// normal notification.
|
||||
// 2. When the battery is temporary kept at 80% (i.e. |hours_to_full| has
|
||||
// a value), the notification will have higher priority (SYSTEM_PRIORITY).
|
||||
void ShowAdaptiveChargingNotification(
|
||||
absl::optional<int> hours_to_full = absl::nullopt);
|
||||
|
||||
bool ShouldShowNotification();
|
||||
|
||||
// message_center::NotificationObserver:
|
||||
void Click(const absl::optional<int>& button_index,
|
||||
const absl::optional<std::u16string>& reply) override;
|
||||
|
||||
private:
|
||||
base::WeakPtrFactory<AdaptiveChargingNotificationController>
|
||||
weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace ash
|
||||
|
||||
#endif // ASH_SYSTEM_POWER_ADAPTIVE_CHARGING_NOTIFICATION_CONTROLLER_H_
|
@ -0,0 +1,120 @@
|
||||
// Copyright 2022 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "ash/system/power/adaptive_charging_notification_controller.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ash/constants/ash_pref_names.h"
|
||||
#include "ash/session/session_controller_impl.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/test/ash_test_base.h"
|
||||
#include "base/i18n/rtl.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/test/icu_test_util.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/time/time_override.h"
|
||||
#include "ui/message_center/message_center.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
namespace {
|
||||
|
||||
const base::Time::Exploded kTestDateTimeExploded = {
|
||||
2022, 4, 5, 29, // Fri, Apr 29, 2022
|
||||
2, 42, 7, 0 // 2:42:07.000 in UTC = 12:42:07 in Australia AEST.
|
||||
};
|
||||
|
||||
// Enables or disables the user pref for the entire feature.
|
||||
void SetAdaptiveChargingPref(bool enabled) {
|
||||
Shell::Get()->session_controller()->GetActivePrefService()->SetBoolean(
|
||||
prefs::kPowerAdaptiveChargingEnabled, enabled);
|
||||
base::RunLoop().RunUntilIdle();
|
||||
}
|
||||
|
||||
// Returns the number of (popup or non-popup) notifications that are currently
|
||||
// visible in the message center queue.
|
||||
size_t VisibleNotificationCount() {
|
||||
return message_center::MessageCenter::Get()->GetVisibleNotifications().size();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class AdaptiveChargingNotificationControllerTest : public AshTestBase {
|
||||
public:
|
||||
AdaptiveChargingNotificationControllerTest() = default;
|
||||
AdaptiveChargingNotificationControllerTest(
|
||||
const AdaptiveChargingNotificationControllerTest&) = delete;
|
||||
AdaptiveChargingNotificationControllerTest& operator=(
|
||||
const AdaptiveChargingNotificationControllerTest&) = delete;
|
||||
~AdaptiveChargingNotificationControllerTest() override = default;
|
||||
|
||||
// AshTestBase:
|
||||
void SetUp() override {
|
||||
AshTestBase::SetUp();
|
||||
controller_ = std::make_unique<AdaptiveChargingNotificationController>();
|
||||
}
|
||||
|
||||
AdaptiveChargingNotificationController* GetController() {
|
||||
return controller_.get();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<AdaptiveChargingNotificationController> controller_;
|
||||
};
|
||||
|
||||
TEST_F(AdaptiveChargingNotificationControllerTest, ShouldntShowNotification) {
|
||||
SetAdaptiveChargingPref(false);
|
||||
|
||||
GetController()->ShowAdaptiveChargingNotification();
|
||||
GetController()->ShowAdaptiveChargingNotification(5);
|
||||
|
||||
EXPECT_EQ(VisibleNotificationCount(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(AdaptiveChargingNotificationControllerTest, ShowNotificationWithHour) {
|
||||
SetAdaptiveChargingPref(true);
|
||||
GetController()->ShowAdaptiveChargingNotification(5);
|
||||
|
||||
EXPECT_EQ(VisibleNotificationCount(), 1u);
|
||||
}
|
||||
|
||||
TEST_F(AdaptiveChargingNotificationControllerTest,
|
||||
ShowNotificationWithoutHour) {
|
||||
SetAdaptiveChargingPref(true);
|
||||
GetController()->ShowAdaptiveChargingNotification();
|
||||
|
||||
EXPECT_EQ(VisibleNotificationCount(), 1u);
|
||||
}
|
||||
|
||||
TEST_F(AdaptiveChargingNotificationControllerTest, HaveTimeInNotification) {
|
||||
// Set default locale.
|
||||
base::test::ScopedRestoreICUDefaultLocale restore_locale;
|
||||
base::i18n::SetICUDefaultLocale("en_AU");
|
||||
base::test::ScopedRestoreDefaultTimezone sydney_time("Australia/Sydney");
|
||||
|
||||
// Override time for testing.
|
||||
base::subtle::ScopedTimeClockOverrides time_override(
|
||||
[]() {
|
||||
base::Time time;
|
||||
EXPECT_TRUE(base::Time::FromUTCExploded(kTestDateTimeExploded, &time));
|
||||
return time;
|
||||
},
|
||||
/*time_ticks_override=*/nullptr,
|
||||
/*thread_ticks_override=*/nullptr);
|
||||
|
||||
SetAdaptiveChargingPref(true);
|
||||
GetController()->ShowAdaptiveChargingNotification(5);
|
||||
|
||||
const message_center::Notification* notification =
|
||||
message_center::MessageCenter::Get()->FindPopupNotificationById(
|
||||
"adaptive-charging-notify-info");
|
||||
|
||||
ASSERT_TRUE(notification);
|
||||
|
||||
// Current local time is 12:42 pm, so 5 hours after should be 5:42 pm.
|
||||
EXPECT_NE(notification->message().find(u"5:42 pm"), std::u16string::npos);
|
||||
}
|
||||
|
||||
} // namespace ash
|
Reference in New Issue
Block a user