diff options
author | mnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-14 07:45:59 +0000 |
---|---|---|
committer | mnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-14 07:45:59 +0000 |
commit | d3b98c88fa50c3b6bf4644570220cf93f8ca9bea (patch) | |
tree | e2fdf54cee2d8546526ed9aca724e9f957d0fb2b | |
parent | 9473a8d2db6780ecac153c65ba8200cdb0eeb1bd (diff) | |
download | chromium_src-d3b98c88fa50c3b6bf4644570220cf93f8ca9bea.zip chromium_src-d3b98c88fa50c3b6bf4644570220cf93f8ca9bea.tar.gz chromium_src-d3b98c88fa50c3b6bf4644570220cf93f8ca9bea.tar.bz2 |
Implement support for disabling sync through configuration management.
BUG=45316
TEST=Configure SyncDisabled policy and check the UI.
Review URL: http://codereview.chromium.org/2905003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52288 0039d316-1c4b-4281-b951-d872f2087c98
27 files changed, 245 insertions, 58 deletions
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index 0ed8a0d..e06cc60 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm @@ -634,8 +634,8 @@ void RecordLastRunAppBundlePath() { << "NULL defaultProfile detected -- not doing anything"; break; } - enable = ProfileSyncService::IsSyncEnabled() && - [self keyWindowIsNotModal]; + enable = defaultProfile->IsSyncAccessible() && + [self keyWindowIsNotModal]; sync_ui_util::UpdateSyncItem(item, enable, defaultProfile); break; } @@ -848,8 +848,7 @@ void RecordLastRunAppBundlePath() { menuState_->UpdateCommandEnabled(IDC_HELP_PAGE, true); menuState_->UpdateCommandEnabled(IDC_IMPORT_SETTINGS, true); menuState_->UpdateCommandEnabled(IDC_REPORT_BUG, true); - menuState_->UpdateCommandEnabled(IDC_SYNC_BOOKMARKS, - ProfileSyncService::IsSyncEnabled()); + menuState_->UpdateCommandEnabled(IDC_SYNC_BOOKMARKS, true); menuState_->UpdateCommandEnabled(IDC_TASK_MANAGER, true); } diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 24918de..e0d797d 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -236,6 +236,9 @@ Browser::Browser(Type type, Profile* profile) tab_restore_service_->AddObserver(this); TabRestoreServiceChanged(tab_restore_service_); } + + if (profile_->GetProfileSyncService()) + profile_->GetProfileSyncService()->AddObserver(this); } Browser::~Browser() { @@ -243,6 +246,9 @@ Browser::~Browser() { DCHECK(!tabstrip_model_.HasNonPhantomTabs()); tabstrip_model_.RemoveObserver(this); + if (profile_->GetProfileSyncService()) + profile_->GetProfileSyncService()->RemoveObserver(this); + BrowserList::RemoveBrowser(this); #if defined(OS_WIN) || defined(OS_LINUX) @@ -1059,8 +1065,8 @@ void Browser::UpdateCommandsForFullscreenMode(bool is_fullscreen) { command_updater_.UpdateCommandEnabled(IDC_REPORT_BUG, show_main_ui); command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR, show_main_ui); command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, show_main_ui); - command_updater_.UpdateCommandEnabled( - IDC_SYNC_BOOKMARKS, show_main_ui && ProfileSyncService::IsSyncEnabled()); + command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS, + show_main_ui && profile_->IsSyncAccessible()); command_updater_.UpdateCommandEnabled(IDC_OPTIONS, show_main_ui); command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui); command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui); @@ -3037,6 +3043,21 @@ void Browser::Observe(NotificationType type, } } +/////////////////////////////////////////////////////////////////////////////// +// Browser, ProfileSyncServiceObserver implementation: + +void Browser::OnStateChanged() { + DCHECK(profile_->GetProfileSyncService()); + +#if !defined(OS_MACOSX) + const bool show_main_ui = (type() == TYPE_NORMAL) && !window_->IsFullscreen(); +#else + const bool show_main_ui = (type() == TYPE_NORMAL); +#endif + + command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS, + show_main_ui && profile_->IsSyncAccessible()); +} /////////////////////////////////////////////////////////////////////////////// // Browser, Command and state updating (private): diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index 2577eb4..1c0283d 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -17,6 +17,7 @@ #include "chrome/browser/sessions/session_id.h" #include "chrome/browser/sessions/tab_restore_service.h" #include "chrome/browser/shell_dialogs.h" +#include "chrome/browser/sync/profile_sync_service_observer.h" #include "chrome/browser/tabs/tab_strip_model.h" #include "chrome/browser/tab_contents/page_navigator.h" #include "chrome/browser/tab_contents/tab_contents_delegate.h" @@ -50,7 +51,8 @@ class Browser : public TabStripModelDelegate, public CommandUpdater::CommandUpdaterDelegate, public NotificationObserver, public SelectFileDialog::Listener, - public TabRestoreService::Observer { + public TabRestoreService::Observer, + public ProfileSyncServiceObserver { public: // If you change the values in this enum you'll need to update browser_proxy. // TODO(sky): move into a common place that is referenced by both ui_tests @@ -737,6 +739,9 @@ class Browser : public TabStripModelDelegate, const NotificationSource& source, const NotificationDetails& details); + // Overridden from ProfileSyncServiceObserver: + virtual void OnStateChanged(); + // Command and state updating /////////////////////////////////////////////// // Initialize state for all browser commands. diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm index aa7b325..b4d2af8 100644 --- a/chrome/browser/cocoa/browser_window_controller.mm +++ b/chrome/browser/cocoa/browser_window_controller.mm @@ -878,7 +878,7 @@ break; } case IDC_SYNC_BOOKMARKS: - enable &= ProfileSyncService::IsSyncEnabled(); + enable &= browser_->profile()->IsSyncAccessible(); sync_ui_util::UpdateSyncItem(item, enable, browser_->profile()); break; default: diff --git a/chrome/browser/cocoa/preferences_window_controller.mm b/chrome/browser/cocoa/preferences_window_controller.mm index 4065f0b..5a075cf 100644 --- a/chrome/browser/cocoa/preferences_window_controller.mm +++ b/chrome/browser/cocoa/preferences_window_controller.mm @@ -76,6 +76,11 @@ static const wchar_t* kGeneralPolicyConstrainedPrefs[] = { prefs::kHomePageIsNewTabPage }; +// Content page preferences that are potentially constrained by policy. +static const wchar_t* kContentPolicyConstrainedPrefs[] = { + prefs::kSyncManaged +}; + std::string GetNewTabUIURLString() { return URLFixerUpper::FixupURL(chrome::kChromeUINewTabURL, std::string()).possibly_invalid_spec(); @@ -412,6 +417,9 @@ class ManagedPrefsBannerState : public ManagedPrefsBannerBase { kGeneralPolicyConstrainedPrefs, arraysize(kGeneralPolicyConstrainedPrefs)); case OPTIONS_PAGE_CONTENT: + return new ManagedPrefsBannerState(controller, page, prefs, + kContentPolicyConstrainedPrefs, + arraysize(kContentPolicyConstrainedPrefs)); break; case OPTIONS_PAGE_ADVANCED: break; @@ -1235,7 +1243,7 @@ const int kDisabledIndex = 1; - (void)stopSyncAlertDidEnd:(NSAlert*)alert returnCode:(int)returnCode contextInfo:(void*)contextInfo { - DCHECK(syncService_); + DCHECK(syncService_ && !syncService_->IsManaged()); if (returnCode == NSAlertFirstButtonReturn) { syncService_->DisableForUser(); ProfileSyncService::SyncEvent(ProfileSyncService::STOP_FROM_OPTIONS); @@ -1245,7 +1253,7 @@ const int kDisabledIndex = 1; // Called when the user clicks the multi-purpose sync button in the // "Personal Stuff" pane. - (IBAction)doSyncAction:(id)sender { - DCHECK(syncService_); + DCHECK(syncService_ && !syncService_->IsManaged()); if (syncService_->HasSyncSetupCompleted()) { // If sync setup has completed that means the sync button was a // "stop syncing" button. Bring up a confirmation dialog before @@ -1292,7 +1300,7 @@ const int kDisabledIndex = 1; } - (IBAction)doSyncReauthentication:(id)sender { - DCHECK(syncService_); + DCHECK(syncService_ && !syncService_->IsManaged()); syncService_->ShowLoginDialog(); } @@ -1720,6 +1728,7 @@ const int kDisabledIndex = 1; string16 statusLabel, linkLabel; sync_ui_util::MessageType status = sync_ui_util::GetStatusLabels(syncService_, &statusLabel, &linkLabel); + bool managed = syncService_->IsManaged(); [syncButton_ setEnabled:!syncService_->WizardIsVisible()]; NSString* buttonLabel; @@ -1736,11 +1745,14 @@ const int kDisabledIndex = 1; IDS_SYNC_START_SYNC_BUTTON_LABEL); [syncCustomizeButton_ setHidden:true]; } + [syncCustomizeButton_ setEnabled:!managed]; [syncButton_ setTitle:buttonLabel]; + [syncButton_ setEnabled:!managed]; [syncStatus_ setStringValue:base::SysUTF16ToNSString(statusLabel)]; [syncLink_ setHidden:linkLabel.empty()]; [syncLink_ setTitle:base::SysUTF16ToNSString(linkLabel)]; + [syncLink_ setEnabled:!managed]; NSButtonCell* syncLinkCell = static_cast<NSButtonCell*>([syncLink_ cell]); if (!syncStatusNoErrorBackgroundColor_) { diff --git a/chrome/browser/configuration_policy_pref_store.cc b/chrome/browser/configuration_policy_pref_store.cc index d2ada7c..43c9caa 100644 --- a/chrome/browser/configuration_policy_pref_store.cc +++ b/chrome/browser/configuration_policy_pref_store.cc @@ -224,6 +224,19 @@ bool ConfigurationPolicyPrefStore::ApplyProxyPolicy(PolicyType policy, return result; } +bool ConfigurationPolicyPrefStore::ApplySyncPolicy(PolicyType policy, + Value* value) { + if (policy == ConfigurationPolicyStore::kPolicySyncDisabled) { + bool disable_sync; + if (value->GetAsBoolean(&disable_sync) && disable_sync) + prefs_->Set(prefs::kSyncManaged, value); + else + delete value; + return true; + } + return false; +} + bool ConfigurationPolicyPrefStore::ApplyPolicyFromMap(PolicyType policy, Value* value, const PolicyToPreferenceMapEntry map[], int size) { const PolicyToPreferenceMapEntry* end = map + size; @@ -242,6 +255,9 @@ void ConfigurationPolicyPrefStore::Apply(PolicyType policy, Value* value) { if (ApplyProxyPolicy(policy, value)) return; + if (ApplySyncPolicy(policy, value)) + return; + if (ApplyPolicyFromMap(policy, value, simple_policy_map_, arraysize(simple_policy_map_))) return; @@ -249,4 +265,3 @@ void ConfigurationPolicyPrefStore::Apply(PolicyType policy, Value* value) { // Other policy implementations go here. NOTIMPLEMENTED(); } - diff --git a/chrome/browser/configuration_policy_pref_store.h b/chrome/browser/configuration_policy_pref_store.h index b87f42176..5035cba 100644 --- a/chrome/browser/configuration_policy_pref_store.h +++ b/chrome/browser/configuration_policy_pref_store.h @@ -85,8 +85,11 @@ class ConfigurationPolicyPrefStore : public PrefStore, // of |value| in the case that the policy is proxy-specific. bool ApplyProxyPolicy(PolicyType policy, Value* value); + // Handles sync-related policies. Returns true if the policy was handled. + // Assumes ownership of |value| in that case. + bool ApplySyncPolicy(PolicyType policy, Value* value); + DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyPrefStore); }; #endif // CHROME_BROWSER_CONFIGURATION_POLICY_PREF_STORE_H_ - diff --git a/chrome/browser/configuration_policy_provider.cc b/chrome/browser/configuration_policy_provider.cc index a6d2f52..3156c59 100644 --- a/chrome/browser/configuration_policy_provider.cc +++ b/chrome/browser/configuration_policy_provider.cc @@ -39,7 +39,9 @@ const InternalPolicyValueMapEntry kPolicyValueMap[] = { { ConfigurationPolicyStore::kPolicySafeBrowsingEnabled, Value::TYPE_BOOLEAN, "SafeBrowsingEnabled" }, { ConfigurationPolicyStore::kPolicyMetricsReportingEnabled, - Value::TYPE_BOOLEAN, "MetricsReportingEnabled" } + Value::TYPE_BOOLEAN, "MetricsReportingEnabled" }, + { ConfigurationPolicyStore::kPolicySyncDisabled, + Value::TYPE_BOOLEAN, "SyncDisabled" } }; } // namespace diff --git a/chrome/browser/configuration_policy_store.h b/chrome/browser/configuration_policy_store.h index 20d0b36..8cdbe77 100644 --- a/chrome/browser/configuration_policy_store.h +++ b/chrome/browser/configuration_policy_store.h @@ -26,6 +26,7 @@ class ConfigurationPolicyStore { kPolicyDnsPrefetchingEnabled, kPolicySafeBrowsingEnabled, kPolicyMetricsReportingEnabled, + kPolicySyncDisabled }; static const int kPolicyNoProxyServerMode = 0; @@ -43,4 +44,3 @@ class ConfigurationPolicyStore { }; #endif // CHROME_BROWSER_CONFIGURATION_POLICY_STORE_H_ - diff --git a/chrome/browser/dom_ui/new_tab_page_sync_handler.cc b/chrome/browser/dom_ui/new_tab_page_sync_handler.cc index f711709..b7349fd 100644 --- a/chrome/browser/dom_ui/new_tab_page_sync_handler.cc +++ b/chrome/browser/dom_ui/new_tab_page_sync_handler.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -98,6 +98,7 @@ NewTabPageSyncHandler::MessageType DOMMessageHandler* NewTabPageSyncHandler::Attach(DOMUI* dom_ui) { sync_service_ = dom_ui->GetProfile()->GetProfileSyncService(); DCHECK(sync_service_); // This shouldn't get called by an incognito NTP. + DCHECK(!sync_service_->IsManaged()); // And neither if sync is managed. sync_service_->AddObserver(this); return DOMMessageHandler::Attach(dom_ui); } @@ -121,8 +122,8 @@ void NewTabPageSyncHandler::HideSyncStatusSection() { void NewTabPageSyncHandler::BuildAndSendSyncStatus() { DCHECK(!waiting_for_initial_page_load_); - // Hide the sync status section if sync is disabled entirely. - if (!sync_service_) { + // Hide the sync status section if sync is managed or disabled entirely. + if (!sync_service_ || sync_service_->IsManaged()) { HideSyncStatusSection(); return; } @@ -149,6 +150,8 @@ void NewTabPageSyncHandler::BuildAndSendSyncStatus() { void NewTabPageSyncHandler::HandleSyncLinkClicked(const Value* value) { DCHECK(!waiting_for_initial_page_load_); DCHECK(sync_service_); + if (!sync_service_->IsSyncEnabled()) + return; if (sync_service_->HasSyncSetupCompleted()) { if (sync_service_->GetAuthError().state() == GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS || diff --git a/chrome/browser/dom_ui/new_tab_ui.cc b/chrome/browser/dom_ui/new_tab_ui.cc index 8bcb449..6d2bdde 100644 --- a/chrome/browser/dom_ui/new_tab_ui.cc +++ b/chrome/browser/dom_ui/new_tab_ui.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -465,9 +465,8 @@ NewTabUI::NewTabUI(TabContents* contents) AddMessageHandler((new MetricsHandler())->Attach(this)); if (WebResourcesEnabled()) AddMessageHandler((new TipsHandler())->Attach(this)); - if (ProfileSyncService::IsSyncEnabled()) { + if (GetProfile()->IsSyncAccessible()) AddMessageHandler((new NewTabPageSyncHandler())->Attach(this)); - } if (Extension::AppsAreEnabled()) { ExtensionsService* service = GetProfile()->GetExtensionsService(); // We might not have an ExtensionsService (on ChromeOS when not logged in diff --git a/chrome/browser/gtk/bookmark_bar_gtk.cc b/chrome/browser/gtk/bookmark_bar_gtk.cc index 16bf8a4..7712196 100644 --- a/chrome/browser/gtk/bookmark_bar_gtk.cc +++ b/chrome/browser/gtk/bookmark_bar_gtk.cc @@ -998,7 +998,7 @@ gboolean BookmarkBarGtk::OnButtonPressed(GtkWidget* sender, gboolean BookmarkBarGtk::OnSyncErrorButtonPressed(GtkWidget* sender, GdkEventButton* event) { if (sender == sync_error_button_) { - DCHECK(sync_service_); + DCHECK(sync_service_ && !sync_service_->IsManaged()); sync_service_->ShowLoginDialog(); } diff --git a/chrome/browser/gtk/options/content_page_gtk.cc b/chrome/browser/gtk/options/content_page_gtk.cc index 540766c..4cc89ed 100644 --- a/chrome/browser/gtk/options/content_page_gtk.cc +++ b/chrome/browser/gtk/options/content_page_gtk.cc @@ -42,6 +42,11 @@ namespace { // Background color for the status label when it's showing an error. static const GdkColor kSyncLabelErrorBgColor = GDK_COLOR_RGB(0xff, 0x9a, 0x9a); +// Set of preferences which might be unavailable for editing when managed. +const wchar_t* kContentManagablePrefs[] = { + prefs::kSyncManaged +}; + // Helper for WrapLabelAtAllocationHack. void OnLabelAllocate(GtkWidget* label, GtkAllocation* allocation) { gtk_widget_set_size_request(label, allocation->width, -1); @@ -80,7 +85,9 @@ ContentPageGtk::ContentPageGtk(Profile* profile) sync_customize_button_(NULL), privacy_dashboard_link_(NULL), initializing_(true), - sync_service_(NULL) { + sync_service_(NULL), + managed_prefs_banner_(profile->GetPrefs(), kContentManagablePrefs, + arraysize(kContentManagablePrefs)) { if (profile->GetProfileSyncService()) { sync_service_ = profile->GetProfileSyncService(); sync_service_->AddObserver(this); @@ -89,6 +96,7 @@ ContentPageGtk::ContentPageGtk(Profile* profile) // Prepare the group options layout. scoped_ptr<OptionsLayoutBuilderGtk> options_builder(OptionsLayoutBuilderGtk::CreateOptionallyCompactLayout()); + options_builder->AddWidget(managed_prefs_banner_.banner_widget(), false); if (sync_service_) { options_builder->AddOptionGroup( l10n_util::GetStringUTF8(IDS_SYNC_OPTIONS_GROUP_NAME), @@ -391,6 +399,7 @@ void ContentPageGtk::UpdateSyncControls() { string16 link_label; std::string customize_button_label; std::string button_label; + bool managed = sync_service_->IsManaged(); bool sync_setup_completed = sync_service_->HasSyncSetupCompleted(); bool status_has_error = sync_ui_util::GetStatusLabels(sync_service_, &status_label, &link_label) == sync_ui_util::SYNC_ERROR; @@ -408,7 +417,7 @@ void ContentPageGtk::UpdateSyncControls() { UTF16ToUTF8(status_label).c_str()); #if !defined(OS_CHROMEOS) gtk_widget_set_sensitive(sync_start_stop_button_, - !sync_service_->WizardIsVisible()); + !sync_service_->WizardIsVisible() && !managed); gtk_button_set_label(GTK_BUTTON(sync_start_stop_button_), button_label.c_str()); #endif @@ -417,6 +426,7 @@ void ContentPageGtk::UpdateSyncControls() { sync_setup_completed && !status_has_error); gtk_button_set_label(GTK_BUTTON(sync_customize_button_), customize_button_label.c_str()); + gtk_widget_set_sensitive(sync_customize_button_, !managed); #if !defined(OS_CHROMEOS) gtk_chrome_link_button_set_label(GTK_CHROME_LINK_BUTTON(sync_action_link_), UTF16ToUTF8(link_label).c_str()); @@ -427,6 +437,7 @@ void ContentPageGtk::UpdateSyncControls() { gtk_widget_set_no_show_all(sync_action_link_background_, FALSE); gtk_widget_show(sync_action_link_background_); } + gtk_widget_set_sensitive(sync_action_link_, !managed); #endif if (status_has_error) { gtk_widget_modify_bg(sync_status_label_background_, GTK_STATE_NORMAL, @@ -529,7 +540,7 @@ void ContentPageGtk::OnPasswordRadioToggled(GtkWidget* widget) { } void ContentPageGtk::OnSyncStartStopButtonClicked(GtkWidget* widget) { - DCHECK(sync_service_); + DCHECK(sync_service_ && !sync_service_->IsManaged()); if (sync_service_->HasSyncSetupCompleted()) { GtkWidget* dialog = gtk_message_dialog_new( @@ -567,12 +578,13 @@ void ContentPageGtk::OnSyncStartStopButtonClicked(GtkWidget* widget) { void ContentPageGtk::OnSyncCustomizeButtonClicked(GtkWidget* widget) { // sync_customize_button_ should be invisible if sync is not yet set up. - DCHECK(sync_service_->HasSyncSetupCompleted()); + DCHECK(sync_service_ && !sync_service_->IsManaged() && + sync_service_->HasSyncSetupCompleted()); sync_service_->ShowChooseDataTypes(); } void ContentPageGtk::OnSyncActionLinkClicked(GtkWidget* widget) { - DCHECK(sync_service_); + DCHECK(sync_service_ && !sync_service_->IsManaged()); sync_service_->ShowLoginDialog(); } diff --git a/chrome/browser/gtk/options/content_page_gtk.h b/chrome/browser/gtk/options/content_page_gtk.h index 024eec8..f7239e0 100644 --- a/chrome/browser/gtk/options/content_page_gtk.h +++ b/chrome/browser/gtk/options/content_page_gtk.h @@ -9,6 +9,7 @@ #include "app/gtk_signal.h" #include "chrome/browser/autofill/personal_data_manager.h" +#include "chrome/browser/gtk/options/managed_prefs_banner_gtk.h" #include "chrome/browser/options_page_base.h" #include "chrome/browser/pref_member.h" #include "chrome/browser/profile.h" @@ -103,6 +104,9 @@ class ContentPageGtk : public OptionsPageBase, // and NULL-ed out on destruction. ProfileSyncService* sync_service_; + // Tracks managed preference warning banner state. + ManagedPrefsBannerGtk managed_prefs_banner_; + DISALLOW_COPY_AND_ASSIGN(ContentPageGtk); }; diff --git a/chrome/browser/managed_prefs_banner_base.cc b/chrome/browser/managed_prefs_banner_base.cc index 5251d7f..09dcde6 100644 --- a/chrome/browser/managed_prefs_banner_base.cc +++ b/chrome/browser/managed_prefs_banner_base.cc @@ -12,11 +12,15 @@ ManagedPrefsBannerBase::ManagedPrefsBannerBase(PrefService* prefs, const wchar_t** relevant_prefs, size_t count) - : prefs_(prefs), - relevant_prefs_(relevant_prefs, relevant_prefs + count) { - for (PrefSet::const_iterator pref(relevant_prefs_.begin()); - pref != relevant_prefs_.end(); ++pref) - prefs_->AddPrefObserver(pref->c_str(), this); + : prefs_(prefs) { + for (size_t i = 0; i < count; ++i) { + // Ignore prefs that are not registered. + const wchar_t* pref = relevant_prefs[i]; + if (prefs->FindPreference(pref)) { + prefs_->AddPrefObserver(pref, this); + relevant_prefs_.insert(pref); + } + } } ManagedPrefsBannerBase::~ManagedPrefsBannerBase() { diff --git a/chrome/browser/managed_prefs_banner_base.h b/chrome/browser/managed_prefs_banner_base.h index f0013ca..b06d0c8 100644 --- a/chrome/browser/managed_prefs_banner_base.h +++ b/chrome/browser/managed_prefs_banner_base.h @@ -40,7 +40,7 @@ class ManagedPrefsBannerBase : public NotificationObserver { private: PrefService* prefs_; typedef std::set<std::wstring> PrefSet; - const PrefSet relevant_prefs_; + PrefSet relevant_prefs_; DISALLOW_COPY_AND_ASSIGN(ManagedPrefsBannerBase); }; diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index 89c50f4..570371b 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -277,6 +277,11 @@ URLRequestContextGetter* Profile::GetDefaultRequestContext() { return default_request_context_; } +bool Profile::IsSyncAccessible() { + ProfileSyncService* syncService = GetProfileSyncService(); + return syncService && !syncService->IsManaged(); +} + #if defined(OS_WIN) #include "chrome/browser/password_manager/password_store_win.h" #elif defined(OS_MACOSX) @@ -1642,9 +1647,6 @@ TokenService* ProfileImpl::GetTokenService() { } ProfileSyncService* ProfileImpl::GetProfileSyncService() { - if (!ProfileSyncService::IsSyncEnabled()) { - return NULL; - } if (!sync_service_.get()) InitSyncService(); return sync_service_.get(); diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h index 59019cb..16bea36 100644 --- a/chrome/browser/profile.h +++ b/chrome/browser/profile.h @@ -452,6 +452,10 @@ class Profile { return 0 == accessibility_pause_level_; } + // Checks whether sync is configurable by the user. Returns false if sync is + // disabled or controlled by configuration management. + bool IsSyncAccessible(); + protected: static URLRequestContextGetter* default_request_context_; diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc index 055f039..7ee7bf2 100644 --- a/chrome/browser/sync/profile_sync_service.cc +++ b/chrome/browser/sync/profile_sync_service.cc @@ -126,6 +126,16 @@ void ProfileSyncService::Initialize() { InitSettings(); RegisterPreferences(); + // Watch the preference that indicates sync is managed so we can take + // appropriate action. + pref_sync_managed_.Init(prefs::kSyncManaged, profile_->GetPrefs(), this); + + // For now, the only thing we can do through policy is to turn sync off. + if (IsManaged()) { + DisableForUser(); + return; + } + if (!profile()->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted)) { DisableForUser(); // Clean up in case of previous crash / setup abort. @@ -218,6 +228,8 @@ void ProfileSyncService::RegisterPreferences() { pref_service->RegisterBooleanPref(prefs::kKeepEverythingSynced, enable_by_default); + + pref_service->RegisterBooleanPref(prefs::kSyncManaged, false); } void ProfileSyncService::ClearPreferences() { @@ -732,6 +744,17 @@ void ProfileSyncService::Observe(NotificationType type, FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged()); break; } + case NotificationType::PREF_CHANGED: { + std::wstring* pref_name = Details<std::wstring>(details).ptr(); + if (*pref_name == prefs::kSyncManaged) { + FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged()); + if (*pref_sync_managed_) + DisableForUser(); + else if (HasSyncSetupCompleted()) + StartUp(); + } + break; + } default: { NOTREACHED(); } @@ -750,12 +773,18 @@ void ProfileSyncService::SyncEvent(SyncEventCodes code) { UMA_HISTOGRAM_ENUMERATION("Sync.EventCodes", code, MAX_SYNC_EVENT_CODE); } +// static bool ProfileSyncService::IsSyncEnabled() { // We have switches::kEnableSync just in case we need to change back to // sync-disabled-by-default on a platform. return !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableSync); } +bool ProfileSyncService::IsManaged() { + // Some tests use ProfileSyncServiceMock which doesn't have a profile. + return profile_ && profile_->GetPrefs()->GetBoolean(prefs::kSyncManaged); +} + bool ProfileSyncService::ShouldPushChanges() { // True only after all bootstrapping has succeeded: the sync backend // is initialized, all enabled data types are consistent with one diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h index 5b36e0b..e88d852 100644 --- a/chrome/browser/sync/profile_sync_service.h +++ b/chrome/browser/sync/profile_sync_service.h @@ -14,10 +14,12 @@ #include "base/scoped_ptr.h" #include "base/time.h" #include "chrome/browser/google_service_auth_error.h" +#include "chrome/browser/pref_member.h" #include "chrome/browser/sync/glue/data_type_controller.h" #include "chrome/browser/sync/glue/data_type_manager.h" #include "chrome/browser/sync/glue/sync_backend_host.h" #include "chrome/browser/sync/notification_method.h" +#include "chrome/browser/sync/profile_sync_service_observer.h" #include "chrome/browser/sync/sync_setup_wizard.h" #include "chrome/browser/sync/syncable/model_type.h" #include "chrome/browser/sync/unrecoverable_error_handler.h" @@ -31,21 +33,6 @@ class NotificationType; class Profile; class ProfileSyncFactory; -// Various UI components such as the New Tab page can be driven by observing -// the ProfileSyncService through this interface. -class ProfileSyncServiceObserver { - public: - // When one of the following events occurs, OnStateChanged() is called. - // Observers should query the service to determine what happened. - // - We initialized successfully. - // - There was an authentication error and the user needs to reauthenticate. - // - The sync servers are unavailable at this time. - // - Credentials are now in flight for authentication. - virtual void OnStateChanged() = 0; - protected: - virtual ~ProfileSyncServiceObserver() { } -}; - // ProfileSyncService is the layer between browser subsystems like bookmarks, // and the sync backend. Each subsystem is logically thought of as being // a sync datatype. @@ -258,6 +245,10 @@ class ProfileSyncService : public browser_sync::SyncFrontend, // command-line switches). static bool IsSyncEnabled(); + // Retuns whether sync is managed, i.e. controlled by configuration + // management. If so, the user is not allowed to configure sync. + bool IsManaged(); + // UnrecoverableErrorHandler implementation. virtual void OnUnrecoverableError( const tracked_objects::Location& from_here, @@ -442,6 +433,10 @@ class ProfileSyncService : public browser_sync::SyncFrontend, ScopedRunnableMethodFactory<ProfileSyncService> scoped_runnable_method_factory_; + // The preference that controls whether sync is under control by configuration + // management. + BooleanPrefMember pref_sync_managed_; + DISALLOW_COPY_AND_ASSIGN(ProfileSyncService); }; diff --git a/chrome/browser/sync/profile_sync_service_observer.h b/chrome/browser/sync/profile_sync_service_observer.h new file mode 100644 index 0000000..2bd967c --- /dev/null +++ b/chrome/browser/sync/profile_sync_service_observer.h @@ -0,0 +1,23 @@ +// Copyright (c) 2010 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_SYNC_PROFILE_SYNC_SERVICE_OBSERVER_H_ +#define CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_OBSERVER_H_ + +// Various UI components such as the New Tab page can be driven by observing +// the ProfileSyncService through this interface. +class ProfileSyncServiceObserver { + public: + // When one of the following events occurs, OnStateChanged() is called. + // Observers should query the service to determine what happened. + // - We initialized successfully. + // - There was an authentication error and the user needs to reauthenticate. + // - The sync servers are unavailable at this time. + // - Credentials are now in flight for authentication. + virtual void OnStateChanged() = 0; + protected: + virtual ~ProfileSyncServiceObserver() { } +}; + +#endif // CHROME_BROWSER_SYNC_PROFILE_SYNC_SERVICE_OBSERVER_H_ diff --git a/chrome/browser/sync/profile_sync_service_startup_unittest.cc b/chrome/browser/sync/profile_sync_service_startup_unittest.cc index 21e6648..63df954 100644 --- a/chrome/browser/sync/profile_sync_service_startup_unittest.cc +++ b/chrome/browser/sync/profile_sync_service_startup_unittest.cc @@ -121,6 +121,40 @@ TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(StartNormal)) { service_->Initialize(); } +TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(ManagedStartup)) { + // Disable sync through policy. + profile_.GetPrefs()->SetBoolean(prefs::kSyncManaged, true); + + EXPECT_CALL(factory_, CreateDataTypeManager(_, _)).Times(0); + EXPECT_CALL(observer_, OnStateChanged()).Times(1); + + // Service should not be started by Initialize() since it's managed. + service_->Initialize(); +} + +TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(SwitchManaged)) { + DataTypeManagerMock* data_type_manager = SetUpDataTypeManager(); + EXPECT_CALL(*data_type_manager, Configure(_)).Times(1); + EXPECT_CALL(observer_, OnStateChanged()).Times(3); + + service_->Initialize(); + + // The service should stop when switching to managed mode. + Mock::VerifyAndClearExpectations(data_type_manager); + EXPECT_CALL(*data_type_manager, state()). + WillOnce(Return(DataTypeManager::CONFIGURED)); + EXPECT_CALL(*data_type_manager, Stop()).Times(1); + EXPECT_CALL(observer_, OnStateChanged()).Times(2); + profile_.GetPrefs()->SetBoolean(prefs::kSyncManaged, true); + + // When switching back to unmanaged, the state should change, but the service + // should not start up automatically (kSyncSetupCompleted will be false). + Mock::VerifyAndClearExpectations(data_type_manager); + EXPECT_CALL(factory_, CreateDataTypeManager(_, _)).Times(0); + EXPECT_CALL(observer_, OnStateChanged()).Times(1); + profile_.GetPrefs()->ClearPref(prefs::kSyncManaged); +} + TEST_F(ProfileSyncServiceStartupTest, SKIP_MACOSX(StartFailure)) { DataTypeManagerMock* data_type_manager = SetUpDataTypeManager(); DataTypeManager::ConfigureResult result = diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc index df28f40..ce8e4f9 100644 --- a/chrome/browser/sync/sync_ui_util.cc +++ b/chrome/browser/sync/sync_ui_util.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -163,7 +163,7 @@ MessageType GetStatus(ProfileSyncService* service) { } bool ShouldShowSyncErrorButton(ProfileSyncService* service) { - return service && service->HasSyncSetupCompleted() && + return service && !service->IsManaged() && service->HasSyncSetupCompleted() && (GetStatus(service) == sync_ui_util::SYNC_ERROR); } @@ -182,7 +182,7 @@ void OpenSyncMyBookmarksDialog( Profile* profile, ProfileSyncService::SyncEventCodes code) { ProfileSyncService* service = profile->GetOriginalProfile()->GetProfileSyncService(); - if (!service) { + if (!service || !service->IsSyncEnabled()) { LOG(DFATAL) << "OpenSyncMyBookmarksDialog called with sync disabled"; return; } diff --git a/chrome/browser/views/bookmark_bar_view.cc b/chrome/browser/views/bookmark_bar_view.cc index a4de470..984744c 100644 --- a/chrome/browser/views/bookmark_bar_view.cc +++ b/chrome/browser/views/bookmark_bar_view.cc @@ -1187,7 +1187,7 @@ void BookmarkBarView::ButtonPressed(views::Button* sender, // Show the login wizard if the user clicked the re-login button. if (sender->tag() == kSyncErrorButtonTag) { DCHECK(sender == sync_error_button_); - DCHECK(sync_service_); + DCHECK(sync_service_ && !sync_service_->IsManaged()); sync_service_->ShowLoginDialog(); return; } diff --git a/chrome/browser/views/options/content_page_view.cc b/chrome/browser/views/options/content_page_view.cc index 1d25651..093c90d 100644 --- a/chrome/browser/views/options/content_page_view.cc +++ b/chrome/browser/views/options/content_page_view.cc @@ -24,6 +24,7 @@ #include "chrome/browser/sync/sync_ui_util.h" #include "chrome/browser/sync/sync_setup_wizard.h" #include "chrome/browser/views/importer_view.h" +#include "chrome/browser/views/options/managed_prefs_banner_view.h" #include "chrome/browser/views/options/options_group_view.h" #include "chrome/browser/views/options/passwords_exceptions_window_view.h" #include "chrome/common/chrome_switches.h" @@ -49,6 +50,12 @@ const int kFormAutofillRadioGroup = 202; // Background color for the status label when it's showing an error. static const SkColor kSyncLabelErrorBgColor = SkColorSetRGB(0xff, 0x9a, 0x9a); +// All content related preferences that are potentially managed by policy. We'll +// display the warning banner if one of these have the managed bit set. +const wchar_t* kContentPolicyConstrainedPrefs[] = { + prefs::kSyncManaged +}; + static views::Background* CreateErrorBackground() { return views::Background::CreateSolidBackground(kSyncLabelErrorBgColor); } @@ -136,7 +143,7 @@ void ContentPageView::ButtonPressed( gfx::Rect(), new ImporterView(profile(), importer::ALL))->Show(); } else if (sender == sync_start_stop_button_) { - DCHECK(sync_service_); + DCHECK(sync_service_ && !sync_service_->IsManaged()); if (sync_service_->HasSyncSetupCompleted()) { ConfirmMessageBoxDialog::RunWithCustomConfiguration( @@ -170,7 +177,7 @@ void ContentPageView::LinkActivated(views::Link* source, int event_flags) { return; } if (source == sync_action_link_) { - DCHECK(sync_service_); + DCHECK(sync_service_ && !sync_service_->IsManaged()); sync_service_->ShowLoginDialog(); return; } @@ -197,6 +204,11 @@ void ContentPageView::InitControlLayout() { column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, GridLayout::USE_PREF, 0, 0); + layout->StartRow(0, single_column_view_set_id); + layout->AddView( + new ManagedPrefsBannerView(profile()->GetPrefs(), + kContentPolicyConstrainedPrefs, + arraysize(kContentPolicyConstrainedPrefs))); if (sync_service_) { layout->StartRow(0, single_column_view_set_id); InitSyncGroup(); @@ -489,6 +501,7 @@ void ContentPageView::UpdateSyncControls() { std::wstring link_label; std::wstring customize_button_label; std::wstring button_label; + bool managed = sync_service_->IsManaged(); bool sync_setup_completed = sync_service_->HasSyncSetupCompleted(); bool status_has_error = sync_ui_util::GetStatusLabels(sync_service_, &status_label, &link_label) == sync_ui_util::SYNC_ERROR; @@ -503,12 +516,15 @@ void ContentPageView::UpdateSyncControls() { } sync_status_label_->SetText(status_label); - sync_start_stop_button_->SetEnabled(!sync_service_->WizardIsVisible()); + sync_start_stop_button_->SetEnabled( + !sync_service_->WizardIsVisible() && !managed); sync_start_stop_button_->SetLabel(button_label); sync_customize_button_->SetLabel(customize_button_label); sync_customize_button_->SetVisible(sync_setup_completed && !status_has_error); + sync_customize_button_->SetEnabled(!managed); sync_action_link_->SetText(link_label); sync_action_link_->SetVisible(!link_label.empty()); + sync_action_link_->SetEnabled(!managed); if (status_has_error) { sync_status_label_->set_background(CreateErrorBackground()); diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 9e098d5..424b011 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -874,6 +874,10 @@ const wchar_t kSyncThemes[] = L"sync.themes"; const wchar_t kSyncTypedUrls[] = L"sync.typed_urls"; const wchar_t kSyncExtensions[] = L"sync.extensions"; +// Boolean used by enterprise configuration management in order to lock down +// sync. +const wchar_t kSyncManaged[] = L"sync.managed"; + // Create web application shortcut dialog preferences. const wchar_t kWebAppCreateOnDesktop[] = L"browser.web_app.create_on_desktop"; const wchar_t kWebAppCreateInAppsMenu[] = diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 360b655..4a00675 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -319,6 +319,7 @@ extern const wchar_t kSyncAutofill[]; extern const wchar_t kSyncThemes[]; extern const wchar_t kSyncTypedUrls[]; extern const wchar_t kSyncExtensions[]; +extern const wchar_t kSyncManaged[]; extern const wchar_t kWebAppCreateOnDesktop[]; extern const wchar_t kWebAppCreateInAppsMenu[]; |