diff options
author | munjal@chromium.org <munjal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-21 21:59:26 +0000 |
---|---|---|
committer | munjal@chromium.org <munjal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-21 21:59:26 +0000 |
commit | aae9eeb10159ca2e345408f74d8425a41bb81ab4 (patch) | |
tree | a1843a6f019e1f08f214ac4e11e8346a6614ec8a | |
parent | 4e57c88872d08f8e98ee1bae3258ba38e4694d87 (diff) | |
download | chromium_src-aae9eeb10159ca2e345408f74d8425a41bb81ab4.zip chromium_src-aae9eeb10159ca2e345408f74d8425a41bb81ab4.tar.gz chromium_src-aae9eeb10159ca2e345408f74d8425a41bb81ab4.tar.bz2 |
Implement sync data type controller and UI for syncing notifications:
- Add class AppNotificationDataTypeController
- Add resources and other things needed for sync UI for app notifications
- Add command line flag to enable/disable app notifications sync.
Review URL: http://codereview.chromium.org/8320017
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@106786 0039d316-1c4b-4281-b951-d872f2087c98
24 files changed, 530 insertions, 4 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 26c5bd7..96bfaeb 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -4696,6 +4696,12 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_FLAGS_SYNC_TABS_DESCRIPTION" desc="Description for the flag to enable syncing the open tabs datatype"> Enable open tabs in the sync options. This allows syncing your open tabs to other clients. </message> + <message name="IDS_FLAGS_SYNC_APP_NOTIFICATIONS_NAME" desc="Title for the flag to enable syncing the app notifications datatype"> + Enable syncing app notifications + </message> + <message name="IDS_FLAGS_SYNC_APP_NOTIFICATIONS_DESCRIPTION" desc="Description for the flag to enable syncing the app notifications datatype"> + Enable app notifications in the sync options. This allows syncing notifications received from your apps to other clients. + </message> <if expr="pp_ifdef('android')"> <message name="IDS_FLAGS_SYNC_TYPED_URLS_NAME" desc="Title for the flag to enable syncing the TypedUrl datatype"> Enable syncing typed URLs @@ -10325,6 +10331,9 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_SYNC_DATATYPE_TABS" desc="Open Tabs, one of the data types that we allow syncing."> Open Tabs </message> + <message name="IDS_SYNC_DATATYPE_APP_NOTIFICATIONS" desc="App notifications, one of the data types that we allow syncing."> + App Notifications + </message> <!-- Encryption tab of the configure sync dialog --> <if expr="not pp_ifdef('use_titlecase')"> diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 19780ef..2ad644f 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc @@ -308,6 +308,13 @@ const Experiment kExperiments[] = { SINGLE_VALUE_TYPE(switches::kEnableSyncSearchEngines) }, { + "sync-app-notifications", + IDS_FLAGS_SYNC_APP_NOTIFICATIONS_NAME, + IDS_FLAGS_SYNC_APP_NOTIFICATIONS_DESCRIPTION, + kOsAll, + SINGLE_VALUE_TYPE(switches::kEnableSyncAppNotifications) + }, + { "enable-smooth-scrolling", // FLAGS:RECORD_UMA IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_NAME, IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_DESCRIPTION, diff --git a/chrome/browser/resources/sync_setup_overlay.html b/chrome/browser/resources/sync_setup_overlay.html index da782e8..2002e22 100644 --- a/chrome/browser/resources/sync_setup_overlay.html +++ b/chrome/browser/resources/sync_setup_overlay.html @@ -238,6 +238,14 @@ il8n-values="title:searchEngines" name="dataTypeLabel"></label> </div> + <div id="app-notifications-item" class="sync-item-show"> + <input id="app-notifications-checkbox" type="checkbox" + name="dataTypeCheckbox"> + <label for="app-notifications-checkbox" + i18n-content="appNotifications" + il8n-values="title:appNotifications" + name="dataTypeLabel"></label> + </div> </div> </div> </div> diff --git a/chrome/browser/resources/sync_setup_overlay.js b/chrome/browser/resources/sync_setup_overlay.js index a60b29b..2876331 100644 --- a/chrome/browser/resources/sync_setup_overlay.js +++ b/chrome/browser/resources/sync_setup_overlay.js @@ -250,6 +250,8 @@ cr.define('options', function() { "syncTypedUrls": syncAll || $('typed-urls-checkbox').checked, "syncApps": syncAll || $('apps-checkbox').checked, "syncSearchEngines": syncAll || $('search-engines-checkbox').checked, + "syncAppNotifications": syncAll || + $('app-notifications-checkbox').checked, "syncSessions": syncAll || $('sessions-checkbox').checked, "encryptAllData": encryptAllData, "usePassphrase": usePassphrase, @@ -356,6 +358,12 @@ cr.define('options', function() { } else { $('sessions-item').className = "sync-item-hide"; } + if (args.appNotificationsRegistered) { + $('app-notifications-checkbox').checked = args.syncAppNotifications; + $('app-notifications-item').className = "sync-item-show"; + } else { + $('app-notifications-item').className = "sync-item-hide"; + } this.setCheckboxesToKeepEverythingSynced_(args.syncAllDataTypes); }, diff --git a/chrome/browser/sync/glue/app_notification_data_type_controller.cc b/chrome/browser/sync/glue/app_notification_data_type_controller.cc new file mode 100644 index 0000000..e1a272d --- /dev/null +++ b/chrome/browser/sync/glue/app_notification_data_type_controller.cc @@ -0,0 +1,97 @@ +// Copyright (c) 2011 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. + +#include "chrome/browser/sync/glue/app_notification_data_type_controller.h" + +#include "base/metrics/histogram.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/extensions/app_notification_manager.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/sync/api/syncable_service.h" +#include "chrome/browser/sync/glue/generic_change_processor.h" +#include "chrome/browser/sync/profile_sync_factory.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/common/chrome_notification_types.h" +#include "content/public/browser/notification_source.h" + +namespace browser_sync { + +AppNotificationDataTypeController::AppNotificationDataTypeController( + ProfileSyncFactory* profile_sync_factory, + Profile* profile, + ProfileSyncService* sync_service) + : FrontendDataTypeController(profile_sync_factory, + profile, + sync_service) { +} + +AppNotificationDataTypeController::~AppNotificationDataTypeController() { + CleanUpState(); +} + +syncable::ModelType AppNotificationDataTypeController::type() const { + return syncable::APP_NOTIFICATIONS; +} + +void AppNotificationDataTypeController::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK_EQ(chrome::NOTIFICATION_APP_NOTIFICATION_MANAGER_LOADED, type); + registrar_.RemoveAll(); + DCHECK_EQ(state_, MODEL_STARTING); + state_ = ASSOCIATING; + Associate(); +} + +// We want to start the AppNotificationManager before we begin associating. +bool AppNotificationDataTypeController::StartModels() { + AppNotificationManager* manager = GetAppNotificationManager(); + DCHECK(manager); + if (manager->loaded()) + return true; // Continue to Associate(). + + // Add an observer and continue when the AppNotificationManager is loaded. + registrar_.Add(this, chrome::NOTIFICATION_APP_NOTIFICATION_MANAGER_LOADED, + content::Source<AppNotificationManager>(manager)); + return false; // Don't continue Associate(). +} + +// Cleanup for our extra registrar usage. +void AppNotificationDataTypeController::CleanUpState() { + registrar_.RemoveAll(); +} + +void AppNotificationDataTypeController::CreateSyncComponents() { + ProfileSyncFactory::SyncComponents sync_components = + profile_sync_factory_->CreateAppNotificationSyncComponents( + sync_service_, this); + set_model_associator(sync_components.model_associator); + set_change_processor(sync_components.change_processor); +} + +void AppNotificationDataTypeController::RecordUnrecoverableError( + const tracked_objects::Location& from_here, + const std::string& message) { + UMA_HISTOGRAM_COUNTS("Sync.AppNotificationRunFailures", 1); +} + +void AppNotificationDataTypeController::RecordAssociationTime( + base::TimeDelta time) { + UMA_HISTOGRAM_TIMES("Sync.AppNotificationAssociationTime", time); +} + +void AppNotificationDataTypeController::RecordStartFailure(StartResult result) { + UMA_HISTOGRAM_ENUMERATION("Sync.AppNotificationStartFailures", + result, + MAX_START_RESULT); +} + +AppNotificationManager* +AppNotificationDataTypeController::GetAppNotificationManager() { + return profile_->GetExtensionService()->app_notification_manager(); +} + +} // namespace browser_sync diff --git a/chrome/browser/sync/glue/app_notification_data_type_controller.h b/chrome/browser/sync/glue/app_notification_data_type_controller.h new file mode 100644 index 0000000..407d9c9 --- /dev/null +++ b/chrome/browser/sync/glue/app_notification_data_type_controller.h @@ -0,0 +1,59 @@ +// Copyright (c) 2011 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_GLUE_APP_NOTIFICATION_DATA_TYPE_CONTROLLER_H__ +#define CHROME_BROWSER_SYNC_GLUE_APP_NOTIFICATION_DATA_TYPE_CONTROLLER_H__ +#pragma once + +#include <string> + +#include "base/compiler_specific.h" +#include "chrome/browser/sync/glue/frontend_data_type_controller.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" + +class AppNotificationManager; + +namespace browser_sync { + +class AppNotificationDataTypeController + : public FrontendDataTypeController, + public content::NotificationObserver { + public: + AppNotificationDataTypeController( + ProfileSyncFactory* profile_sync_factory, + Profile* profile, + ProfileSyncService* sync_service); + virtual ~AppNotificationDataTypeController(); + + // FrontendDataTypeController implementation. + virtual syncable::ModelType type() const OVERRIDE; + + // NotificationObserver interface. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + // Overridden in test to control creation and init order. + virtual AppNotificationManager* GetAppNotificationManager(); + + private: + // FrontendDataTypeController implementations. + virtual bool StartModels() OVERRIDE; + virtual void CleanUpState() OVERRIDE; + virtual void CreateSyncComponents() OVERRIDE; + virtual void RecordUnrecoverableError( + const tracked_objects::Location& from_here, + const std::string& message) OVERRIDE; + virtual void RecordAssociationTime(base::TimeDelta time) OVERRIDE; + virtual void RecordStartFailure(StartResult result) OVERRIDE; + + content::NotificationRegistrar registrar_; + + DISALLOW_COPY_AND_ASSIGN(AppNotificationDataTypeController); +}; + +} // namespace browser_sync + +#endif // CHROME_BROWSER_SYNC_GLUE_APP_NOTIFICATION_DATA_TYPE_CONTROLLER_H__ diff --git a/chrome/browser/sync/glue/app_notification_data_type_controller_unittest.cc b/chrome/browser/sync/glue/app_notification_data_type_controller_unittest.cc new file mode 100644 index 0000000..466717f --- /dev/null +++ b/chrome/browser/sync/glue/app_notification_data_type_controller_unittest.cc @@ -0,0 +1,250 @@ +// Copyright (c) 2011 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. + +#include "base/bind.h" +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/task.h" +#include "base/tracked_objects.h" +#include "chrome/browser/extensions/app_notification_manager.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/sync/glue/app_notification_data_type_controller.h" +#include "chrome/browser/sync/glue/change_processor_mock.h" +#include "chrome/browser/sync/glue/data_type_controller_mock.h" +#include "chrome/browser/sync/glue/model_associator_mock.h" +#include "chrome/browser/sync/profile_sync_factory_mock.h" +#include "chrome/browser/sync/profile_sync_service_mock.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/browser/notification_service.h" +#include "testing/gtest/include/gtest/gtest.h" + +using browser_sync::AppNotificationDataTypeController; +using browser_sync::ChangeProcessorMock; +using browser_sync::DataTypeController; +using browser_sync::ModelAssociatorMock; +using browser_sync::StartCallback; +using testing::_; +using testing::DoAll; +using testing::InvokeWithoutArgs; +using testing::Return; +using testing::SetArgumentPointee; + +class TestAppNotificationDataTypeController + : public AppNotificationDataTypeController { + public: + TestAppNotificationDataTypeController( + ProfileSyncFactory* profile_sync_factory, + Profile* profile, + ProfileSyncService* sync_service) + : AppNotificationDataTypeController(profile_sync_factory, + profile, + sync_service), + manager_(new AppNotificationManager(profile_)) { + } + + virtual AppNotificationManager* GetAppNotificationManager() { + return manager_.get(); + } + + private: + scoped_refptr<AppNotificationManager> manager_; +}; + +class AppNotificationDataTypeControllerTest + : public testing::Test { + public: + AppNotificationDataTypeControllerTest() + : ui_thread_(BrowserThread::UI, &ui_loop_), + file_thread_(BrowserThread::FILE) { + } + + virtual void SetUp() { + ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI)); + file_thread_.Start(); + + profile_.reset(new TestingProfile()); + model_associator_ = new ModelAssociatorMock(); + change_processor_ = new ChangeProcessorMock(); + profile_sync_factory_.reset(new ProfileSyncFactoryMock( + model_associator_, change_processor_)); + app_notif_dtc_ = new TestAppNotificationDataTypeController( + profile_sync_factory_.get(), + profile_.get(), + &service_); + } + + virtual void TearDown() { } + + protected: + // Waits until the file thread executes all tasks queued up so far. + static void WaitForFileThread() { + ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI)); + // Post a task on the file thread that will post a task back on the + // UI thread to quit the loop. + BrowserThread::PostTask(BrowserThread::FILE, + FROM_HERE, + base::Bind(&PostQuitToUIThread)); + // Now run the message loop until quit is called. + MessageLoop::current()->Run(); + } + + // Posts quit task on the UI thread. + static void PostQuitToUIThread() { + ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + BrowserThread::PostTask(BrowserThread::UI, + FROM_HERE, + new MessageLoop::QuitTask()); + } + + void InitAndLoadManager() { + app_notif_dtc_->GetAppNotificationManager()->Init(); + WaitForFileThread(); + } + + void SetAssociateExpectations() { + EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). + WillRepeatedly(Return(true)); + EXPECT_CALL(*profile_sync_factory_, + CreateAppNotificationSyncComponents(_, _)); + EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). + WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true))); + EXPECT_CALL(*model_associator_, AssociateModels(_)). + WillRepeatedly(Return(true)); + EXPECT_CALL(service_, ActivateDataType(_, _, _)); + } + + void SetStopExpectations() { + EXPECT_CALL(service_, DeactivateDataType(_)); + EXPECT_CALL(*model_associator_, DisassociateModels(_)); + } + + void PumpLoop() { + ui_loop_.RunAllPending(); + } + + MessageLoop ui_loop_; + BrowserThread ui_thread_; + BrowserThread file_thread_; + scoped_ptr<TestingProfile> profile_; + scoped_refptr<TestAppNotificationDataTypeController> app_notif_dtc_; + scoped_ptr<ProfileSyncFactoryMock> profile_sync_factory_; + ProfileSyncServiceMock service_; + ModelAssociatorMock* model_associator_; + ChangeProcessorMock* change_processor_; + StartCallback start_callback_; +}; + +// When notification manager is ready, sync assocation should happen +// successfully. +TEST_F(AppNotificationDataTypeControllerTest, StartManagerReady) { + InitAndLoadManager(); + + EXPECT_EQ(DataTypeController::NOT_RUNNING, app_notif_dtc_->state()); + SetAssociateExpectations(); + EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _)); + app_notif_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run)); + EXPECT_EQ(DataTypeController::RUNNING, app_notif_dtc_->state()); +} + +// When notification manager is not ready, sync assocation should wait +// until loaded event is seen. +TEST_F(AppNotificationDataTypeControllerTest, StartManagerNotReady) { + EXPECT_EQ(DataTypeController::NOT_RUNNING, app_notif_dtc_->state()); + SetAssociateExpectations(); + EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _)); + app_notif_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run)); + EXPECT_EQ(DataTypeController::MODEL_STARTING, app_notif_dtc_->state()); + + // Unblock file thread and wait for it to finish all tasks. + // Send the notification that the TemplateURLService has started. + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_APP_NOTIFICATION_MANAGER_LOADED, + content::Source<AppNotificationManager>( + app_notif_dtc_->GetAppNotificationManager()), + content::NotificationService::NoDetails()); + EXPECT_EQ(DataTypeController::RUNNING, app_notif_dtc_->state()); +} + +TEST_F(AppNotificationDataTypeControllerTest, StartFirstRun) { + InitAndLoadManager(); + SetAssociateExpectations(); + EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). + WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(true))); + EXPECT_CALL(start_callback_, Run(DataTypeController::OK_FIRST_RUN, _)); + app_notif_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run)); +} + +TEST_F(AppNotificationDataTypeControllerTest, StartOk) { + InitAndLoadManager(); + SetAssociateExpectations(); + EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). + WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true))); + EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _)); + app_notif_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run)); +} + +TEST_F(AppNotificationDataTypeControllerTest, StartAssociationFailed) { + InitAndLoadManager(); + EXPECT_CALL(*profile_sync_factory_, + CreateAppNotificationSyncComponents(_, _)); + EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). + WillRepeatedly(Return(true)); + EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). + WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true))); + EXPECT_CALL(*model_associator_, AssociateModels(_)). + WillRepeatedly(DoAll( + browser_sync::SetSyncError(syncable::APP_NOTIFICATIONS), + Return(false))); + + EXPECT_CALL(start_callback_, Run(DataTypeController::ASSOCIATION_FAILED, _)); + app_notif_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run)); + EXPECT_EQ(DataTypeController::DISABLED, app_notif_dtc_->state()); +} + +TEST_F(AppNotificationDataTypeControllerTest, + StartAssociationTriggersUnrecoverableError) { + InitAndLoadManager(); + // Set up association to fail with an unrecoverable error. + EXPECT_CALL(*profile_sync_factory_, + CreateAppNotificationSyncComponents(_, _)); + EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). + WillRepeatedly(Return(true)); + EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). + WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false))); + EXPECT_CALL(start_callback_, Run(DataTypeController::UNRECOVERABLE_ERROR, _)); + app_notif_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run)); + EXPECT_EQ(DataTypeController::NOT_RUNNING, app_notif_dtc_->state()); +} + +TEST_F(AppNotificationDataTypeControllerTest, Stop) { + InitAndLoadManager(); + SetAssociateExpectations(); + SetStopExpectations(); + + EXPECT_EQ(DataTypeController::NOT_RUNNING, app_notif_dtc_->state()); + + EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _)); + app_notif_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run)); + EXPECT_EQ(DataTypeController::RUNNING, app_notif_dtc_->state()); + app_notif_dtc_->Stop(); + EXPECT_EQ(DataTypeController::NOT_RUNNING, app_notif_dtc_->state()); +} + +TEST_F(AppNotificationDataTypeControllerTest, OnUnrecoverableError) { + InitAndLoadManager(); + SetAssociateExpectations(); + EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). + WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true))); + EXPECT_CALL(service_, OnUnrecoverableError(_, _)). + WillOnce(InvokeWithoutArgs(app_notif_dtc_.get(), + &AppNotificationDataTypeController::Stop)); + SetStopExpectations(); + + EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _)); + app_notif_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run)); + // This should cause app_notif_dtc_->Stop() to be called. + app_notif_dtc_->OnUnrecoverableError(FROM_HERE, "Test"); + PumpLoop(); +} diff --git a/chrome/browser/sync/profile_sync_factory.h b/chrome/browser/sync/profile_sync_factory.h index b65fe21..d956d3c 100644 --- a/chrome/browser/sync/profile_sync_factory.h +++ b/chrome/browser/sync/profile_sync_factory.h @@ -172,6 +172,13 @@ class ProfileSyncFactory { virtual SyncComponents CreateSearchEngineSyncComponents( ProfileSyncService* profile_sync_service, browser_sync::UnrecoverableErrorHandler* error_handler) = 0; + + // Instantiates both a model associator and change processor for the app + // notification data type. The pointers in the return struct are owned by the + // caller. + virtual SyncComponents CreateAppNotificationSyncComponents( + ProfileSyncService* profile_sync_service, + browser_sync::UnrecoverableErrorHandler* error_handler) = 0; }; #endif // CHROME_BROWSER_SYNC_PROFILE_SYNC_FACTORY_H__ diff --git a/chrome/browser/sync/profile_sync_factory_impl.cc b/chrome/browser/sync/profile_sync_factory_impl.cc index ede961c..c219624 100644 --- a/chrome/browser/sync/profile_sync_factory_impl.cc +++ b/chrome/browser/sync/profile_sync_factory_impl.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/command_line.h" +#include "chrome/browser/extensions/app_notification_manager.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_settings_backend.h" #include "chrome/browser/prefs/pref_model_associator.h" @@ -11,6 +12,7 @@ #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/sync/api/syncable_service.h" #include "chrome/browser/sync/glue/app_data_type_controller.h" +#include "chrome/browser/sync/glue/app_notification_data_type_controller.h" #include "chrome/browser/sync/glue/autofill_change_processor.h" #include "chrome/browser/sync/glue/autofill_data_type_controller.h" #include "chrome/browser/sync/glue/autofill_model_associator.h" @@ -49,6 +51,7 @@ #include "content/browser/browser_thread.h" using browser_sync::AppDataTypeController; +using browser_sync::AppNotificationDataTypeController; using browser_sync::AutofillChangeProcessor; using browser_sync::AutofillDataTypeController; using browser_sync::AutofillProfileDataTypeController; @@ -177,6 +180,13 @@ void ProfileSyncFactoryImpl::RegisterDataTypes(ProfileSyncService* pss) { pss->RegisterDataTypeController( new SearchEngineDataTypeController(this, profile_, pss)); } + + // App notifications sync is disabled by default. Register only if + // explicitly enabled. + if (command_line_->HasSwitch(switches::kEnableSyncAppNotifications)) { + pss->RegisterDataTypeController( + new AppNotificationDataTypeController(this, profile_, pss)); + } } DataTypeManager* ProfileSyncFactoryImpl::CreateDataTypeManager( @@ -383,3 +393,22 @@ ProfileSyncFactoryImpl::CreateSearchEngineSyncComponents( change_processor); return SyncComponents(sync_service_adapter, change_processor); } + +ProfileSyncFactory::SyncComponents +ProfileSyncFactoryImpl::CreateAppNotificationSyncComponents( + ProfileSyncService* profile_sync_service, + browser_sync::UnrecoverableErrorHandler* error_handler) { + base::WeakPtr<SyncableService> notif_sync_service = + profile_->GetExtensionService()->app_notification_manager()->AsWeakPtr(); + DCHECK(notif_sync_service); + sync_api::UserShare* user_share = profile_sync_service->GetUserShare(); + GenericChangeProcessor* change_processor = + new GenericChangeProcessor(error_handler, + notif_sync_service, + user_share); + SyncableServiceAdapter* sync_service_adapter = + new SyncableServiceAdapter(syncable::APP_NOTIFICATIONS, + notif_sync_service, + change_processor); + return SyncComponents(sync_service_adapter, change_processor); +} diff --git a/chrome/browser/sync/profile_sync_factory_impl.h b/chrome/browser/sync/profile_sync_factory_impl.h index 27063a5..f7e7494 100644 --- a/chrome/browser/sync/profile_sync_factory_impl.h +++ b/chrome/browser/sync/profile_sync_factory_impl.h @@ -88,6 +88,10 @@ class ProfileSyncFactoryImpl : public ProfileSyncFactory { ProfileSyncService* profile_sync_service, browser_sync::UnrecoverableErrorHandler* error_handler); + virtual SyncComponents CreateAppNotificationSyncComponents( + ProfileSyncService* profile_sync_service, + browser_sync::UnrecoverableErrorHandler* error_handler); + private: Profile* profile_; CommandLine* command_line_; diff --git a/chrome/browser/sync/profile_sync_factory_mock.cc b/chrome/browser/sync/profile_sync_factory_mock.cc index 46bcddc..fc3af4f 100644 --- a/chrome/browser/sync/profile_sync_factory_mock.cc +++ b/chrome/browser/sync/profile_sync_factory_mock.cc @@ -27,6 +27,11 @@ ProfileSyncFactoryMock::ProfileSyncFactoryMock( InvokeWithoutArgs( this, &ProfileSyncFactoryMock::MakeSyncComponents)); + ON_CALL(*this, CreateAppNotificationSyncComponents(_, _)). + WillByDefault( + InvokeWithoutArgs( + this, + &ProfileSyncFactoryMock::MakeSyncComponents)); } ProfileSyncFactoryMock::~ProfileSyncFactoryMock() {} diff --git a/chrome/browser/sync/profile_sync_factory_mock.h b/chrome/browser/sync/profile_sync_factory_mock.h index efbb7b9..0d184d1 100644 --- a/chrome/browser/sync/profile_sync_factory_mock.h +++ b/chrome/browser/sync/profile_sync_factory_mock.h @@ -84,6 +84,10 @@ class ProfileSyncFactoryMock : public ProfileSyncFactory { SyncComponents( ProfileSyncService* profile_sync_service, browser_sync::UnrecoverableErrorHandler* error_handler)); + MOCK_METHOD2(CreateAppNotificationSyncComponents, + SyncComponents( + ProfileSyncService* profile_sync_service, + browser_sync::UnrecoverableErrorHandler* error_handler)); private: SyncComponents MakeSyncComponents(); diff --git a/chrome/browser/sync/resources/configure.html b/chrome/browser/sync/resources/configure.html index 2ce7d3b..6bb13e6 100644 --- a/chrome/browser/sync/resources/configure.html +++ b/chrome/browser/sync/resources/configure.html @@ -373,6 +373,13 @@ html[os='mac'] input[type='submit'] { } else {
document.getElementById("sessionsItem").className = "sync-item-hide";
}
+ if (args.appNotificationsRegistered) {
+ document.getElementById("appNotificationsCheckbox").checked =
+ args.syncAppNotifications;
+ document.getElementById("appNotificationsItem").className = "sync-item-show";
+ } else {
+ document.getElementById("appNotificationsItem").className = "sync-item-hide";
+ }
setCheckboxesToKeepEverythingSynced(args.syncAllDataTypes); } @@ -465,6 +472,7 @@ html[os='mac'] input[type='submit'] { "syncApps": syncAll || f.appsCheckbox.checked,
"syncSearchEngines": syncAll || f.searchEnginesCheckbox.checked, "syncSessions": syncAll || f.sessionsCheckbox.checked, + "syncAppNotifications": syncAll || f.appNotificationsCheckbox.checked, "usePassphrase": (getRadioCheckedValue() == 'explicit'), "passphrase": f.passphrase.value }); @@ -625,7 +633,13 @@ html[os='mac'] input[type='submit'] { <label id="searchEnginesCheckboxLabel" name="dataTypeLabel" for="searchEnginesCheckbox" i18n-content="searchengines" il8n-values="title:searchengines"></label> - </div> + </div> + <div class="sync-item-show" id="appNotificationsItem"> + <input id="appNotificationsCheckbox" name="dataTypeCheckbox" type="checkbox"> + <label id="appNotificationsCheckboxLabel" name="dataTypeLabel" + for="appNotificationsCheckbox" i18n-content="appnotifications" + il8n-values="title:appnotifications"></label> + </div> </div> </div> </div> diff --git a/chrome/browser/sync/sync_setup_flow.cc b/chrome/browser/sync/sync_setup_flow.cc index e831831..a4d13b0 100644 --- a/chrome/browser/sync/sync_setup_flow.cc +++ b/chrome/browser/sync/sync_setup_flow.cc @@ -142,6 +142,8 @@ void SyncSetupFlow::GetArgsForConfigure(ProfileSyncService* service, registered_types.count(syncable::SEARCH_ENGINES) > 0); args->SetBoolean("sessionsRegistered", registered_types.count(syncable::SESSIONS) > 0); + args->SetBoolean("appNotificationsRegistered", + registered_types.count(syncable::APP_NOTIFICATIONS) > 0); args->SetBoolean("syncBookmarks", service->profile()->GetPrefs()->GetBoolean(prefs::kSyncBookmarks)); args->SetBoolean("syncPreferences", @@ -162,6 +164,8 @@ void SyncSetupFlow::GetArgsForConfigure(ProfileSyncService* service, service->profile()->GetPrefs()->GetBoolean(prefs::kSyncTypedUrls)); args->SetBoolean("syncApps", service->profile()->GetPrefs()->GetBoolean(prefs::kSyncApps)); + args->SetBoolean("syncAppNotifications", + service->profile()->GetPrefs()->GetBoolean(prefs::kSyncAppNotifications)); args->SetBoolean("encryptionEnabled", !CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableSyncEncryption)); diff --git a/chrome/browser/sync/sync_setup_wizard_unittest.cc b/chrome/browser/sync/sync_setup_wizard_unittest.cc index bbe7673..e08c91d 100644 --- a/chrome/browser/sync/sync_setup_wizard_unittest.cc +++ b/chrome/browser/sync/sync_setup_wizard_unittest.cc @@ -314,7 +314,8 @@ TEST_F(SyncSetupWizardTest, ChooseDataTypesSetsPrefs) { "\"syncPreferences\":true,\"syncThemes\":false,\"syncPasswords\":false," "\"syncAutofill\":false,\"syncExtensions\":false,\"syncTypedUrls\":true," "\"syncApps\":true,\"syncSearchEngines\":false,\"syncSessions\":false," - "\"usePassphrase\":false,\"encryptAllData\":false}"; + "\"syncAppNotifications\":false,\"usePassphrase\":false," + "\"encryptAllData\":false}"; data_type_choices_value.Append(new StringValue(data_type_choices)); // Simulate the user choosing data types; bookmarks, prefs, typed URLS, and @@ -333,6 +334,8 @@ TEST_F(SyncSetupWizardTest, ChooseDataTypesSetsPrefs) { EXPECT_EQ(1U, service_->chosen_data_types_.count(syncable::TYPED_URLS)); EXPECT_EQ(1U, service_->chosen_data_types_.count(syncable::APPS)); EXPECT_EQ(0U, service_->chosen_data_types_.count(syncable::SEARCH_ENGINES)); + EXPECT_EQ(0U, service_->chosen_data_types_.count( + syncable::APP_NOTIFICATIONS)); } TEST_F(SyncSetupWizardTest, EnterPassphraseRequired) { diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc index 6ba45e8..ff6e9df 100644 --- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc +++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc @@ -308,6 +308,8 @@ void NTPResourceCache::CreateNewTabHTML() { l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_SEARCH_ENGINES)); localized_strings.SetString("foreignsessions", l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_TABS)); + localized_strings.SetString("appnotifications", + l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_APP_NOTIFICATIONS)); localized_strings.SetString("closedwindowmultiple", l10n_util::GetStringUTF16(IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_MULTIPLE)); localized_strings.SetString("attributionintro", diff --git a/chrome/browser/ui/webui/options/personal_options_handler.cc b/chrome/browser/ui/webui/options/personal_options_handler.cc index 80bdd68..acc3da7 100644 --- a/chrome/browser/ui/webui/options/personal_options_handler.cc +++ b/chrome/browser/ui/webui/options/personal_options_handler.cc @@ -189,6 +189,8 @@ void PersonalOptionsHandler::GetLocalizedValues( l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_SEARCH_ENGINES)); localized_strings->SetString("syncsessions", l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_TABS)); + localized_strings->SetString("syncappnotifications", + l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_APP_NOTIFICATIONS)); #if defined(OS_CHROMEOS) localized_strings->SetString("account", diff --git a/chrome/browser/ui/webui/sync_setup_handler.cc b/chrome/browser/ui/webui/sync_setup_handler.cc index 414743b..82cc1f5 100644 --- a/chrome/browser/ui/webui/sync_setup_handler.cc +++ b/chrome/browser/ui/webui/sync_setup_handler.cc @@ -138,6 +138,12 @@ bool GetConfiguration(const std::string& json, SyncConfiguration* config) { if (sync_apps) config->data_types.insert(syncable::APPS); + bool sync_app_notifications; + if (!result->GetBoolean("syncAppNotifications", &sync_app_notifications)) + return false; + if (sync_app_notifications) + config->data_types.insert(syncable::APP_NOTIFICATIONS); + // Encryption settings. if (!result->GetBoolean("encryptAllData", &config->encrypt_all)) return false; @@ -279,6 +285,7 @@ void SyncSetupHandler::GetStaticLocalizedValues( { "apps", IDS_SYNC_DATATYPE_APPS }, { "searchEngines", IDS_SYNC_DATATYPE_SEARCH_ENGINES }, { "openTabs", IDS_SYNC_DATATYPE_TABS }, + { "appNotifications", IDS_SYNC_DATATYPE_APP_NOTIFICATIONS }, { "syncZeroDataTypesError", IDS_SYNC_ZERO_DATA_TYPES_ERROR }, { "serviceUnavailableError", IDS_SYNC_SETUP_ABORTED_BY_PENDING_CLEAR }, { "encryptAllLabel", IDS_SYNC_ENCRYPT_ALL_LABEL }, diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index b251337..95ee107 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2137,6 +2137,8 @@ 'browser/status_icons/status_tray.h', 'browser/sync/glue/app_data_type_controller.cc', 'browser/sync/glue/app_data_type_controller.h', + 'browser/sync/glue/app_notification_data_type_controller.cc', + 'browser/sync/glue/app_notification_data_type_controller.h', 'browser/sync/glue/autofill_change_processor.cc', 'browser/sync/glue/autofill_change_processor.h', 'browser/sync/glue/autofill_data_type_controller.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 425ee2b..bc8ee41 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1523,6 +1523,7 @@ 'browser/sync/backend_migrator_unittest.cc', 'browser/sync/internal_api/read_node_mock.cc', 'browser/sync/internal_api/read_node_mock.h', + 'browser/sync/glue/app_notification_data_type_controller_unittest.cc', 'browser/sync/glue/autofill_data_type_controller_unittest.cc', 'browser/sync/glue/autofill_model_associator_unittest.cc', 'browser/sync/glue/bookmark_data_type_controller_unittest.cc', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 283849c..fe98f7f 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -537,6 +537,9 @@ const char kEnableSyncTabs[] = "enable-sync-tabs"; const char kEnableSyncTabsForOtherClients[] = "enable-sync-tabs-for-other-clients"; +// Enable syncing app notifications. +const char kEnableSyncAppNotifications[] = "enable-sync-app-notifications"; + // Enables context menu for selecting groups of tabs. const char kEnableTabGroupsContextMenu[] = "enable-tab-groups-context-menu"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index e2b13f4..1d07572 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -156,6 +156,7 @@ extern const char kEnableSyncOAuth[]; extern const char kEnableSyncSearchEngines[]; extern const char kEnableSyncTabs[]; extern const char kEnableSyncTabsForOtherClients[]; +extern const char kEnableSyncAppNotifications[]; extern const char kEnableSyncedBookmarksFolder[]; extern const char kEnableTabGroupsContextMenu[]; extern const char kEnableTopSites[]; diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 0e9dfe4..e51f1c1 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -1375,6 +1375,7 @@ const char kSyncBookmarks[] = "sync.bookmarks"; const char kSyncPasswords[] = "sync.passwords"; const char kSyncPreferences[] = "sync.preferences"; const char kSyncApps[] = "sync.apps"; +const char kSyncAppNotifications[] = "sync.app_notifications"; const char kSyncAutofill[] = "sync.autofill"; const char kSyncAutofillProfile[] = "sync.autofill_profile"; const char kSyncThemes[] = "sync.themes"; @@ -1383,7 +1384,6 @@ const char kSyncExtensions[] = "sync.extensions"; const char kSyncExtensionSettings[] = "sync.extension_settings"; const char kSyncSearchEngines[] = "sync.search_engines"; const char kSyncSessions[] = "sync.sessions"; -const char kSyncAppNotifications[] = "sync.app_notifications"; // Boolean used by enterprise configuration management in order to lock down // sync. diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 12da82a..6d78ba1 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -492,6 +492,7 @@ extern const char kSyncKeepEverythingSynced[]; extern const char kSyncBookmarks[]; extern const char kSyncPasswords[]; extern const char kSyncPreferences[]; +extern const char kSyncAppNotifications[]; extern const char kSyncApps[]; extern const char kSyncAutofill[]; extern const char kSyncAutofillProfile[]; @@ -502,7 +503,6 @@ extern const char kSyncExtensionSettings[]; extern const char kSyncManaged[]; extern const char kSyncSearchEngines[]; extern const char kSyncSessions[]; -extern const char kSyncAppNotifications[]; extern const char kSyncSuppressStart[]; extern const char kGoogleServicesUsername[]; extern const char kSyncUsingOAuth[]; |