1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/sync/sessions/notification_service_sessions_router.h" 6 7#include "base/logging.h" 8#include "chrome/browser/chrome_notification_types.h" 9#include "chrome/browser/extensions/tab_helper.h" 10#include "chrome/browser/history/history_service.h" 11#include "chrome/browser/history/history_service_factory.h" 12#include "chrome/browser/profiles/profile.h" 13#include "chrome/browser/sync/glue/sync_start_util.h" 14#include "chrome/browser/sync/glue/synced_tab_delegate.h" 15#include "chrome/browser/sync/sessions/sessions_util.h" 16#include "chrome/browser/ui/browser.h" 17#include "content/public/browser/navigation_controller.h" 18#include "content/public/browser/navigation_entry.h" 19#include "content/public/browser/notification_details.h" 20#include "content/public/browser/notification_service.h" 21#include "content/public/browser/notification_source.h" 22#include "content/public/browser/web_contents.h" 23 24#if defined(ENABLE_MANAGED_USERS) 25#include "chrome/browser/supervised_user/supervised_user_service.h" 26#include "chrome/browser/supervised_user/supervised_user_service_factory.h" 27#endif 28 29using content::NavigationController; 30using content::WebContents; 31 32namespace browser_sync { 33 34NotificationServiceSessionsRouter::NotificationServiceSessionsRouter( 35 Profile* profile, const syncer::SyncableService::StartSyncFlare& flare) 36 : handler_(NULL), 37 profile_(profile), 38 flare_(flare), 39 weak_ptr_factory_(this) { 40 41 registrar_.Add(this, chrome::NOTIFICATION_TAB_PARENTED, 42 content::NotificationService::AllSources()); 43 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 44 content::NotificationService::AllSources()); 45 registrar_.Add(this, content::NOTIFICATION_NAV_LIST_PRUNED, 46 content::NotificationService::AllSources()); 47 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_CHANGED, 48 content::NotificationService::AllSources()); 49 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, 50 content::NotificationService::AllSources()); 51 registrar_.Add(this, 52 chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED, 53 content::NotificationService::AllSources()); 54 registrar_.Add(this, 55 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, 56 content::NotificationService::AllBrowserContextsAndSources()); 57 HistoryService* history_service = 58 HistoryServiceFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS); 59 if (history_service) { 60 favicon_changed_subscription_ = history_service->AddFaviconChangedCallback( 61 base::Bind(&NotificationServiceSessionsRouter::OnFaviconChanged, 62 base::Unretained(this))); 63 } 64#if defined(ENABLE_MANAGED_USERS) 65 if (profile_->IsSupervised()) { 66 SupervisedUserService* supervised_user_service = 67 SupervisedUserServiceFactory::GetForProfile(profile_); 68 supervised_user_service->AddNavigationBlockedCallback( 69 base::Bind(&NotificationServiceSessionsRouter::OnNavigationBlocked, 70 weak_ptr_factory_.GetWeakPtr())); 71 } 72#endif 73} 74 75NotificationServiceSessionsRouter::~NotificationServiceSessionsRouter() {} 76 77void NotificationServiceSessionsRouter::Observe( 78 int type, 79 const content::NotificationSource& source, 80 const content::NotificationDetails& details) { 81 switch (type) { 82 // Source<WebContents>. 83 case chrome::NOTIFICATION_TAB_PARENTED: 84 case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME: 85 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { 86 WebContents* web_contents = content::Source<WebContents>(source).ptr(); 87 SyncedTabDelegate* tab = 88 SyncedTabDelegate::ImplFromWebContents(web_contents); 89 if (!tab || tab->profile() != profile_) 90 return; 91 if (handler_) 92 handler_->OnLocalTabModified(tab); 93 if (!sessions_util::ShouldSyncTab(*tab)) 94 return; 95 break; 96 } 97 // Source<NavigationController>. 98 case content::NOTIFICATION_NAV_LIST_PRUNED: 99 case content::NOTIFICATION_NAV_ENTRY_CHANGED: 100 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: { 101 SyncedTabDelegate* tab = SyncedTabDelegate::ImplFromWebContents( 102 content::Source<NavigationController>(source).ptr()-> 103 GetWebContents()); 104 if (!tab || tab->profile() != profile_) 105 return; 106 if (handler_) 107 handler_->OnLocalTabModified(tab); 108 if (!sessions_util::ShouldSyncTab(*tab)) 109 return; 110 break; 111 } 112 case chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED: { 113 extensions::TabHelper* extension_tab_helper = 114 content::Source<extensions::TabHelper>(source).ptr(); 115 if (extension_tab_helper->web_contents()->GetBrowserContext() != 116 profile_) { 117 return; 118 } 119 if (extension_tab_helper->extension_app()) { 120 SyncedTabDelegate* tab = SyncedTabDelegate::ImplFromWebContents( 121 extension_tab_helper->web_contents()); 122 if (!tab || tab->profile() != profile_) 123 return; 124 if (handler_) 125 handler_->OnLocalTabModified(tab); 126 break; 127 } 128 return; 129 } 130 default: 131 LOG(ERROR) << "Received unexpected notification of type " << type; 132 return; 133 } 134 135 if (!flare_.is_null()) { 136 flare_.Run(syncer::SESSIONS); 137 flare_.Reset(); 138 } 139} 140 141void NotificationServiceSessionsRouter::OnNavigationBlocked( 142 content::WebContents* web_contents) { 143 SyncedTabDelegate* tab = 144 SyncedTabDelegate::ImplFromWebContents(web_contents); 145 if (!tab || !handler_) 146 return; 147 148 DCHECK(tab->profile() == profile_); 149 handler_->OnLocalTabModified(tab); 150} 151 152void NotificationServiceSessionsRouter::OnFaviconChanged( 153 const std::set<GURL>& changed_favicons) { 154 if (handler_) 155 handler_->OnFaviconPageUrlsUpdated(changed_favicons); 156} 157 158void NotificationServiceSessionsRouter::StartRoutingTo( 159 LocalSessionEventHandler* handler) { 160 DCHECK(!handler_); 161 handler_ = handler; 162} 163 164void NotificationServiceSessionsRouter::Stop() { 165 weak_ptr_factory_.InvalidateWeakPtrs(); 166 handler_ = NULL; 167} 168 169} // namespace browser_sync 170