Skip to content

Commit

Permalink
[ash] Switch the theme on the login screen based on the focused pod
Browse files Browse the repository at this point in the history
Also switch the theme to light when the OOBE WebUI is shown

Bug: 1143060
Change-Id: If4e981e8b8ef65b80ee886300536c0f7f7d75534
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3565367
Reviewed-by: Min Chen <minch@chromium.org>
Reviewed-by: Toni Barzic <tbarzic@chromium.org>
Commit-Queue: Roman Sorokin <rsorokin@chromium.org>
Cr-Commit-Position: refs/heads/main@{#988877}
  • Loading branch information
Roman Sorokin authored and Chromium LUCI CQ committed Apr 5, 2022
1 parent 49b303f commit 5d61038
Show file tree
Hide file tree
Showing 11 changed files with 147 additions and 23 deletions.
4 changes: 4 additions & 0 deletions ash/login/login_screen_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "base/debug/alias.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/account_id/account_id.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/session_manager/session_manager_types.h"

Expand Down Expand Up @@ -182,18 +183,21 @@ bool LoginScreenController::GetSecurityTokenPinRequestCanceled() const {
}

void LoginScreenController::HardlockPod(const AccountId& account_id) {
GetModel()->NotifyFocusPod(account_id);
if (!client_)
return;
client_->HardlockPod(account_id);
}

void LoginScreenController::OnFocusPod(const AccountId& account_id) {
GetModel()->NotifyFocusPod(account_id);
if (!client_)
return;
client_->OnFocusPod(account_id);
}

void LoginScreenController::OnNoPodFocused() {
GetModel()->NotifyFocusPod(EmptyAccountId());
if (!client_)
return;
client_->OnNoPodFocused();
Expand Down
9 changes: 8 additions & 1 deletion ash/login/login_screen_controller_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,21 @@
#include "base/test/bind.h"
#include "components/prefs/pref_service.h"
#include "components/session_manager/session_manager_types.h"
#include "components/user_manager/known_user.h"

using session_manager::SessionState;
using ::testing::_;

namespace ash {

namespace {
using LoginScreenControllerTest = AshTestBase;
class LoginScreenControllerTest : public AshTestBase {
public:
LoginScreenControllerTest() {
user_manager::KnownUser::RegisterPrefs(local_state()->registry());
}
};

using LoginScreenControllerNoSessionTest = NoSessionAshTestBase;

// Enum instead of enum class, because it is used for indexing.
Expand Down
9 changes: 9 additions & 0 deletions ash/login/ui/login_data_dispatcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "ash/login/ui/login_data_dispatcher.h"
#include "ash/constants/ash_features.h"

class AccountId;

namespace ash {

LoginDataDispatcher::Observer::~Observer() = default;
Expand Down Expand Up @@ -105,6 +107,8 @@ void LoginDataDispatcher::Observer::OnFocusLeavingLockScreenApps(bool reverse) {
void LoginDataDispatcher::Observer::OnOobeDialogStateChanged(
OobeDialogState state) {}

void LoginDataDispatcher::Observer::OnFocusPod(const AccountId& account_id) {}

LoginDataDispatcher::LoginDataDispatcher() = default;

LoginDataDispatcher::~LoginDataDispatcher() = default;
Expand Down Expand Up @@ -284,4 +288,9 @@ void LoginDataDispatcher::NotifyOobeDialogState(OobeDialogState state) {
observer.OnOobeDialogStateChanged(state);
}

void LoginDataDispatcher::NotifyFocusPod(const AccountId& account_id) {
for (auto& observer : observers_)
observer.OnFocusPod(account_id);
}

} // namespace ash
8 changes: 8 additions & 0 deletions ash/login/ui/login_data_dispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include "base/observer_list.h"
#include "base/time/time.h"

class AccountId;

namespace ash {

// Provides access to data needed by the lock/login screen. The login UI will
Expand Down Expand Up @@ -155,6 +157,11 @@ class ASH_EXPORT LoginDataDispatcher : public LoginScreenModel {

// Called when the state of the OOBE dialog is changed.
virtual void OnOobeDialogStateChanged(OobeDialogState state);

// Called when the focused pod is changed on the login screen with the
// corresponding `account_id`. In case all the pods lost focus the
// `EmptyAccountId` passed as the argument.
virtual void OnFocusPod(const AccountId& account_id);
};

LoginDataDispatcher();
Expand Down Expand Up @@ -223,6 +230,7 @@ class ASH_EXPORT LoginDataDispatcher : public LoginScreenModel {
DetachableBasePairingStatus pairing_status);
void HandleFocusLeavingLockScreenApps(bool reverse) override;
void NotifyOobeDialogState(OobeDialogState state) override;
void NotifyFocusPod(const AccountId& account_id) override;

private:
base::ObserverList<Observer>::Unchecked observers_;
Expand Down
2 changes: 2 additions & 0 deletions ash/public/cpp/login_screen_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ class ASH_PUBLIC_EXPORT LoginScreenModel {
// as add user or powerwash.
virtual void NotifyOobeDialogState(OobeDialogState state) = 0;

virtual void NotifyFocusPod(const AccountId& account_id) = 0;

protected:
virtual ~LoginScreenModel();
};
Expand Down
73 changes: 65 additions & 8 deletions ash/style/ash_color_provider.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,25 @@
#include "ash/constants/ash_constants.h"
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/login/login_screen_controller.h"
#include "ash/login_status.h"
#include "ash/public/cpp/login_types.h"
#include "ash/public/cpp/style/color_mode_observer.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/wallpaper/wallpaper_controller_impl.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/string_number_conversions.h"
#include "components/account_id/account_id.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/session_manager/session_manager_types.h"
#include "components/user_manager/known_user.h"
#include "ui/chromeos/styles/cros_styles.h"
#include "ui/gfx/color_analysis.h"
#include "ui/gfx/color_utils.h"
Expand Down Expand Up @@ -115,8 +122,11 @@ AshColorProvider::AshColorProvider() {
g_instance = this;

// May be null in unit tests.
if (Shell::HasInstance())
if (Shell::HasInstance()) {
Shell::Get()->session_controller()->AddObserver(this);
Shell::Get()->login_screen_controller()->data_dispatcher()->AddObserver(
this);
}

cros_styles::SetDebugColorsEnabled(base::FeatureList::IsEnabled(
ash::features::kSemanticColorsDebugOverride));
Expand All @@ -127,8 +137,16 @@ AshColorProvider::~AshColorProvider() {
g_instance = nullptr;

// May be null in unit tests.
if (Shell::HasInstance())
if (Shell::HasInstance()) {
Shell::Get()->session_controller()->RemoveObserver(this);
if (Shell::Get()->login_screen_controller() &&
Shell::Get()->login_screen_controller()->data_dispatcher()) {
Shell::Get()
->login_screen_controller()
->data_dispatcher()
->RemoveObserver(this);
}
}

cros_styles::SetDebugColorsEnabled(false);
cros_styles::SetDarkModeEnabled(false);
Expand Down Expand Up @@ -272,12 +290,19 @@ bool AshColorProvider::IsDarkModeEnabled() const {
if (!features::IsDarkLightModeEnabled() && override_light_mode_as_default_)
return false;

// Keep colors in OOBE as LIGHT when D/L is enabled. When the feature is
// disabled, lots of colors are hard coded in OOBE for now.
if (features::IsDarkLightModeEnabled() &&
Shell::Get()->session_controller()->GetSessionState() ==
session_manager::SessionState::OOBE) {
return false;
if (features::IsDarkLightModeEnabled()) {
// Always use the LIGHT theme when OOBE WebUI is show (either as out-of-box
// or the WebUI dialog on the login screen). Lots of colors are hard coded
// in OOBE WebUI for now.
if (is_oobe_webui_shown_)
return false;

// On the login screen use the preference of the focused pod's user if they
// had the preference stored in the known_user and the pod is focused.
if (!active_user_pref_service_ &&
is_dark_mode_enabled_for_focused_pod_.has_value()) {
return is_dark_mode_enabled_for_focused_pod_.value();
}
}

// Keep the color mode as DARK in login screen or when dark/light mode feature
Expand All @@ -294,6 +319,23 @@ void AshColorProvider::SetDarkModeEnabledForTest(bool enabled) {
}
}

void AshColorProvider::OnOobeDialogStateChanged(OobeDialogState state) {
auto closure = GetNotifyOnDarkModeChangeClosure();
is_oobe_webui_shown_ = state != OobeDialogState::HIDDEN;
}

void AshColorProvider::OnFocusPod(const AccountId& account_id) {
auto closure = GetNotifyOnDarkModeChangeClosure();

if (!account_id.is_valid()) {
is_dark_mode_enabled_for_focused_pod_.reset();
return;
}
is_dark_mode_enabled_for_focused_pod_ =
user_manager::KnownUser(ash::Shell::Get()->local_state())
.FindBoolPath(account_id, prefs::kDarkModeEnabled);
}

bool AshColorProvider::IsThemed() const {
if (!active_user_pref_service_)
return kDefaultColorModeThemed;
Expand Down Expand Up @@ -501,4 +543,19 @@ void AshColorProvider::NotifyColorModeThemedPrefChange() {
NotifyColorModeAndThemeChanges(IsDarkModeEnabled());
}

base::ScopedClosureRunner AshColorProvider::GetNotifyOnDarkModeChangeClosure() {
return base::ScopedClosureRunner(
// Unretained is safe here because GetNotifyOnDarkModeChangeClosure is a
// private function and callback should be called on going out of scope of
// the calling method.
base::BindOnce(&AshColorProvider::NotifyIfDarkModeChanged,
base::Unretained(this), IsDarkModeEnabled()));
}

void AshColorProvider::NotifyIfDarkModeChanged(bool old_is_dark_mode_enabled) {
if (old_is_dark_mode_enabled == IsDarkModeEnabled())
return;
NotifyDarkModeEnabledPrefChange();
}

} // namespace ash
21 changes: 20 additions & 1 deletion ash/style/ash_color_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
#define ASH_STYLE_ASH_COLOR_PROVIDER_H_

#include "ash/ash_export.h"
#include "ash/login/ui/login_data_dispatcher.h"
#include "ash/public/cpp/session/session_observer.h"
#include "ash/public/cpp/style/color_provider.h"
#include "base/callback_helpers.h"
#include "base/observer_list.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/color_palette.h"

class AccountId;
class PrefChangeRegistrar;
class PrefRegistrySimple;
class PrefService;
Expand All @@ -30,7 +33,8 @@ class ColorModeObserver;
// the UI elements, e.g., separator, text, icon. The color of an element in
// system UI will be the combination of the colors of the four layers.
class ASH_EXPORT AshColorProvider : public SessionObserver,
public ColorProvider {
public ColorProvider,
public LoginDataDispatcher::Observer {
public:
AshColorProvider();
AshColorProvider(const AshColorProvider& other) = delete;
Expand Down Expand Up @@ -68,6 +72,10 @@ class ASH_EXPORT AshColorProvider : public SessionObserver,
bool IsDarkModeEnabled() const override;
void SetDarkModeEnabledForTest(bool enabled) override;

// LoginDataDispatcher::Observer:
void OnOobeDialogStateChanged(OobeDialogState state) override;
void OnFocusPod(const AccountId& account_id) override;

// Gets the color of |type| of the corresponding layer based on the current
// inverted color mode. For views that need LIGHT colors while DARK mode is
// active, and vice versa.
Expand Down Expand Up @@ -134,6 +142,11 @@ class ASH_EXPORT AshColorProvider : public SessionObserver,
// Notifies all the observers on |kColorModeThemed|'s change.
void NotifyColorModeThemedPrefChange();

// Returns a closure which calls `NotifyIfDarkModeChanged` if the dark mode
// changed between creation and getting out of scope.
base::ScopedClosureRunner GetNotifyOnDarkModeChangeClosure();
void NotifyIfDarkModeChanged(bool old_is_dark_mode_enabled);

// The default color is DARK when the DarkLightMode feature is disabled. But
// we can also override it to LIGHT through ScopedLightModeAsDefault. This is
// done to help keeping some of the UI elements as LIGHT by default before
Expand All @@ -142,6 +155,12 @@ class ASH_EXPORT AshColorProvider : public SessionObserver,
// DarkLightMode feature.
bool override_light_mode_as_default_ = false;

// True if we're in the OOBE state or OOBE WebUI dialog is open (e.g. for the
// "Add person" flow).
bool is_oobe_webui_shown_ = false;
// absl::nullopt in case no user pod is focused.
absl::optional<bool> is_dark_mode_enabled_for_focused_pod_;

base::ObserverList<ColorModeObserver> observers_;
std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
PrefService* active_user_pref_service_ = nullptr; // Not owned.
Expand Down
14 changes: 13 additions & 1 deletion ash/style/ash_color_provider_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/login/ui/login_test_base.h"
#include "ash/public/cpp/login_types.h"
#include "ash/style/ash_color_provider.h"

#include "ash/session/test_session_controller_client.h"
Expand All @@ -11,7 +13,7 @@

namespace ash {

using AshColorProviderTest = AshTestBase;
using AshColorProviderTest = LoginTestBase;

// Tests the color mode in non-active user sessions.
TEST_F(AshColorProviderTest, ColorModeInNonActiveUserSessions) {
Expand All @@ -24,7 +26,16 @@ TEST_F(AshColorProviderTest, ColorModeInNonActiveUserSessions) {
enable_dark_light.InitAndEnableFeature(chromeos::features::kDarkLightMode);
client->SetSessionState(session_manager::SessionState::UNKNOWN);
EXPECT_TRUE(color_provider->IsDarkModeEnabled());

client->SetSessionState(session_manager::SessionState::OOBE);
DataDispatcher()->NotifyOobeDialogState(OobeDialogState::USER_CREATION);
EXPECT_FALSE(color_provider->IsDarkModeEnabled());

client->SetSessionState(session_manager::SessionState::LOGIN_PRIMARY);
DataDispatcher()->NotifyOobeDialogState(OobeDialogState::HIDDEN);
EXPECT_TRUE(color_provider->IsDarkModeEnabled());

DataDispatcher()->NotifyOobeDialogState(OobeDialogState::GAIA_SIGNIN);
EXPECT_FALSE(color_provider->IsDarkModeEnabled());

// When dark/light mode is disabled. Color mode in non-active user sessions
Expand All @@ -34,6 +45,7 @@ TEST_F(AshColorProviderTest, ColorModeInNonActiveUserSessions) {
client->SetSessionState(session_manager::SessionState::UNKNOWN);
EXPECT_TRUE(color_provider->IsDarkModeEnabled());
client->SetSessionState(session_manager::SessionState::OOBE);
DataDispatcher()->NotifyOobeDialogState(OobeDialogState::USER_CREATION);
EXPECT_TRUE(color_provider->IsDarkModeEnabled());
}

Expand Down

0 comments on commit 5d61038

Please sign in to comment.