diff options
23 files changed, 288 insertions, 109 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 9c689fb..e6218a3 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -4704,6 +4704,9 @@ Update checks have repeatedly failed for the extension "<ph name="EXTENSION_NAME <message name="IDS_EXTENSIONS_POLICY_CONTROLLED" desc="The text in the extensions UI informing the user that an extension is policy controlled"> (This extension is managed and cannot be removed or disabled.) </message> + <message name="IDS_EXTENSIONS_LOCKED_MANAGED_MODE" desc="The error message (either shown in the extensions UI or logged) informing the user that extensions are controlled by managed mode"> + Extensions cannot be modified in managed mode. + </message> <message name="IDS_GET_MORE_EXTENSIONS_DEPRECATED" desc="The link for getting more extensions. Displayed at bottom of extension management page when there is at least one extension installed."> <ph name="BEGIN_LINK"><a target="blank_" href="$1"></ph>Get more extensions<ph name="END_LINK"></a><ex></a></ex></ph> </message> diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 928ab28..7ab2892 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc @@ -49,6 +49,7 @@ #include "chrome/browser/gpu_util.h" #include "chrome/browser/jankometer.h" #include "chrome/browser/language_usage_metrics.h" +#include "chrome/browser/managed_mode.h" #include "chrome/browser/metrics/field_trial_synchronizer.h" #include "chrome/browser/metrics/histogram_synchronizer.h" #include "chrome/browser/metrics/metrics_log.h" @@ -1603,7 +1604,10 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() { translate_manager_ = TranslateManager::GetInstance(); DCHECK(translate_manager_ != NULL); - // TODO(stevenjb): Move WIN and MACOSX specific code to apprpriate Parts. + // Initialize Managed Mode. + ManagedMode::Init(profile_); + + // TODO(stevenjb): Move WIN and MACOSX specific code to appropriate Parts. // (requires supporting early exit). PostProfileInit(); diff --git a/chrome/browser/extensions/extension_managed_mode_apitest.cc b/chrome/browser/extensions/extension_managed_mode_apitest.cc index d8d1c07..4c19cfb 100644 --- a/chrome/browser/extensions/extension_managed_mode_apitest.cc +++ b/chrome/browser/extensions/extension_managed_mode_apitest.cc @@ -4,6 +4,7 @@ #include "chrome/browser/managed_mode.h" #include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" #include "chrome/test/base/ui_test_utils.h" @@ -37,10 +38,10 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ManagedModeOnChange) { // Fire the extension event when entering managed mode. We directly call // SetInManagedMode() to bypass any confirmation dialogs etc. - ManagedMode::GetInstance()->SetInManagedMode(true); + ManagedMode::GetInstance()->SetInManagedMode(browser()->profile()); // Fire the extension event when leaving managed mode. - ManagedMode::GetInstance()->SetInManagedMode(false); + ManagedMode::GetInstance()->SetInManagedMode(NULL); ASSERT_TRUE(catcher.GetNextResult()) << catcher.message(); } diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc index fc523325..fed7aec 100644 --- a/chrome/browser/extensions/extension_prefs.cc +++ b/chrome/browser/extensions/extension_prefs.cc @@ -657,8 +657,13 @@ void ExtensionPrefs::SetAppNotificationDisabled( Value::CreateBooleanValue(value)); } -std::string ExtensionPrefs::GetPolicyProviderName() const { +std::string ExtensionPrefs::GetDebugPolicyProviderName() const { +#ifdef NDEBUG + NOTREACHED(); + return std::string(); +#else return "admin policy black/white/forcelist, via the ExtensionPrefs"; +#endif } bool ExtensionPrefs::UserMayLoad(const extensions::Extension* extension, diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h index 0efe0b4..8b906cd 100644 --- a/chrome/browser/extensions/extension_prefs.h +++ b/chrome/browser/extensions/extension_prefs.h @@ -211,7 +211,7 @@ class ExtensionPrefs : public extensions::ContentSettingsStore::Observer, // ManagementPolicy::Provider // These methods apply admin policy to extensions. - virtual std::string GetPolicyProviderName() const OVERRIDE; + virtual std::string GetDebugPolicyProviderName() const OVERRIDE; virtual bool UserMayLoad(const extensions::Extension* extension, string16* error) const OVERRIDE; virtual bool UserMayModifySettings(const extensions::Extension* extension, diff --git a/chrome/browser/extensions/management_policy.cc b/chrome/browser/extensions/management_policy.cc index 2524116..ce28faa 100644 --- a/chrome/browser/extensions/management_policy.cc +++ b/chrome/browser/extensions/management_policy.cc @@ -41,8 +41,10 @@ bool ManagementPolicy::UserMayLoad(const Extension* extension, if (!(*it)->UserMayLoad(extension, error)) { // The extension may be NULL in testing. std::string id = extension ? extension->id() : "[test]"; - DLOG(WARNING) << "Installation of extension " << id - << " prohibited by " << (*it)->GetPolicyProviderName(); + std::string name = extension ? extension->name() : "test"; + DLOG(WARNING) << "Installation of extension " << name + << "( " << id << ")" + << " prohibited by " << (*it)->GetDebugPolicyProviderName(); return false; } } @@ -56,8 +58,10 @@ bool ManagementPolicy::UserMayModifySettings(const Extension* extension, if (!(*it)->UserMayModifySettings(extension, error)) { // The extension may be NULL in testing. std::string id = extension ? extension->id() : "[test]"; - DLOG(WARNING) << "Modification of extension " << id - << " prohibited by " << (*it)->GetPolicyProviderName(); + std::string name = extension ? extension->name() : "test"; + DLOG(WARNING) << "Modification of extension " << name + << "( " << id << ")" + << " prohibited by " << (*it)->GetDebugPolicyProviderName(); return false; } } @@ -68,12 +72,14 @@ bool ManagementPolicy::MustRemainEnabled(const Extension* extension, string16* error) const { for (ProviderList::const_iterator it = providers_.begin(); it != providers_.end(); ++it) { + if ((*it)->MustRemainEnabled(extension, error)) { // The extension may be NULL in testing. std::string id = extension ? extension->id() : "[test]"; - if ((*it)->MustRemainEnabled(extension, error)) { - DLOG(WARNING) << "Extension " << id + std::string name = extension ? extension->name() : "test"; + DLOG(WARNING) << "Extension " << name + << "( " << id << ")" << " required to remain enabled by " - << (*it)->GetPolicyProviderName(); + << (*it)->GetDebugPolicyProviderName(); return true; } } diff --git a/chrome/browser/extensions/management_policy.h b/chrome/browser/extensions/management_policy.h index f2d16f5..47f499f 100644 --- a/chrome/browser/extensions/management_policy.h +++ b/chrome/browser/extensions/management_policy.h @@ -46,7 +46,9 @@ class ManagementPolicy { virtual ~Provider() {} // A human-readable name for this provider, for use in debug messages. - virtual std::string GetPolicyProviderName() const = 0; + // Implementers should return an empty string in non-debug builds, to save + // executable size. + virtual std::string GetDebugPolicyProviderName() const = 0; // Providers should return false if a user may not install the |extension|, // or load or run it if it has already been installed. diff --git a/chrome/browser/extensions/test_management_policy.cc b/chrome/browser/extensions/test_management_policy.cc index 16d317e..2296fc8 100644 --- a/chrome/browser/extensions/test_management_policy.cc +++ b/chrome/browser/extensions/test_management_policy.cc @@ -27,7 +27,7 @@ void TestManagementPolicyProvider::SetProhibitedActions( must_remain_enabled_ = (prohibited_actions & MUST_REMAIN_ENABLED) != 0; } -std::string TestManagementPolicyProvider::GetPolicyProviderName() const { +std::string TestManagementPolicyProvider::GetDebugPolicyProviderName() const { return "the test management policy provider"; } diff --git a/chrome/browser/extensions/test_management_policy.h b/chrome/browser/extensions/test_management_policy.h index bcb300d..649ea91 100644 --- a/chrome/browser/extensions/test_management_policy.h +++ b/chrome/browser/extensions/test_management_policy.h @@ -32,7 +32,7 @@ class TestManagementPolicyProvider : public ManagementPolicy::Provider { void SetProhibitedActions(int prohibited_actions); - virtual std::string GetPolicyProviderName() const OVERRIDE; + virtual std::string GetDebugPolicyProviderName() const OVERRIDE; virtual bool UserMayLoad(const Extension* extension, string16* error) const OVERRIDE; diff --git a/chrome/browser/managed_mode.cc b/chrome/browser/managed_mode.cc index 480bf4c..259882f 100644 --- a/chrome/browser/managed_mode.cc +++ b/chrome/browser/managed_mode.cc @@ -6,6 +6,7 @@ #include "base/command_line.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/extensions/extension_system.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h" @@ -16,6 +17,8 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "content/public/browser/notification_service.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" // static ManagedMode* ManagedMode::GetInstance() { @@ -25,12 +28,26 @@ ManagedMode* ManagedMode::GetInstance() { // static void ManagedMode::RegisterPrefs(PrefService* prefs) { prefs->RegisterBooleanPref(prefs::kInManagedMode, false); +} + +// static +void ManagedMode::Init(Profile* profile) { + GetInstance()->InitImpl(profile); +} + +void ManagedMode::InitImpl(Profile* profile) { + DCHECK(g_browser_process); + DCHECK(g_browser_process->local_state()); + + Profile* original_profile = profile->GetOriginalProfile(); // Set the value directly in the PrefService instead of using // CommandLinePrefStore so we can change it at runtime. - if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoManaged)) - GetInstance()->SetInManagedMode(false); - else if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kManaged)) - GetInstance()->SetInManagedMode(true); + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoManaged)) { + SetInManagedMode(NULL); + } else if (IsInManagedModeImpl() || + CommandLine::ForCurrentProcess()->HasSwitch(switches::kManaged)) { + SetInManagedMode(original_profile); + } } // static @@ -38,7 +55,7 @@ bool ManagedMode::IsInManagedMode() { return GetInstance()->IsInManagedModeImpl(); } -bool ManagedMode::IsInManagedModeImpl() { +bool ManagedMode::IsInManagedModeImpl() const { // |g_browser_process| can be NULL during startup. if (!g_browser_process) return false; @@ -56,11 +73,11 @@ void ManagedMode::EnterManagedMode(Profile* profile, void ManagedMode::EnterManagedModeImpl(Profile* profile, const EnterCallback& callback) { + Profile* original_profile = profile->GetOriginalProfile(); if (IsInManagedModeImpl()) { - callback.Run(true); + callback.Run(original_profile == managed_profile_); return; } - Profile* original_profile = profile->GetOriginalProfile(); if (!callbacks_.empty()) { // We are already in the process of entering managed mode, waiting for // browsers to close. Don't allow entering managed mode again for a @@ -76,22 +93,23 @@ void ManagedMode::EnterManagedModeImpl(Profile* profile, callback.Run(false); return; } - managed_profile_ = original_profile; // Close all other profiles. // At this point, we shouldn't be waiting for other browsers to close (yet). DCHECK_EQ(0u, browsers_to_close_.size()); for (BrowserList::const_iterator i = BrowserList::begin(); i != BrowserList::end(); ++i) { - if ((*i)->profile()->GetOriginalProfile() != managed_profile_) + if ((*i)->profile()->GetOriginalProfile() != original_profile) browsers_to_close_.insert(*i); } if (browsers_to_close_.empty()) { - SetInManagedMode(true); - managed_profile_ = NULL; + SetInManagedMode(original_profile); callback.Run(true); return; } + // Remember the profile we're trying to manage while we wait for other + // browsers to close. + managed_profile_ = original_profile; callbacks_.push_back(callback); registrar_.Add(this, content::NOTIFICATION_APP_EXITING, content::NotificationService::AllSources()); @@ -111,7 +129,36 @@ void ManagedMode::LeaveManagedMode() { void ManagedMode::LeaveManagedModeImpl() { bool confirmed = PlatformConfirmLeave(); if (confirmed) - SetInManagedMode(false); + SetInManagedMode(NULL); +} + +std::string ManagedMode::GetDebugPolicyProviderName() const { + // Save the string space in official builds. +#ifdef NDEBUG + NOTREACHED(); + return std::string(); +#else + return "Managed Mode"; +#endif +} + +bool ManagedMode::UserMayLoad(const extensions::Extension* extension, + string16* error) const { + return ExtensionManagementPolicyImpl(error); +} + +bool ManagedMode::UserMayModifySettings(const extensions::Extension* extension, + string16* error) const { + return ExtensionManagementPolicyImpl(error); +} + +bool ManagedMode::ExtensionManagementPolicyImpl(string16* error) const { + if (!IsInManagedModeImpl()) + return true; + + if (error) + *error = l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCKED_MANAGED_MODE); + return false; } void ManagedMode::OnBrowserAdded(Browser* browser) { @@ -119,6 +166,7 @@ void ManagedMode::OnBrowserAdded(Browser* browser) { if (callbacks_.empty()) return; + DCHECK(managed_profile_); if (browser->profile()->GetOriginalProfile() != managed_profile_) FinalizeEnter(false); } @@ -128,6 +176,7 @@ void ManagedMode::OnBrowserRemoved(Browser* browser) { if (callbacks_.empty()) return; + DCHECK(managed_profile_); if (browser->profile()->GetOriginalProfile() == managed_profile_) { // Ignore closing browser windows that are in managed mode. return; @@ -144,7 +193,6 @@ ManagedMode::ManagedMode() : managed_profile_(NULL) { ManagedMode::~ManagedMode() { BrowserList::RemoveObserver(this); - DCHECK(!managed_profile_); DCHECK_EQ(0u, callbacks_.size()); DCHECK_EQ(0u, browsers_to_close_.size()); } @@ -176,12 +224,11 @@ void ManagedMode::Observe(int type, void ManagedMode::FinalizeEnter(bool result) { if (result) - SetInManagedMode(true); + SetInManagedMode(managed_profile_); for (std::vector<EnterCallback>::iterator it = callbacks_.begin(); it != callbacks_.end(); ++it) { it->Run(result); } - managed_profile_ = NULL; callbacks_.clear(); browsers_to_close_.clear(); registrar_.RemoveAll(); @@ -197,13 +244,25 @@ bool ManagedMode::PlatformConfirmLeave() { return true; } -void ManagedMode::SetInManagedMode(bool in_managed_mode) { - g_browser_process->local_state()->SetBoolean(prefs::kInManagedMode, - in_managed_mode); +void ManagedMode::SetInManagedMode(Profile* newly_managed_profile) { + // Register the ManagementPolicy::Provider before changing the pref when + // setting it, and unregister it after changing the pref when clearing it, + // so pref observers see the correct ManagedMode state. + if (newly_managed_profile) { + DCHECK(!managed_profile_ || managed_profile_ == newly_managed_profile); + ExtensionSystem::Get( + newly_managed_profile)->management_policy()->RegisterProvider(this); + g_browser_process->local_state()->SetBoolean(prefs::kInManagedMode, true); + } else { + ExtensionSystem::Get( + managed_profile_)->management_policy()->UnregisterProvider(this); + g_browser_process->local_state()->SetBoolean(prefs::kInManagedMode, false); + } + managed_profile_ = newly_managed_profile; + // This causes the avatar and the profile menu to get updated. content::NotificationService::current()->Notify( chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, content::NotificationService::AllBrowserContextsAndSources(), content::NotificationService::NoDetails()); } - diff --git a/chrome/browser/managed_mode.h b/chrome/browser/managed_mode.h index d3779ca..76f0b32 100644 --- a/chrome/browser/managed_mode.h +++ b/chrome/browser/managed_mode.h @@ -6,11 +6,13 @@ #define CHROME_BROWSER_MANAGED_MODE_H_ #include <set> +#include <string> #include <vector> #include "base/callback.h" #include "base/compiler_specific.h" #include "base/memory/singleton.h" +#include "chrome/browser/extensions/management_policy.h" #include "chrome/browser/ui/browser_list.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -26,11 +28,16 @@ class Profile; // The ManagedMode class provides methods to check whether the browser is in // managed mode, and to attempt to enter or leave managed mode. class ManagedMode : public BrowserList::Observer, + public extensions::ManagementPolicy::Provider, public content::NotificationObserver { public: typedef base::Callback<void(bool)> EnterCallback; static void RegisterPrefs(PrefService* prefs); + + // Initializes the singleton, setting the managed_profile_. Must be called + // after g_browser_process and the LocalState have been created. + static void Init(Profile* profile); static bool IsInManagedMode(); // Calls |callback| with the argument true iff managed mode was entered @@ -38,6 +45,13 @@ class ManagedMode : public BrowserList::Observer, static void EnterManagedMode(Profile* profile, const EnterCallback& callback); static void LeaveManagedMode(); + // ExtensionManagementPolicy::Provider implementation: + virtual std::string GetDebugPolicyProviderName() const OVERRIDE; + virtual bool UserMayLoad(const extensions::Extension* extension, + string16* error) const OVERRIDE; + virtual bool UserMayModifySettings(const extensions::Extension* extension, + string16* error) const OVERRIDE; + // BrowserList::Observer implementation: virtual void OnBrowserAdded(Browser* browser) OVERRIDE; virtual void OnBrowserRemoved(Browser* browser) OVERRIDE; @@ -52,13 +66,25 @@ class ManagedMode : public BrowserList::Observer, virtual ~ManagedMode(); void EnterManagedModeImpl(Profile* profile, const EnterCallback& callback); + // The managed profile. This is NULL iff we are not in managed mode. + Profile* managed_profile_; + private: friend struct DefaultSingletonTraits<ManagedMode>; friend class Singleton<ManagedMode>; FRIEND_TEST_ALL_PREFIXES(ExtensionApiTest, ManagedModeOnChange); + FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, + ManagedModeProhibitsModification); static ManagedMode* GetInstance(); + virtual void InitImpl(Profile* profile); + + // Internal implementation for ExtensionManagementPolicy::Delegate methods. + // If |error| is not NULL, it will be filled with an error message if the + // requested extension action (install, modify status, etc.) is not permitted. + bool ExtensionManagementPolicyImpl(string16* error) const; + void LeaveManagedModeImpl(); void FinalizeEnter(bool result); @@ -68,16 +94,21 @@ class ManagedMode : public BrowserList::Observer, virtual bool PlatformConfirmEnter(); virtual bool PlatformConfirmLeave(); - virtual bool IsInManagedModeImpl(); - virtual void SetInManagedMode(bool in_managed_mode); + virtual bool IsInManagedModeImpl() const; + + // Enables or disables managed mode and registers or unregisters it with the + // ManagementPolicy. If |newly_managed_profile| is NULL, managed mode will + // be disabled. Otherwise, managed mode will be enabled for that profile + // (typically |managed_profile_|, but other values are possible during + // testing). + virtual void SetInManagedMode(Profile* newly_managed_profile); content::NotificationRegistrar registrar_; - // The managed profile. This is non-NULL only while we're entering - // managed mode. - const Profile* managed_profile_; std::set<Browser*> browsers_to_close_; std::vector<EnterCallback> callbacks_; + + DISALLOW_COPY_AND_ASSIGN(ManagedMode); }; #endif // CHROME_BROWSER_MANAGED_MODE_H_ diff --git a/chrome/browser/managed_mode_unittest.cc b/chrome/browser/managed_mode_unittest.cc index 5f35d5d..881ba4e 100644 --- a/chrome/browser/managed_mode_unittest.cc +++ b/chrome/browser/managed_mode_unittest.cc @@ -37,12 +37,17 @@ class FakeManagedMode : public ManagedMode { } // ManagedMode overrides: - virtual bool IsInManagedModeImpl() OVERRIDE { + virtual bool IsInManagedModeImpl() const OVERRIDE { return in_managed_mode_; } - virtual void SetInManagedMode(bool in_managed_mode) OVERRIDE { - in_managed_mode_ = in_managed_mode; + virtual void SetInManagedMode(Profile* newly_managed_profile) OVERRIDE { + if (newly_managed_profile) { + ASSERT_TRUE(!managed_profile_ || + managed_profile_ == newly_managed_profile); + } + managed_profile_ = newly_managed_profile; + in_managed_mode_ = (newly_managed_profile != NULL); } virtual bool PlatformConfirmEnter() OVERRIDE { @@ -96,7 +101,7 @@ class MockCallback : public base::RefCountedThreadSafe<MockCallback> { } void CheckManagedMode(bool success) { - EXPECT_EQ(managed_mode_->IsInManagedModeImpl(), success); + EXPECT_EQ(success, managed_mode_->IsInManagedModeImpl()); DidEnterManagedMode(success); } @@ -151,8 +156,9 @@ TEST_F(ManagedModeTest, AlreadyInManagedMode) { BrowserFixture managed_mode_browser(&managed_mode_, &managed_mode_profile_); BrowserFixture other_browser(&managed_mode_, &other_profile_); - // If we're already in managed mode, entering should immediately succeed. - managed_mode_.SetInManagedMode(true); + // If we're already in managed mode in this profile, entering should + // immediately succeed. + managed_mode_.SetInManagedMode(&managed_mode_profile_); managed_mode_.EnterManagedModeForTesting(&managed_mode_profile_, CreateExpectedCallback(true)); } @@ -228,3 +234,18 @@ TEST_F(ManagedModeTest, Cancelled) { managed_mode_.EnterManagedModeForTesting(&managed_mode_profile_, CreateExpectedCallback(false)); } + +TEST_F(ManagedModeTest, ExtensionManagementPolicyProvider) { + BrowserFixture managed_mode_browser(&managed_mode_, &managed_mode_profile_); + + EXPECT_TRUE(managed_mode_.UserMayLoad(NULL, NULL)); + EXPECT_TRUE(managed_mode_.UserMayModifySettings(NULL, NULL)); + + managed_mode_.SetInManagedMode(&managed_mode_profile_); + EXPECT_FALSE(managed_mode_.UserMayLoad(NULL, NULL)); + EXPECT_FALSE(managed_mode_.UserMayModifySettings(NULL, NULL)); + +#ifndef NDEBUG + EXPECT_FALSE(managed_mode_.GetDebugPolicyProviderName().empty()); +#endif +} diff --git a/chrome/browser/resources/extensions/extensions.css b/chrome/browser/resources/extensions/extensions.css index 213fbb0..02c2160 100644 --- a/chrome/browser/resources/extensions/extensions.css +++ b/chrome/browser/resources/extensions/extensions.css @@ -253,3 +253,17 @@ html[dir='rtl'] #extension-settings .trash { .may-not-disable .optional-controls { display: none; } + +.page:not(.dev-mode) #dev-controls { + display: none; +} + +/* Managed mode */ + +.page:not(.managed-mode) #managed-mode-banner { + display: none; +} + +.managed-mode .more-extensions-link { + display: none; +} diff --git a/chrome/browser/resources/extensions/extensions.html b/chrome/browser/resources/extensions/extensions.html index cd2babd..4f6b1c7 100644 --- a/chrome/browser/resources/extensions/extensions.html +++ b/chrome/browser/resources/extensions/extensions.html @@ -42,8 +42,15 @@ <input id="toggle-dev-on" type="checkbox"> <span i18n-content="extensionSettingsDeveloperMode"> </label></div> + <div id="managed-mode-banner" + class="page-banner managed-mode-banner"> + <div class="page-banner-gradient"> + <span id="managed-prefs-text" class="page-banner-text" + i18n-content="extensionSettingsManagedMode"></span> + </div> + </div> </header> - <div id="dev-controls" hidden> + <div id="dev-controls"> <button id="load-unpacked" i18n-content="extensionSettingsLoadUnpackedButton"></button> <button id="pack-extension" @@ -56,12 +63,12 @@ <div id="no-extensions"> <span id="no-extensions-message" i18n-content="extensionSettingsNoExtensions"></span> - <span id="suggest-gallery" + <span id="suggest-gallery" class="more-extensions-link" i18n-values=".innerHTML:extensionSettingsSuggestGallery"> </span> </div> <div id="footer-section"> - <a target="blank_" + <a target="blank_" class="more-extensions-link" i18n-values="href:extensionSettingsGetMoreExtensionsUrl" i18n-content="extensionSettingsGetMoreExtensions"></a> <a target="blank_" hidden diff --git a/chrome/browser/resources/extensions/extensions.js b/chrome/browser/resources/extensions/extensions.js index bfcf3e8..1fe0c19 100644 --- a/chrome/browser/resources/extensions/extensions.js +++ b/chrome/browser/resources/extensions/extensions.js @@ -223,13 +223,23 @@ cr.define('extensions', function() { }); } - if (extensionsData.developerMode) { + var pageDiv = $('extension-settings'); + if (extensionsData.managedMode) { + pageDiv.classList.add('showing-banner'); + pageDiv.classList.add('managed-mode'); + $('toggle-dev-on').disabled = true; + } else { + pageDiv.classList.remove('showing-banner'); + pageDiv.classList.remove('managed-mode'); + $('toggle-dev-on').disabled = false; + } + + if (extensionsData.developerMode && !extensionsData.managedMode) { + pageDiv.classList.add('dev-mode'); $('toggle-dev-on').checked = true; - $('extension-settings').classList.add('dev-mode'); - $('dev-controls').hidden = false; } else { + pageDiv.classList.remove('dev-mode'); $('toggle-dev-on').checked = false; - $('extension-settings').classList.remove('dev-mode'); } $('load-unpacked').disabled = extensionsData.loadUnpackedDisabled; diff --git a/chrome/browser/resources/options2/chromeos/internet_detail.html b/chrome/browser/resources/options2/chromeos/internet_detail.html index 0e3da70..19a5757e 100644 --- a/chrome/browser/resources/options2/chromeos/internet_detail.html +++ b/chrome/browser/resources/options2/chromeos/internet_detail.html @@ -453,8 +453,8 @@ <div id="network-proxy-tab" class="subpages-tab-contents"> <section> <div id="info-banner" hidden> - <span id="banner-icon" class="managed-prefs-icon"></span> - <span id="banner-text" class="managed-prefs-text"></span> + <span id="banner-icon" class="page-banner-icon"></span> + <span id="banner-text" class="page-banner-text"></span> </div> <div class="radio"> <label> diff --git a/chrome/browser/resources/options2/options.html b/chrome/browser/resources/options2/options.html index e28a48d..ab9ec85 100644 --- a/chrome/browser/resources/options2/options.html +++ b/chrome/browser/resources/options2/options.html @@ -150,9 +150,9 @@ </div> <div id="templates" hidden> - <div id="managed-prefs-banner" class="managed-prefs-banner"> - <div class="managed-prefs-gradient"> - <span id="managed-prefs-text" class="managed-prefs-text"></span> + <div id="managed-prefs-banner" class="page-banner managed-prefs-banner"> + <div class="page-banner-gradient"> + <span id="managed-prefs-text" class="page-banner-text"></span> </div> </div> </div> diff --git a/chrome/browser/resources/options2/options_page.css b/chrome/browser/resources/options2/options_page.css index e6273ff..b65aa53 100644 --- a/chrome/browser/resources/options2/options_page.css +++ b/chrome/browser/resources/options2/options_page.css @@ -109,50 +109,6 @@ div.disabled { padding-top: 0; } -.managed-prefs-banner { - background-color: white; - width: 100%; - z-index: 2; -} - -.page:not(.showing-banner) .managed-prefs-banner { - display: none; -} - -.managed-prefs-gradient { - background: -webkit-linear-gradient(rgb(255, 242, 183), - rgb(250, 230, 145)); - border: 1px solid rgb(201, 189, 141); - border-radius: 3px; - height: 25px; - margin: 9px 9px 0 9px; -} - -.main-page-banner .managed-prefs-gradient { - -webkit-margin-end: 20px; - -webkit-margin-start: 0; - margin-bottom: 9px; -} - -.managed-prefs-text { - background-image: url('chrome://theme/IDR_MANAGED'); - background-position: 5px center; - background-repeat: no-repeat; - background-size: 16px; - display: block; - line-height: 24px; - padding-left: 26px; -} - -.managed-prefs-banner.clickable:active .managed-prefs-text { - background: -webkit-linear-gradient(rgb(250, 230, 145), - rgb(255, 242, 183)); -} - -#page-container .page.showing-banner { - margin-top: 45px; -} - .page list { /* Min height is a multiple of the list item height (32) */ min-height: 192px; diff --git a/chrome/browser/resources/options2/options_page.js b/chrome/browser/resources/options2/options_page.js index 7bb67f0..c42cac4 100644 --- a/chrome/browser/resources/options2/options_page.js +++ b/chrome/browser/resources/options2/options_page.js @@ -708,7 +708,7 @@ cr.define('options', function() { } else { this.pageDiv.classList.add('showing-banner'); - var text = bannerDiv.querySelector('.managed-prefs-text'); + var text = bannerDiv.querySelector('#managed-prefs-text'); if (controlledByPolicy && !controlledByExtension) { text.textContent = loadTimeData.getString('policyManagedPrefsBannerText'); diff --git a/chrome/browser/resources/uber/uber_shared.css b/chrome/browser/resources/uber/uber_shared.css index 2a8f9bc..0fb3209 100644 --- a/chrome/browser/resources/uber/uber_shared.css +++ b/chrome/browser/resources/uber/uber_shared.css @@ -116,3 +116,48 @@ body.uber-frame section > h3 { body.uber-frame section > div:only-of-type { -webkit-box-flex: 1; } + +/* Styles for a hideable notification banner at the top of a page. + * See the Options page .managed-prefs-banner for a usage example. */ +.page.showing-banner { + margin-top: 45px; +} + +.page-banner { + background-color: white; + width: 100%; + z-index: 2; +} + +.page:not(.showing-banner) .page-banner { + display: none; +} + +.page-banner-gradient { + background: -webkit-linear-gradient(rgb(255, 242, 183), + rgb(250, 230, 145)); + border: 1px solid rgb(201, 189, 141); + border-radius: 3px; + height: 25px; + margin: 9px 9px 0 9px; +} + +.page-banner .page-banner-gradient { + -webkit-margin-end: 20px; + -webkit-margin-start: 0; + margin-bottom: 9px; +} + +.page-banner-text { + background-image: url('chrome://theme/IDR_MANAGED'); + background-position: 5px center; + background-repeat: no-repeat; + display: block; + line-height: 24px; + padding-left: 26px; +} + +.page-banner.clickable:active .page-banner-text { + background: -webkit-linear-gradient(rgb(250, 230, 145), + rgb(255, 242, 183)); +} diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc index 1605be8..a379835 100644 --- a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc +++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc @@ -14,6 +14,7 @@ #include "base/utf_string_conversions.h" #include "base/values.h" #include "base/version.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/debugger/devtools_window.h" #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_disabled_ui.h" @@ -25,6 +26,7 @@ #include "chrome/browser/extensions/unpacked_installer.h" #include "chrome/browser/extensions/updater/extension_updater.h" #include "chrome/browser/google/google_util.h" +#include "chrome/browser/managed_mode.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/background_contents.h" @@ -267,6 +269,8 @@ void ExtensionSettingsHandler::GetLocalizedValues( l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSTORE)); localized_strings->SetString("extensionSettingsPolicyControlled", l10n_util::GetStringUTF16(IDS_EXTENSIONS_POLICY_CONTROLLED)); + localized_strings->SetString("extensionSettingsManagedMode", + l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCKED_MANAGED_MODE)); localized_strings->SetString("extensionSettingsShowButton", l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_BUTTON)); localized_strings->SetString("extensionSettingsLoadUnpackedButton", @@ -501,10 +505,16 @@ void ExtensionSettingsHandler::HandleRequestExtensionsData( } results.Set("extensions", extensions_list); - Profile* profile = Profile::FromWebUI(web_ui()); - bool developer_mode = - profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode); - results.SetBoolean("developerMode", developer_mode); + if (ManagedMode::IsInManagedMode()) { + results.SetBoolean("managedMode", true); + results.SetBoolean("developerMode", false); + } else { + results.SetBoolean("managedMode", false); + Profile* profile = Profile::FromWebUI(web_ui()); + bool developer_mode = + profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode); + results.SetBoolean("developerMode", developer_mode); + } bool load_unpacked_disabled = extension_service_->extension_prefs()->ExtensionsBlacklistedByDefault(); @@ -519,6 +529,9 @@ void ExtensionSettingsHandler::HandleRequestExtensionsData( void ExtensionSettingsHandler::HandleToggleDeveloperMode( const ListValue* args) { + if (ManagedMode::IsInManagedMode()) + return; + Profile* profile = Profile::FromWebUI(web_ui()); bool developer_mode = profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode); @@ -782,6 +795,8 @@ void ExtensionSettingsHandler::MaybeRegisterForNotifications() { pref_registrar_.Init(profile->GetPrefs()); pref_registrar_.Add(prefs::kExtensionInstallDenyList, this); + local_state_pref_registrar_.Init(g_browser_process->local_state()); + local_state_pref_registrar_.Add(prefs::kInManagedMode, this); } std::vector<ExtensionPage> diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.h b/chrome/browser/ui/webui/extensions/extension_settings_handler.h index 3c6da67..7dd6610 100644 --- a/chrome/browser/ui/webui/extensions/extension_settings_handler.h +++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.h @@ -216,6 +216,7 @@ class ExtensionSettingsHandler : public content::WebUIMessageHandler, content::NotificationRegistrar registrar_; PrefChangeRegistrar pref_registrar_; + PrefChangeRegistrar local_state_pref_registrar_; DISALLOW_COPY_AND_ASSIGN(ExtensionSettingsHandler); }; diff --git a/chrome/test/functional/policy_prefs_ui.py b/chrome/test/functional/policy_prefs_ui.py index 9785127..415042d 100755 --- a/chrome/test/functional/policy_prefs_ui.py +++ b/chrome/test/functional/policy_prefs_ui.py @@ -50,11 +50,10 @@ class PolicyPrefsUITest(policy_base.PolicyTestBase): self.LoginWithTestAccount() def IsAnyBannerVisible(self): - """Returns true if any managed prefs banner is visible in the current page. - """ + """Returns true if any banner (e.g. for managed prefs) is visible.""" ret = self.ExecuteJavascript(""" var visible = false; - var banners = document.querySelectorAll('.managed-prefs-banner'); + var banners = document.querySelectorAll('.page-banner'); for (var i=0; i<banners.length; i++) { if (banners[i].parentElement.id == 'templates') continue; |