Commit 308923f3 authored by minch's avatar minch Committed by Commit Bot

dark_mode: Syncable dark/light mode switcher.

Add the logic for syncable dark/light switcher. Enable/Disable the dark
mode through the feature pod in system tray will update the preference
for this user on other devices too.
Login screen will be done in a follow up cl.

Bug: 1106012
Change-Id: Idbbc3f5652effdc7590713fc5687e031e3d97dac
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2373134
Commit-Queue: Min Chen <minch@chromium.org>
Reviewed-by: default avatarAhmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#802737}
parent 814a27f8
......@@ -903,6 +903,7 @@ component("ash") {
"system/cast/tray_cast.h",
"system/cast/unified_cast_detailed_view_controller.cc",
"system/cast/unified_cast_detailed_view_controller.h",
"system/dark_mode/color_mode_observer.h",
"system/dark_mode/dark_mode_detailed_view.cc",
"system/dark_mode/dark_mode_detailed_view.h",
"system/dark_mode/dark_mode_detailed_view_controller.cc",
......
......@@ -20,6 +20,7 @@
#include "ash/public/cpp/ash_pref_names.h"
#include "ash/shelf/contextual_tooltip.h"
#include "ash/shelf/shelf_controller.h"
#include "ash/style/ash_color_provider.h"
#include "ash/system/bluetooth/bluetooth_power_controller.h"
#include "ash/system/caps_lock_notification_controller.h"
#include "ash/system/gesture_education/gesture_education_notification_controller.h"
......@@ -47,6 +48,7 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry, bool for_test) {
AccessibilityControllerImpl::RegisterProfilePrefs(registry);
AppListControllerImpl::RegisterProfilePrefs(registry);
AssistantControllerImpl::RegisterProfilePrefs(registry);
AshColorProvider::RegisterProfilePrefs(registry);
AmbientController::RegisterProfilePrefs(registry);
BluetoothPowerController::RegisterProfilePrefs(registry);
CapsLockNotificationController::RegisterProfilePrefs(registry, for_test);
......
......@@ -72,6 +72,9 @@ constexpr SkColor kDefaultFrameColor = SkColorSetRGB(0xFD, 0xFE, 0xFF);
// Whether keyboard auto repeat is enabled by default.
constexpr bool kDefaultKeyAutoRepeatEnabled = true;
// Whether dark mode is enabled by default.
constexpr bool kDefaultDarkModeEnabled = true;
// The default delay before a held keypress will start to auto repeat.
constexpr base::TimeDelta kDefaultKeyAutoRepeatDelay =
base::TimeDelta::FromMilliseconds(500);
......
......@@ -577,6 +577,9 @@ const char kMouseReverseScroll[] = "settings.mouse.reverse_scroll";
// contextual nudge was shown.
const char kMultipasteNudges[] = "ash.clipboard.multipaste_nudges";
// A boolean pref that indicates whether dark mode is enabled.
const char kDarkModeEnabled[] = "cros.system.dark_mode_enabled";
// NOTE: New prefs should start with the "ash." prefix. Existing prefs moved
// into this file should not be renamed, since they may be synced.
......
......@@ -207,6 +207,8 @@ ASH_PUBLIC_EXPORT extern const char kMouseReverseScroll[];
ASH_PUBLIC_EXPORT extern const char kMultipasteNudges[];
ASH_PUBLIC_EXPORT extern const char kDarkModeEnabled[];
} // namespace prefs
} // namespace ash
......
......@@ -494,10 +494,9 @@ AshColorProvider::BaseLayerType ShelfConfig::GetShelfBaseLayerType() const {
if (in_tablet_mode_) {
if (is_in_app()) {
return AshColorProvider::Get()->color_mode() ==
AshColorProvider::AshColorMode::kLight
? AshColorProvider::BaseLayerType::kOpaque
: AshColorProvider::BaseLayerType::kTransparent90;
return AshColorProvider::Get()->IsDarkModeEnabled()
? AshColorProvider::BaseLayerType::kTransparent90
: AshColorProvider::BaseLayerType::kOpaque;
}
return AshColorProvider::BaseLayerType::kTransparent60;
}
......
......@@ -548,7 +548,6 @@ Shell::Shell(std::unique_ptr<ShellDelegate> shell_delegate)
std::make_unique<KeyboardBrightnessController>()),
locale_update_controller_(std::make_unique<LocaleUpdateControllerImpl>()),
parent_access_controller_(std::make_unique<ParentAccessController>()),
ash_color_provider_(std::make_unique<AshColorProvider>()),
session_controller_(std::make_unique<SessionControllerImpl>()),
shell_delegate_(std::move(shell_delegate)),
shutdown_controller_(std::make_unique<ShutdownControllerImpl>()),
......@@ -958,6 +957,8 @@ void Shell::Init(
if (context_factory)
env->set_context_factory(context_factory);
ash_color_provider_ = std::make_unique<AshColorProvider>();
// Night Light depends on the display manager, the display color manager, and
// aura::Env, so initialize it after all have been initialized.
night_light_controller_ = std::make_unique<NightLightControllerImpl>();
......
......@@ -697,8 +697,8 @@ class ASH_EXPORT Shell : public SessionObserver,
std::unique_ptr<ParentAccessController> parent_access_controller_;
std::unique_ptr<QuickAnswersController> quick_answers_controller_;
std::unique_ptr<ResizeShadowController> resize_shadow_controller_;
std::unique_ptr<AshColorProvider> ash_color_provider_;
std::unique_ptr<SessionControllerImpl> session_controller_;
std::unique_ptr<AshColorProvider> ash_color_provider_;
std::unique_ptr<NightLightControllerImpl> night_light_controller_;
std::unique_ptr<PrivacyScreenController> privacy_screen_controller_;
std::unique_ptr<PolicyRecommendationRestorer> policy_recommendation_restorer_;
......
......@@ -6,11 +6,19 @@
#include <math.h>
#include "ash/public/cpp/ash_constants.h"
#include "ash/public/cpp/ash_pref_names.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/system/dark_mode/color_mode_observer.h"
#include "ash/wallpaper/wallpaper_controller_impl.h"
#include "base/bind.h"
#include "base/check_op.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"
#include "ui/chromeos/colors/cros_colors.h"
#include "ui/gfx/color_analysis.h"
#include "ui/gfx/color_palette.h"
......@@ -61,6 +69,14 @@ bool IsLightMode(AshColorProvider::AshColorMode color_mode) {
} // namespace
AshColorProvider::AshColorProvider() {
Shell::Get()->session_controller()->AddObserver(this);
}
AshColorProvider::~AshColorProvider() {
Shell::Get()->session_controller()->RemoveObserver(this);
}
// static
AshColorProvider* AshColorProvider::Get() {
return Shell::Get()->ash_color_provider();
......@@ -79,6 +95,27 @@ SkColor AshColorProvider::GetSecondToneColor(SkColor color_of_first_tone) {
std::round(SkColorGetA(color_of_first_tone) * kSecondToneOpacity));
}
// static
void AshColorProvider::RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(
prefs::kDarkModeEnabled, kDefaultDarkModeEnabled,
user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
}
void AshColorProvider::OnActiveUserPrefServiceChanged(PrefService* prefs) {
active_user_pref_service_ = prefs;
pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
pref_change_registrar_->Init(prefs);
pref_change_registrar_->Add(
prefs::kDarkModeEnabled,
base::BindRepeating(&AshColorProvider::NotifyDarkModeEnabledPrefChange,
base::Unretained(this)));
// Immediately tell all the observers to load this user's saved preferences.
NotifyDarkModeEnabledPrefChange();
}
SkColor AshColorProvider::DeprecatedGetShieldLayerColor(
ShieldLayerType type,
SkColor default_color) const {
......@@ -218,6 +255,27 @@ void AshColorProvider::DecorateCloseButton(views::ImageButton* button,
// added separately so its easier to monitor performance.
}
void AshColorProvider::AddObserver(ColorModeObserver* observer) {
observers_.AddObserver(observer);
}
void AshColorProvider::RemoveObserver(ColorModeObserver* observer) {
observers_.RemoveObserver(observer);
}
bool AshColorProvider::IsDarkModeEnabled() const {
if (!active_user_pref_service_)
return kDefaultDarkModeEnabled;
return active_user_pref_service_->GetBoolean(prefs::kDarkModeEnabled);
}
void AshColorProvider::Toggle() {
DCHECK(active_user_pref_service_);
active_user_pref_service_->SetBoolean(prefs::kDarkModeEnabled,
!IsDarkModeEnabled());
active_user_pref_service_->CommitPendingWrite();
}
SkColor AshColorProvider::GetShieldLayerColorImpl(
ShieldLayerType type,
AshColorMode color_mode) const {
......@@ -394,4 +452,10 @@ SkColor AshColorProvider::GetBackgroundThemedColor(
muted_color);
}
void AshColorProvider::NotifyDarkModeEnabledPrefChange() {
const bool is_enabled = IsDarkModeEnabled();
for (auto& observer : observers_)
observer.OnColorModeChanged(is_enabled);
}
} // namespace ash
......@@ -6,15 +6,22 @@
#define ASH_STYLE_ASH_COLOR_PROVIDER_H_
#include "ash/ash_export.h"
#include "ash/public/cpp/session/session_observer.h"
#include "base/observer_list.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/vector_icon_types.h"
class PrefChangeRegistrar;
class PrefRegistrySimple;
class PrefService;
namespace views {
class ImageButton;
class LabelButton;
} // namespace views
namespace ash {
class ColorModeObserver;
// The color provider for system UI. It provides colors for Shield layer, Base
// layer, Controls layer and Content layer. Shield layer is a combination of
......@@ -26,11 +33,12 @@ namespace ash {
// state of an interactive element (active/inactive states). Content layer means
// 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 {
class ASH_EXPORT AshColorProvider : public SessionObserver {
public:
// The color mode of system UI. Switch "--ash-color-mode" can only set
// |color_mode_| to |kLight| or |kDark|, |color_mode_| will be |kDefault| if
// the flag is not set.
// TODO(minch): Remove AshColorMode, |color_mode_| and DeprecatedGet*
// functions once all the deprecated colors have been removed.
// The color mode of system UI, which can be set through the dark mode feature
// pod in the system tray menu.
enum class AshColorMode {
// This is the color mode of current system UI, which is a combination of
// dark and light mode. e.g, shelf and system tray are dark while many other
......@@ -142,10 +150,10 @@ class ASH_EXPORT AshColorProvider {
const float highlight_opacity;
};
AshColorProvider() = default;
AshColorProvider();
AshColorProvider(const AshColorProvider& other) = delete;
AshColorProvider operator=(const AshColorProvider& other) = delete;
~AshColorProvider() = default;
~AshColorProvider() override;
static AshColorProvider* Get();
......@@ -157,6 +165,11 @@ class ASH_EXPORT AshColorProvider {
// power status icon inside status area is a dual tone icon.
static SkColor GetSecondToneColor(SkColor color_of_first_tone);
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
// SessionObserver:
void OnActiveUserPrefServiceChanged(PrefService* prefs) override;
// Gets color of Shield layer. See details at the corresponding function of
// Base layer.
SkColor DeprecatedGetShieldLayerColor(ShieldLayerType type,
......@@ -213,7 +226,16 @@ class ASH_EXPORT AshColorProvider {
int button_size,
const gfx::VectorIcon& icon);
AshColorMode color_mode() const { return color_mode_; }
void AddObserver(ColorModeObserver* observer);
void RemoveObserver(ColorModeObserver* observer);
// True if pref |kDarkModeEnabled| is true, which means the current color mode
// is dark.
bool IsDarkModeEnabled() const;
// Toggles pref |kDarkModeEnabled|.
void Toggle();
bool is_themed() const { return is_themed_; }
private:
......@@ -250,12 +272,19 @@ class ASH_EXPORT AshColorProvider {
// muted wallpaper prominent color + SK_ColorWHITE 75%.
SkColor GetBackgroundThemedColor(AshColorMode color_mode) const;
// Notifies all the observers on |kDarkModeEnabled|'s change.
void NotifyDarkModeEnabledPrefChange();
// Current color mode of system UI.
AshColorMode color_mode_ = AshColorMode::kDefault;
// Whether the system color mode is themed, by default is true. If true, the
// background color will be calculated based on extracted wallpaper color.
bool is_themed_ = true;
base::ObserverList<ColorModeObserver> observers_;
std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
PrefService* active_user_pref_service_ = nullptr; // Not owned.
};
} // namespace ash
......
// Copyright 2020 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_DARK_MODE_COLOR_MODE_OBSERVER_H_
#define ASH_SYSTEM_DARK_MODE_COLOR_MODE_OBSERVER_H_
#include "ash/ash_export.h"
#include "base/observer_list_types.h"
namespace ash {
class ASH_EXPORT ColorModeObserver : public base::CheckedObserver {
public:
// Called when the color mode changes.
virtual void OnColorModeChanged(bool dark_mode_enabled) = 0;
protected:
~ColorModeObserver() override = default;
};
} // namespace ash
#endif // ASH_SYSTEM_DARK_MODE_COLOR_MODE_OBSERVER_H_
......@@ -56,8 +56,7 @@ void DarkModeDetailedView::CreateItems() {
toggle_ =
TrayPopupUtils::CreateToggleButton(this, IDS_ASH_STATUS_TRAY_BLUETOOTH);
toggle_->SetIsOn(AshColorProvider::Get()->color_mode() ==
AshColorProvider::AshColorMode::kDark);
toggle_->SetIsOn(AshColorProvider::Get()->IsDarkModeEnabled());
tri_view()->AddView(TriView::Container::END, toggle_);
// Add color mode options.
......
......@@ -5,6 +5,8 @@
#include "ash/system/dark_mode/dark_mode_feature_pod_controller.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/style/ash_color_provider.h"
#include "ash/system/unified/feature_pod_button.h"
......@@ -17,9 +19,12 @@ DarkModeFeaturePodController::DarkModeFeaturePodController(
UnifiedSystemTrayController* tray_controller)
: tray_controller_(tray_controller) {
DCHECK(tray_controller_);
AshColorProvider::Get()->AddObserver(this);
}
DarkModeFeaturePodController::~DarkModeFeaturePodController() = default;
DarkModeFeaturePodController::~DarkModeFeaturePodController() {
AshColorProvider::Get()->RemoveObserver(this);
}
FeaturePodButton* DarkModeFeaturePodController::CreateButton() {
DCHECK(!button_);
......@@ -29,14 +34,17 @@ FeaturePodButton* DarkModeFeaturePodController::CreateButton() {
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DARK_MODE_BUTTON_LABEL));
button_->SetLabelTooltip(l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_DARK_MODE_SETTINGS_TOOLTIP));
// TODO(minch): Add the logic for login screen.
button_->SetVisible(
Shell::Get()->session_controller()->IsActiveUserSessionStarted());
UpdateButton();
UpdateButton(AshColorProvider::Get()->IsDarkModeEnabled());
return button_;
}
void DarkModeFeaturePodController::OnIconPressed() {
// TODO: Switch dark mode here.
UpdateButton();
AshColorProvider::Get()->Toggle();
// TODO(amehfooz): Add metrics recording here.
}
......@@ -50,17 +58,19 @@ SystemTrayItemUmaType DarkModeFeaturePodController::GetUmaType() const {
return SystemTrayItemUmaType::UMA_DARK_MODE;
}
void DarkModeFeaturePodController::UpdateButton() {
const bool is_enabled = AshColorProvider::Get()->color_mode() ==
AshColorProvider::AshColorMode::kDark;
button_->SetToggled(is_enabled);
void DarkModeFeaturePodController::OnColorModeChanged(bool dark_mode_enabled) {
UpdateButton(dark_mode_enabled);
}
void DarkModeFeaturePodController::UpdateButton(bool dark_mode_enabled) {
button_->SetToggled(dark_mode_enabled);
button_->SetSubLabel(l10n_util::GetStringUTF16(
is_enabled ? IDS_ASH_STATUS_TRAY_DARK_MODE_ON_STATE
: IDS_ASH_STATUS_TRAY_DARK_MODE_OFF_STATE));
dark_mode_enabled ? IDS_ASH_STATUS_TRAY_DARK_MODE_ON_STATE
: IDS_ASH_STATUS_TRAY_DARK_MODE_OFF_STATE));
base::string16 tooltip_state = l10n_util::GetStringUTF16(
is_enabled ? IDS_ASH_STATUS_TRAY_DARK_MODE_ENABLED_STATE_TOOLTIP
: IDS_ASH_STATUS_TRAY_DARK_MODE_DISABLED_STATE_TOOLTIP);
dark_mode_enabled ? IDS_ASH_STATUS_TRAY_DARK_MODE_ENABLED_STATE_TOOLTIP
: IDS_ASH_STATUS_TRAY_DARK_MODE_DISABLED_STATE_TOOLTIP);
button_->SetIconTooltip(l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DARK_MODE_TOGGLE_TOOLTIP, tooltip_state));
}
......
......@@ -5,6 +5,7 @@
#ifndef ASH_SYSTEM_DARK_MODE_DARK_MODE_FEATURE_POD_CONTROLLER_H_
#define ASH_SYSTEM_DARK_MODE_DARK_MODE_FEATURE_POD_CONTROLLER_H_
#include "ash/system/dark_mode/color_mode_observer.h"
#include "ash/system/unified/feature_pod_controller_base.h"
#include "base/macros.h"
......@@ -13,7 +14,8 @@ namespace ash {
class UnifiedSystemTrayController;
// Controller of a feature pod button that toggles dark mode for ash.
class DarkModeFeaturePodController : public FeaturePodControllerBase {
class DarkModeFeaturePodController : public FeaturePodControllerBase,
public ColorModeObserver {
public:
explicit DarkModeFeaturePodController(
UnifiedSystemTrayController* tray_controller);
......@@ -29,8 +31,11 @@ class DarkModeFeaturePodController : public FeaturePodControllerBase {
void OnLabelPressed() override;
SystemTrayItemUmaType GetUmaType() const override;
// ColorModeObserver:
void OnColorModeChanged(bool dark_mode_enabled) override;
private:
void UpdateButton();
void UpdateButton(bool dark_mode_enabled);
UnifiedSystemTrayController* const tray_controller_;
......
......@@ -139,10 +139,9 @@ void DeskMiniView::UpdateBorderColor() {
desk_preview_->SetBorderColor(kInactiveColor);
} else {
// Default theme for desks is dark mode.
desk_preview_->SetBorderColor(color_provider->color_mode() ==
AshColorProvider::AshColorMode::kLight
? kLightModeActiveColor
: kDarkModeActiveColor);
desk_preview_->SetBorderColor(color_provider->IsDarkModeEnabled()
? kDarkModeActiveColor
: kLightModeActiveColor);
}
}
......
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