1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/glue/theme_change_processor.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h" 821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h" 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/syncapi.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/glue/theme_util.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/theme_specifics.pb.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/themes/theme_service.h" 13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/themes/theme_service_factory.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension.h" 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_details.h" 16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_source.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_sync { 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochThemeChangeProcessor::ThemeChangeProcessor( 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UnrecoverableErrorHandler* error_handler) 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : ChangeProcessor(error_handler), 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_(NULL) { 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(error_handler); 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochThemeChangeProcessor::~ThemeChangeProcessor() {} 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ThemeChangeProcessor::Observe(NotificationType type, 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationSource& source, 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationDetails& details) { 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(running()); 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(profile_); 34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(type == NotificationType::BROWSER_THEME_CHANGED); 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_api::WriteTransaction trans(share_handle()); 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_api::WriteNode node(&trans); 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!node.InitByClientTagLookup(syncable::THEMES, 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kCurrentThemeClientTag)) { 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string err = "Could not create node with client tag: "; 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch err + kCurrentThemeClientTag); 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_pb::ThemeSpecifics old_theme_specifics = node.GetThemeSpecifics(); 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure to base new_theme_specifics on old_theme_specifics so 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // we preserve the state of use_system_theme_by_default. 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_pb::ThemeSpecifics new_theme_specifics = old_theme_specifics; 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetThemeSpecificsFromCurrentTheme(profile_, &new_theme_specifics); 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Do a write only if something actually changed so as to guard 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // against cycles. 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!AreThemeSpecificsEqual(old_theme_specifics, new_theme_specifics)) { 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch node.SetThemeSpecifics(new_theme_specifics); 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ThemeChangeProcessor::ApplyChangesFromSyncModel( 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const sync_api::BaseTransaction* trans, 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const sync_api::SyncManager::ChangeRecord* changes, 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int change_count) { 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!running()) { 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(akalin): Normally, we should only have a single change and 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // it should be an update. However, the syncapi may occasionally 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // generates multiple changes. When we fix syncapi to not do that, 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // we can remove the extra logic below. See: 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // http://code.google.com/p/chromium/issues/detail?id=41696 . 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (change_count < 1) { 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string err("Unexpected change_count: "); 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch err += change_count; 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, err); 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (change_count > 1) { 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << change_count << " theme changes detected; " 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "only applying the last one"; 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const sync_api::SyncManager::ChangeRecord& change = 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch changes[change_count - 1]; 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (change.action != sync_api::SyncManager::ChangeRecord::ACTION_UPDATE && 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch change.action != sync_api::SyncManager::ChangeRecord::ACTION_DELETE) { 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string err = "strange theme change.action " + change.action; 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, err); 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_pb::ThemeSpecifics theme_specifics; 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the action is a delete, simply use the default values for 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // ThemeSpecifics, which would cause the default theme to be set. 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (change.action != sync_api::SyncManager::ChangeRecord::ACTION_DELETE) { 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_api::ReadNode node(trans); 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!node.InitByIdLookup(change.id)) { 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error_handler()->OnUnrecoverableError(FROM_HERE, 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "Theme node lookup failed."); 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_EQ(node.GetModelType(), syncable::THEMES); 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(profile_); 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch theme_specifics = node.GetThemeSpecifics(); 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopObserving(); 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetCurrentThemeFromThemeSpecificsIfNecessary(theme_specifics, profile_); 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartObserving(); 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ThemeChangeProcessor::StartImpl(Profile* profile) { 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(profile); 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_ = profile; 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartObserving(); 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ThemeChangeProcessor::StopImpl() { 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopObserving(); 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch profile_ = NULL; 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ThemeChangeProcessor::StartObserving() { 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(profile_); 121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen VLOG(1) << "Observing BROWSER_THEME_CHANGED"; 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch notification_registrar_.Add( 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this, NotificationType::BROWSER_THEME_CHANGED, 124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Source<ThemeService>( 125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ThemeServiceFactory::GetForProfile(profile_))); 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ThemeChangeProcessor::StopObserving() { 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(profile_); 130731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "Unobserving all notifications"; 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch notification_registrar_.RemoveAll(); 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace browser_sync 135