Commit d2fd6104 authored by Ahmed Fakhry's avatar Ahmed Fakhry Committed by Commit Bot

Auto Night Light

When this feature is enabled, and the user has never changed the
schedule on the device, NL is set automatically to follow a
sunset-to-sunrise schedule.
We also show a notification when NL changes status because of Auto
Night Light. This notification is never shown again once the user
interacts with it (by closing it, or clicking on it).

This feature is not exposed to the end user, and only enabled by
the session manager on some devices based on their cros-config.

BUG=1026871
TEST=ash_unittests --gtest_filter=*AutoNightLight*

Change-Id: Ia15cd94d7c6a4c5fa30413f526282f713b9ba395
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1927987
Commit-Queue: Ahmed Fakhry <afakhry@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#719304}
parent e2fc6c71
......@@ -1564,6 +1564,15 @@ This file contains the strings for ash.
Yes
</message>
<message name="IDS_ASH_AUTO_NIGHT_LIGHT_NOTIFY_TITLE" desc="The title of the notification shown when Night Light turns on automatically when the auto-night-light feature is enabled.">
Night Light turns on automatically at sunset
</message>
<message name="IDS_ASH_AUTO_NIGHT_LIGHT_NOTIFY_BODY" desc="The body of the notification shown when Night Light turns on automatically when the auto-night-light feature is enabled.">
Night Light makes it easier to look at your screen or read in dim light. Tap to change this.
</message>
<message name="IDS_ASH_AUTO_NIGHT_LIGHT_NOTIFY_BUTTON_TEXT" desc="The text of the button on the notification shown when Night Light turns on automatically when the auto-night-light feature is enabled.">
Turn off for tonight
</message>
<message name="IDS_ASH_IME_MENU_ACCESSIBLE_NAME" desc="The accessible text for opt-in IME menu icon in status tray.">
IME menu button
......
0915488a55a496555dd9edef85ef3c9de0c38888
\ No newline at end of file
0915488a55a496555dd9edef85ef3c9de0c38888
\ No newline at end of file
0915488a55a496555dd9edef85ef3c9de0c38888
\ No newline at end of file
......@@ -14,6 +14,9 @@ namespace features {
const base::Feature kAllowAmbientEQ{"AllowAmbientEQ",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kAutoNightLight{"AutoNightLight",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kDockedMagnifier{"DockedMagnifier",
base::FEATURE_ENABLED_BY_DEFAULT};
......@@ -107,6 +110,10 @@ bool IsAllowAmbientEQEnabled() {
return base::FeatureList::IsEnabled(kAllowAmbientEQ);
}
bool IsAutoNightLightEnabled() {
return base::FeatureList::IsEnabled(kAutoNightLight);
}
bool IsHideArcMediaNotificationsEnabled() {
return base::FeatureList::IsEnabled(kMediaSessionNotification) &&
base::FeatureList::IsEnabled(kHideArcMediaNotifications);
......
......@@ -15,6 +15,12 @@ namespace features {
// See https://crbug.com/1021193 for more details.
ASH_PUBLIC_EXPORT extern const base::Feature kAllowAmbientEQ;
// Enables the Auto Night Light feature which sets the default schedule type to
// sunset-to-sunrise until the user changes it to something else. This feature
// is not exposed to the end user, and is enabled only via cros_config for
// certain devices.
ASH_PUBLIC_EXPORT extern const base::Feature kAutoNightLight;
// Enables the docked (a.k.a. picture-in-picture) magnifier.
// TODO(afakhry): Remove this after the feature is fully launched.
// https://crbug.com/709824.
......@@ -135,6 +141,8 @@ ASH_PUBLIC_EXPORT extern const base::Feature kDragFromShelfToHomeOrOverview;
ASH_PUBLIC_EXPORT bool IsAllowAmbientEQEnabled();
ASH_PUBLIC_EXPORT bool IsAutoNightLightEnabled();
ASH_PUBLIC_EXPORT bool IsHideArcMediaNotificationsEnabled();
ASH_PUBLIC_EXPORT bool IsKeyboardShortcutViewerAppEnabled();
......
......@@ -232,6 +232,11 @@ const char kNightLightCustomEndTime[] = "ash.night_light.custom_end_time";
const char kNightLightCachedLatitude[] = "ash.night_light.cached_latitude";
const char kNightLightCachedLongitude[] = "ash.night_light.cached_longitude";
// A boolean pref storing whether the AutoNightLight notification has ever been
// dismissed by the user, which we use to stop showing it again.
const char kAutoNightLightNotificationDismissed[] =
"ash.auto_night_light.notification_dismissed";
// Whether the Chrome OS lock screen is allowed.
const char kAllowScreenLock[] = "allow_screen_lock";
......
......@@ -90,6 +90,7 @@ ASH_PUBLIC_EXPORT extern const char kNightLightCustomStartTime[];
ASH_PUBLIC_EXPORT extern const char kNightLightCustomEndTime[];
ASH_PUBLIC_EXPORT extern const char kNightLightCachedLatitude[];
ASH_PUBLIC_EXPORT extern const char kNightLightCachedLongitude[];
ASH_PUBLIC_EXPORT extern const char kAutoNightLightNotificationDismissed[];
ASH_PUBLIC_EXPORT extern const char kAllowScreenLock[];
ASH_PUBLIC_EXPORT extern const char kEnableAutoScreenLock[];
......
......@@ -9,10 +9,16 @@
#include "ash/display/display_color_manager.h"
#include "ash/display/window_tree_host_manager.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/ash_pref_names.h"
#include "ash/public/cpp/ash_switches.h"
#include "ash/public/cpp/notification_utils.h"
#include "ash/public/cpp/system_tray_client.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 "ash/system/model/system_tray_model.h"
#include "base/bind.h"
#include "base/i18n/time_formatting.h"
#include "base/logging.h"
......@@ -25,6 +31,7 @@
#include "third_party/icu/source/i18n/astro.h"
#include "ui/aura/env.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
......@@ -35,11 +42,17 @@
#include "ui/gfx/animation/animation_delegate.h"
#include "ui/gfx/animation/linear_animation.h"
#include "ui/gfx/geometry/vector3d_f.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/public/cpp/notification.h"
namespace ash {
namespace {
// Auto Night Light notification IDs.
constexpr char kNotifierId[] = "ash.night_light_controller_impl";
constexpr char kNotificationId[] = "ash.auto_night_light_notify";
// Default start time at 6:00 PM as an offset from 00:00.
constexpr int kDefaultStartTimeOffsetMinutes = 18 * 60;
......@@ -318,7 +331,8 @@ class ColorTemperatureAnimation : public gfx::LinearAnimation,
NightLightControllerImpl::NightLightControllerImpl()
: delegate_(std::make_unique<NightLightControllerDelegateImpl>()),
temperature_animation_(std::make_unique<ColorTemperatureAnimation>()) {
temperature_animation_(std::make_unique<ColorTemperatureAnimation>()),
weak_ptr_factory_(this) {
Shell::Get()->session_controller()->AddObserver(this);
Shell::Get()->window_tree_host_manager()->AddObserver(this);
aura::Env::GetInstance()->AddObserver(this);
......@@ -338,13 +352,18 @@ void NightLightControllerImpl::RegisterProfilePrefs(
registry->RegisterBooleanPref(prefs::kNightLightEnabled, false);
registry->RegisterDoublePref(prefs::kNightLightTemperature,
kDefaultColorTemperature);
const ScheduleType default_schedule_type =
features::IsAutoNightLightEnabled() ? ScheduleType::kSunsetToSunrise
: ScheduleType::kNone;
registry->RegisterIntegerPref(prefs::kNightLightScheduleType,
static_cast<int>(ScheduleType::kNone));
static_cast<int>(default_schedule_type));
registry->RegisterIntegerPref(prefs::kNightLightCustomStartTime,
kDefaultStartTimeOffsetMinutes);
registry->RegisterIntegerPref(prefs::kNightLightCustomEndTime,
kDefaultEndTimeOffsetMinutes);
registry->RegisterBooleanPref(prefs::kAmbientColorEnabled, false);
registry->RegisterBooleanPref(prefs::kAutoNightLightNotificationDismissed,
false);
// Non-public prefs, only meant to be used by ash.
registry->RegisterDoublePref(prefs::kNightLightCachedLatitude, 0.0);
......@@ -548,6 +567,9 @@ void NightLightControllerImpl::OnHostInitialized(aura::WindowTreeHost* host) {
void NightLightControllerImpl::OnActiveUserPrefServiceChanged(
PrefService* pref_service) {
if (pref_service == active_user_pref_service_)
return;
// TODO(afakhry|yjliu): Remove this VLOG when https://crbug.com/1015474 is
// fixed.
auto vlog_helper = [](const PrefService* pref_service) -> std::string {
......@@ -590,11 +612,96 @@ void NightLightControllerImpl::SuspendDone(
Refresh(true /* did_schedule_change */);
}
void NightLightControllerImpl::Close(bool by_user) {
if (by_user)
DisableShowingFutureAutoNightLightNotification();
}
void NightLightControllerImpl::Click(
const base::Optional<int>& button_index,
const base::Optional<base::string16>& reply) {
auto* shell = Shell::Get();
if (!button_index.has_value()) {
// Body has been clicked.
SystemTrayClient* tray_client = shell->system_tray_model()->client();
auto* session_controller = shell->session_controller();
if (session_controller->ShouldEnableSettings() && tray_client)
tray_client->ShowDisplaySettings();
} else {
DCHECK_EQ(0, *button_index);
SetEnabled(false, AnimationDuration::kShort);
}
message_center::MessageCenter::Get()->RemoveNotification(kNotificationId,
/*by_user=*/true);
// Closing the notification with `by_user=true` above should end up calling
// NightLightControllerImpl::Close() which will disable showing the
// notification any further.
DCHECK(UserHasEverDismissedAutoNightLightNotification());
}
void NightLightControllerImpl::SetDelegateForTesting(
std::unique_ptr<Delegate> delegate) {
delegate_ = std::move(delegate);
}
message_center::Notification*
NightLightControllerImpl::GetAutoNightLightNotificationForTesting() const {
return message_center::MessageCenter::Get()->FindVisibleNotificationById(
kNotificationId);
}
bool NightLightControllerImpl::UserHasEverChangedSchedule() const {
return active_user_pref_service_ &&
active_user_pref_service_->HasPrefPath(prefs::kNightLightScheduleType);
}
bool NightLightControllerImpl::UserHasEverDismissedAutoNightLightNotification()
const {
return active_user_pref_service_ &&
active_user_pref_service_->GetBoolean(
prefs::kAutoNightLightNotificationDismissed);
}
void NightLightControllerImpl::ShowAutoNightLightNotification() {
DCHECK(features::IsAutoNightLightEnabled());
DCHECK(GetEnabled());
DCHECK(!UserHasEverDismissedAutoNightLightNotification());
DCHECK_EQ(ScheduleType::kSunsetToSunrise, GetScheduleType());
message_center::RichNotificationData data;
data.buttons.push_back(message_center::ButtonInfo(
l10n_util::GetStringUTF16(IDS_ASH_AUTO_NIGHT_LIGHT_NOTIFY_BUTTON_TEXT)));
std::unique_ptr<message_center::Notification> notification =
ash::CreateSystemNotification(
message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId,
l10n_util::GetStringUTF16(IDS_ASH_AUTO_NIGHT_LIGHT_NOTIFY_TITLE),
l10n_util::GetStringUTF16(IDS_ASH_AUTO_NIGHT_LIGHT_NOTIFY_BODY),
base::string16(), GURL(),
message_center::NotifierId(
message_center::NotifierType::SYSTEM_COMPONENT, kNotifierId),
data,
base::MakeRefCounted<message_center::ThunkNotificationDelegate>(
weak_ptr_factory_.GetWeakPtr()),
kUnifiedMenuNightLightIcon,
message_center::SystemNotificationWarningLevel::NORMAL);
notification->set_priority(message_center::SYSTEM_PRIORITY);
message_center::MessageCenter::Get()->AddNotification(
std::move(notification));
}
void NightLightControllerImpl::
DisableShowingFutureAutoNightLightNotification() {
if (Shell::Get()->session_controller()->IsUserSessionBlocked())
return;
if (active_user_pref_service_) {
active_user_pref_service_->SetBoolean(
prefs::kAutoNightLightNotificationDismissed, true);
}
}
void NightLightControllerImpl::LoadCachedGeopositionIfNeeded() {
DCHECK(active_user_pref_service_);
......@@ -699,6 +806,7 @@ void NightLightControllerImpl::InitFromUserPrefs() {
Refresh(true /* did_schedule_change */);
NotifyStatusChanged();
NotifyClientWithScheduleChange();
is_first_user_init_ = false;
}
void NightLightControllerImpl::NotifyStatusChanged() {
......@@ -712,8 +820,20 @@ void NightLightControllerImpl::NotifyClientWithScheduleChange() {
}
void NightLightControllerImpl::OnEnabledPrefChanged() {
VLOG(1) << "Enable state changed. New state: " << GetEnabled() << ".";
const bool enabled = GetEnabled();
VLOG(1) << "Enable state changed. New state: " << enabled << ".";
DCHECK(active_user_pref_service_);
if (enabled && features::IsAutoNightLightEnabled() &&
GetScheduleType() == kSunsetToSunrise &&
(is_first_user_init_ ||
animation_duration_ == AnimationDuration::kLong) &&
!UserHasEverChangedSchedule() &&
!UserHasEverDismissedAutoNightLightNotification()) {
VLOG(1) << "Auto Night Light is turning on.";
ShowAutoNightLightNotification();
}
Refresh(false /* did_schedule_change */);
NotifyStatusChanged();
}
......
......@@ -12,15 +12,21 @@
#include "ash/public/cpp/night_light_controller.h"
#include "ash/session/session_observer.h"
#include "ash/system/night_light/time_of_day.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "components/prefs/pref_change_registrar.h"
#include "ui/aura/env_observer.h"
#include "ui/message_center/public/cpp/notification_delegate.h"
class PrefRegistrySimple;
class PrefService;
namespace message_center {
class Notification;
} // namespace message_center
namespace ash {
class ColorTemperatureAnimation;
......@@ -39,7 +45,8 @@ class ASH_EXPORT NightLightControllerImpl
public WindowTreeHostManager::Observer,
public aura::EnvObserver,
public SessionObserver,
public chromeos::PowerManagerClient::Observer {
public chromeos::PowerManagerClient::Observer,
public message_center::NotificationObserver {
public:
enum class AnimationDuration {
// Short animation (2 seconds) used for manual changes of NightLight status
......@@ -162,9 +169,33 @@ class ASH_EXPORT NightLightControllerImpl
// chromeos::PowerManagerClient::Observer:
void SuspendDone(const base::TimeDelta& sleep_duration) override;
// message_center::NotificationObserver:
void Close(bool by_user) override;
void Click(const base::Optional<int>& button_index,
const base::Optional<base::string16>& reply) override;
void SetDelegateForTesting(std::unique_ptr<Delegate> delegate);
// Returns the Auto Night Light notification if any is currently shown, or
// nullptr.
message_center::Notification* GetAutoNightLightNotificationForTesting() const;
private:
// Returns true if the user has ever changed the schedule type, which means we
// must respect the user's choice and let it overwrite Auto Night Light.
bool UserHasEverChangedSchedule() const;
// Returns true if the user has ever dismissed the Auto Night Light
// notification, in which case we never show it again.
bool UserHasEverDismissedAutoNightLightNotification() const;
// Shows the notification informing the user that Night Light has been turned
// on from sunset-to-sunrise as a result of Auto Night Light.
void ShowAutoNightLightNotification();
// Disables showing the Auto Night Light from now on.
void DisableShowingFutureAutoNightLightNotification();
// Called only when the active user changes in order to see if we need to use
// a previously cached geoposition value from the active user's prefs.
void LoadCachedGeopositionIfNeeded();
......@@ -242,6 +273,10 @@ class ASH_EXPORT NightLightControllerImpl
// type is either kSunsetToSunrise or kCustom.
base::OneShotTimer timer_;
// True only until Night Light is initialized from the very first user
// session. After that, it is set to false.
bool is_first_user_init_ = true;
// True if the current geoposition value used by the Delegate is from a
// previously cached value in the user prefs of any of the users in the
// current session. It is reset to false once we receive a newly-updated
......@@ -257,6 +292,8 @@ class ASH_EXPORT NightLightControllerImpl
// controlled by this class from the WebUI settings.
std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
base::WeakPtrFactory<NightLightControllerImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(NightLightControllerImpl);
};
......
......@@ -9,6 +9,7 @@
#include "ash/display/cursor_window_controller.h"
#include "ash/display/window_tree_host_manager.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/ash_pref_names.h"
#include "ash/public/cpp/session/session_types.h"
#include "ash/root_window_controller.h"
......@@ -24,7 +25,9 @@
#include "base/command_line.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/optional.h"
#include "base/strings/pattern.h"
#include "base/test/scoped_feature_list.h"
#include "components/prefs/pref_service.h"
#include "ui/compositor/layer.h"
#include "ui/display/fake/fake_display_snapshot.h"
......@@ -33,6 +36,7 @@
#include "ui/display/manager/test/action_logger_util.h"
#include "ui/display/manager/test/test_native_display_delegate.h"
#include "ui/gfx/geometry/vector3d_f.h"
#include "ui/message_center/public/cpp/notification.h"
namespace ash {
......@@ -145,7 +149,7 @@ class TestDelegate : public NightLightControllerImpl::Delegate {
class NightLightTest : public NoSessionAshTestBase {
public:
NightLightTest() = default;
NightLightTest() : delegate_(new TestDelegate) {}
~NightLightTest() override = default;
PrefService* user1_pref_service() {
......@@ -163,13 +167,12 @@ class NightLightTest : public NoSessionAshTestBase {
// AshTestBase:
void SetUp() override {
NoSessionAshTestBase::SetUp();
GetController()->SetDelegateForTesting(base::WrapUnique(delegate_));
CreateTestUserSessions();
// Simulate user 1 login.
SwitchActiveUser(kUser1Email);
delegate_ = new TestDelegate;
GetController()->SetDelegateForTesting(base::WrapUnique(delegate_));
}
void CreateTestUserSessions() {
......@@ -189,7 +192,7 @@ class NightLightTest : public NoSessionAshTestBase {
}
private:
TestDelegate* delegate_ = nullptr;
TestDelegate* delegate_ = nullptr; // Not owned.
DISALLOW_COPY_AND_ASSIGN(NightLightTest);
};
......@@ -1326,6 +1329,144 @@ TEST(AmbientTemperature, AmbientTemperatureToRGBScaleFactors) {
allowed_difference);
}
class AutoNightLightTest : public NightLightTest {
public:
AutoNightLightTest() = default;
~AutoNightLightTest() override = default;
AutoNightLightTest(const AutoNightLightTest& other) = delete;
AutoNightLightTest& operator=(const AutoNightLightTest& rhs) = delete;
// NightLightTest:
void SetUp() override {
scoped_feature_list_.InitAndEnableFeature(features::kAutoNightLight);
delegate()->SetFakeNow(TimeOfDay(fake_now_));
delegate()->SetFakeSunset(TimeOfDay(20 * 60)); // 8:00 PM.
delegate()->SetFakeSunrise(TimeOfDay(5 * 60)); // 5:00 AM.
NightLightTest::SetUp();
}
protected:
// Now is at 4 PM.
//
// 16:00 20:00 5:00
// <----- + ----------------- + ----------------------- + ------->
// | | |
// now sunset sunrise
//
int fake_now_ = 16 * 60; // 4:00 PM.
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(AutoNightLightTest, Notification) {
// Unblock the user session in order to be able to stop showing the Auto Night
// Light notification.
GetSessionControllerClient()->UnlockScreen();
// Since Auto Night Light is enabled, the schedule should be automatically set
// to sunset-to-sunrise, even though the user never set that pref.
NightLightControllerImpl* controller = GetController();
EXPECT_EQ(NightLightController::kSunsetToSunrise,
controller->GetScheduleType());
EXPECT_FALSE(
user1_pref_service()->HasPrefPath(prefs::kNightLightScheduleType));
// Simulate reaching sunset.
delegate()->SetFakeNow(TimeOfDay(20 * 60)); // Now is 8:00 PM.
controller->timer()->FireNow();
EXPECT_TRUE(controller->GetEnabled());
auto* notification = controller->GetAutoNightLightNotificationForTesting();
ASSERT_TRUE(notification);
ASSERT_TRUE(notification->delegate());
// Simulate the user clicking the notification button, Night Light should now
// be disabled, and the notification should be dismissed.
notification->delegate()->Click(base::make_optional<int>(0), base::nullopt);
EXPECT_FALSE(controller->GetEnabled());
EXPECT_FALSE(controller->GetAutoNightLightNotificationForTesting());
// Simulate reaching next sunset. The notification should no longer show.
delegate()->SetFakeNow(TimeOfDay(20 * 60)); // Now is 8:00 PM.
controller->timer()->FireNow();
EXPECT_TRUE(controller->GetEnabled());
EXPECT_FALSE(controller->GetAutoNightLightNotificationForTesting());
}
TEST_F(AutoNightLightTest, CannotDisableNotificationWhenSessionIsBlocked) {
EXPECT_TRUE(Shell::Get()->session_controller()->IsUserSessionBlocked());
// Simulate reaching sunset.
NightLightControllerImpl* controller = GetController();
delegate()->SetFakeNow(TimeOfDay(20 * 60)); // Now is 8:00 PM.
controller->timer()->FireNow();
EXPECT_TRUE(controller->GetEnabled());
auto* notification = controller->GetAutoNightLightNotificationForTesting();
ASSERT_TRUE(notification);
ASSERT_TRUE(notification->delegate());
// Simulate user closing the notification.
notification->delegate()->Close(/*by_user=*/true);
EXPECT_FALSE(user1_pref_service()->GetBoolean(
prefs::kAutoNightLightNotificationDismissed));
}
TEST_F(AutoNightLightTest, OverriddenByUser) {
// Once the user sets the schedule to anything, even sunset-to-sunrise, the
// auto-night light will never show.
NightLightControllerImpl* controller = GetController();
controller->SetScheduleType(NightLightController::kSunsetToSunrise);
// Simulate reaching sunset.
delegate()->SetFakeNow(TimeOfDay(20 * 60)); // Now is 8:00 PM.
controller->timer()->FireNow();
EXPECT_TRUE(controller->GetEnabled());
EXPECT_FALSE(controller->GetAutoNightLightNotificationForTesting());
}
TEST_F(AutoNightLightTest, NoNotificationWhenManuallyEnabledFromSettings) {
NightLightControllerImpl* controller = GetController();
EXPECT_FALSE(controller->GetEnabled());
user1_pref_service()->SetBoolean(prefs::kNightLightEnabled, true);
EXPECT_TRUE(controller->GetEnabled());
EXPECT_FALSE(controller->GetAutoNightLightNotificationForTesting());
}
TEST_F(AutoNightLightTest, NoNotificationWhenManuallyEnabledFromSystemMenu) {
NightLightControllerImpl* controller = GetController();
EXPECT_FALSE(controller->GetEnabled());
controller->Toggle();
EXPECT_TRUE(controller->GetEnabled());
EXPECT_FALSE(controller->GetAutoNightLightNotificationForTesting());
}
// Now is at 11 PM.
//
// 20:00 23:00 5:00
// <----- + ----------------- + ----------------------- + ------->
// | | |
// sunset now sunrise
//
// Tests that when the user logs in for the first time between sunset and
// sunrise with Auto Night Light enabled, and the notification has never been
// dismissed before, the notification should be shown.
class AutoNightLightOnFirstLogin : public AutoNightLightTest {
public:
AutoNightLightOnFirstLogin() { fake_now_ = 23 * 60; }
~AutoNightLightOnFirstLogin() override = default;
AutoNightLightOnFirstLogin(const AutoNightLightOnFirstLogin& other) = delete;
AutoNightLightOnFirstLogin& operator=(const AutoNightLightOnFirstLogin& rhs) =
delete;
};
TEST_F(AutoNightLightOnFirstLogin, NotifyOnFirstLogin) {
NightLightControllerImpl* controller = GetController();
EXPECT_TRUE(controller->GetEnabled());
EXPECT_TRUE(controller->GetAutoNightLightNotificationForTesting());
}
} // namespace
} // namespace ash
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment