blob: 39c49346c6dcb972e7f978b2d6e9f1eb32753ea2 [file] [log] [blame]
// Copyright (c) 2012 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 CHROME_BROWSER_THEMES_THEME_SERVICE_H_
#define CHROME_BROWSER_THEMES_THEME_SERVICE_H_
#include <memory>
#include <string>
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/scoped_observer.h"
#include "base/task/cancelable_task_tracker.h"
#include "chrome/browser/themes/theme_helper.h"
#include "chrome/common/buildflags.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/prefs/pref_change_registrar.h"
#include "extensions/buildflags/buildflags.h"
#include "extensions/common/extension_id.h"
#include "ui/base/theme_provider.h"
#include "ui/native_theme/native_theme.h"
#include "ui/native_theme/native_theme_observer.h"
class BrowserThemePack;
class CustomThemeSupplier;
class Profile;
class ThemeServiceObserver;
class ThemeSyncableService;
namespace extensions {
class Extension;
}
namespace theme_service_internal {
class ThemeServiceTest;
}
class BrowserThemeProviderDelegate {
public:
virtual const CustomThemeSupplier* GetThemeSupplier() const = 0;
};
class ThemeService : public KeyedService,
public ui::NativeThemeObserver,
public BrowserThemeProviderDelegate {
public:
// This class keeps track of the number of existing |ThemeReinstaller|
// objects. When that number reaches 0 then unused themes will be deleted.
class ThemeReinstaller {
public:
ThemeReinstaller(Profile* profile, base::OnceClosure installer);
ThemeReinstaller(const ThemeReinstaller&) = delete;
ThemeReinstaller& operator=(const ThemeReinstaller&) = delete;
~ThemeReinstaller();
void Reinstall();
private:
base::OnceClosure installer_;
ThemeService* const theme_service_;
};
// Constant ID to use for all autogenerated themes.
static const char kAutogeneratedThemeID[];
// Creates a ThemeProvider with a custom theme supplier specified via
// |delegate|. The return value must not outlive |profile|'s ThemeService.
static std::unique_ptr<ui::ThemeProvider> CreateBoundThemeProvider(
Profile* profile,
BrowserThemeProviderDelegate* delegate);
ThemeService(Profile* profile, const ThemeHelper& theme_helper);
ThemeService(const ThemeService&) = delete;
ThemeService& operator=(const ThemeService&) = delete;
~ThemeService() override;
void Init();
// KeyedService:
void Shutdown() override;
// Overridden from ui::NativeThemeObserver:
void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
// Overridden from BrowserThemeProviderDelegate:
const CustomThemeSupplier* GetThemeSupplier() const override;
// Set the current theme to the theme defined in |extension|.
// |extension| must already be added to this profile's
// ExtensionService.
void SetTheme(const extensions::Extension* extension);
// Similar to SetTheme, but doesn't show an undo infobar.
void RevertToExtensionTheme(const std::string& extension_id);
// Reset the theme to default.
virtual void UseDefaultTheme();
// Set the current theme to the system theme. On some platforms, the system
// theme is the default theme.
virtual void UseSystemTheme();
// Returns true if the default theme and system theme are not the same on
// this platform.
virtual bool IsSystemThemeDistinctFromDefaultTheme() const;
// Forwards to ThemeProviderBase::IsDefaultTheme().
// Virtual for testing.
virtual bool UsingDefaultTheme() const;
// Whether we are using the system theme. On GTK, the system theme is the GTK
// theme, not the "Classic" theme.
virtual bool UsingSystemTheme() const;
// Forwards to ThemeProviderBase::IsExtensionTheme().
// Virtual for testing.
virtual bool UsingExtensionTheme() const;
// Forwards to ThemeProviderBase::IsAutogeneratedTheme().
// Virtual for testing.
virtual bool UsingAutogeneratedTheme() const;
// Whether current theme colors are enforced through a policy.
// Virtual for testing.
virtual bool UsingPolicyTheme() const;
// Gets the id of the last installed theme. (The theme may have been further
// locally customized.)
virtual std::string GetThemeID() const;
// Uninstall theme extensions which are no longer in use.
void RemoveUnusedThemes();
// Returns the syncable service for syncing theme. The returned service is
// owned by |this| object.
virtual ThemeSyncableService* GetThemeSyncableService() const;
// Gets the ThemeProvider for |profile|. This will be different for an
// incognito profile and its original profile, even though both profiles use
// the same ThemeService.
static const ui::ThemeProvider& GetThemeProviderForProfile(Profile* profile);
// Builds an autogenerated theme from a given |color| and applies it.
virtual void BuildAutogeneratedThemeFromColor(SkColor color);
// Builds an autogenerated theme from a given |color| and applies it.
virtual void BuildAutogeneratedThemeFromColor(SkColor color,
bool store_in_prefs);
// Returns the theme color for an autogenerated theme.
virtual SkColor GetAutogeneratedThemeColor() const;
// Builds an autogenerated theme from the applied policy color and applies it.
virtual void BuildAutogeneratedPolicyTheme();
// Returns the theme color for the current policy theme.
virtual SkColor GetPolicyThemeColor() const;
// Returns |ThemeService::ThemeReinstaller| for the current theme.
std::unique_ptr<ThemeService::ThemeReinstaller>
BuildReinstallerForCurrentTheme();
void AddObserver(ThemeServiceObserver* observer);
void RemoveObserver(ThemeServiceObserver* observer);
const ThemeHelper& theme_helper_for_testing() const { return theme_helper_; }
// Don't create "Cached Theme.pak" in the extension directory, for testing.
static void DisableThemePackForTesting();
protected:
// Set a custom default theme instead of the normal default theme.
virtual void SetCustomDefaultTheme(
scoped_refptr<CustomThemeSupplier> theme_supplier);
// Returns true if the ThemeService should use the system theme on startup.
virtual bool ShouldInitWithSystemTheme() const;
// Clears all the override fields and saves the dictionary.
virtual void ClearAllThemeData();
// Initialize current theme state data from preferences.
virtual void InitFromPrefs();
// Let all the browser views know that themes have changed.
virtual void NotifyThemeChanged();
// If there is an inconsistency in preferences, change preferences to a
// consistent state.
virtual void FixInconsistentPreferencesIfNeeded();
Profile* profile() const { return profile_; }
void set_ready() { ready_ = true; }
// True if the theme service is ready to be used.
// TODO(pkotwicz): Add DCHECKS to the theme service's getters once
// ThemeSource no longer uses the ThemeService when it is not ready.
bool ready_ = false;
private:
// This class implements ui::ThemeProvider on behalf of ThemeHelper and
// keeps track of the incognito state and CustemThemeSupplier for the calling
// code.
class BrowserThemeProvider : public ui::ThemeProvider {
public:
BrowserThemeProvider(const ThemeHelper& theme_helper,
bool incognito,
const BrowserThemeProviderDelegate* delegate);
BrowserThemeProvider(const BrowserThemeProvider&) = delete;
BrowserThemeProvider& operator=(const BrowserThemeProvider&) = delete;
~BrowserThemeProvider() override;
// Overridden from ui::ThemeProvider:
gfx::ImageSkia* GetImageSkiaNamed(int id) const override;
SkColor GetColor(int original_id) const override;
color_utils::HSL GetTint(int original_id) const override;
int GetDisplayProperty(int id) const override;
bool ShouldUseNativeFrame() const override;
bool HasCustomImage(int id) const override;
bool HasCustomColor(int id) const override;
base::RefCountedMemory* GetRawData(int id, ui::ScaleFactor scale_factor)
const override;
private:
const CustomThemeSupplier* GetThemeSupplier() const;
const ThemeHelper& theme_helper_;
bool incognito_;
const BrowserThemeProviderDelegate* delegate_;
};
friend class BrowserThemeProvider;
friend class theme_service_internal::ThemeServiceTest;
// virtual for testing.
virtual void DoSetTheme(const extensions::Extension* extension,
bool suppress_infobar);
// Called when the extension service is ready.
void OnExtensionServiceReady();
// Migrate the theme to the new theme pack schema by recreating the data pack
// from the extension.
void MigrateTheme();
// Replaces the current theme supplier with a new one and calls
// StopUsingTheme() or StartUsingTheme() as appropriate.
void SwapThemeSupplier(scoped_refptr<CustomThemeSupplier> theme_supplier);
// Implementation of SetTheme() (and the fallback from InitFromPrefs() in
// case we don't have a theme pack). |new_theme| indicates whether this is a
// newly installed theme or a migration.
void BuildFromExtension(const extensions::Extension* extension,
bool new_theme);
// Callback when |pack| has finished or failed building.
void OnThemeBuiltFromExtension(const extensions::ExtensionId& extension_id,
scoped_refptr<BrowserThemePack> pack,
bool new_theme);
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
// Returns true if the profile belongs to a supervised user.
bool IsSupervisedUser() const;
// Sets the current theme to the supervised user theme. Should only be used
// for supervised user profiles.
void SetSupervisedUserTheme();
#endif
// Handles theme color policy pref updates. if policy value contains valid
// color(s), sets browser theme accordingly.
void HandlePolicyColorUpdate();
// Functions that modify theme prefs.
void ClearThemePrefs();
void SetThemePrefsForExtension(const extensions::Extension* extension);
void SetThemePrefsForColor(SkColor color);
bool DisableExtension(const std::string& extension_id);
Profile* profile_;
PrefChangeRegistrar pref_change_registrar_;
const ThemeHelper& theme_helper_;
scoped_refptr<CustomThemeSupplier> theme_supplier_;
// The id of the theme extension which has just been installed but has not
// been loaded yet. The theme extension with |installed_pending_load_id_| may
// never be loaded if the install is due to updating a disabled theme.
// |pending_install_id_| should be set to |kDefaultThemeID| if there are no
// recently installed theme extensions
std::string installed_pending_load_id_ = ThemeHelper::kDefaultThemeID;
// The number of infobars currently displayed.
int number_of_reinstallers_ = 0;
// Declared before |theme_syncable_service_|, because ThemeSyncableService
// removes itself from the |observers_| list on destruction.
base::ObserverList<ThemeServiceObserver> observers_;
std::unique_ptr<ThemeSyncableService> theme_syncable_service_;
#if BUILDFLAG(ENABLE_EXTENSIONS)
class ThemeObserver;
std::unique_ptr<ThemeObserver> theme_observer_;
#endif
BrowserThemeProvider original_theme_provider_;
BrowserThemeProvider incognito_theme_provider_;
// Allows us to cancel building a theme pack from an extension.
base::CancelableTaskTracker build_extension_task_tracker_;
// The ID of the theme that's currently being built on a different thread.
// We hold onto this just to be sure not to uninstall the extension view
// RemoveUnusedThemes while it's still being built.
std::string building_extension_id_;
ScopedObserver<ui::NativeTheme, ui::NativeThemeObserver>
native_theme_observer_{this};
base::WeakPtrFactory<ThemeService> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_THEMES_THEME_SERVICE_H_