| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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/protector/protector_service.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "chrome/browser/google/google_util.h" | |
| 9 #include "chrome/browser/prefs/pref_service.h" | |
| 10 #include "chrome/browser/protector/composite_settings_change.h" | |
| 11 #include "chrome/browser/protector/keys.h" | |
| 12 #include "chrome/browser/protector/protected_prefs_watcher.h" | |
| 13 #include "chrome/browser/protector/protector_utils.h" | |
| 14 #include "chrome/browser/protector/settings_change_global_error.h" | |
| 15 #include "chrome/browser/ui/browser.h" | |
| 16 #include "chrome/browser/ui/host_desktop.h" | |
| 17 #include "chrome/browser/ui/singleton_tabs.h" | |
| 18 #include "chrome/common/chrome_notification_types.h" | |
| 19 #include "chrome/common/pref_names.h" | |
| 20 #include "content/public/browser/notification_source.h" | |
| 21 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | |
| 22 | |
| 23 namespace protector { | |
| 24 | |
| 25 namespace { | |
| 26 | |
| 27 // Returns true if changes with URLs |url1| and |url2| can be merged. | |
| 28 bool CanMerge(const GURL& url1, const GURL& url2) { | |
| 29 VLOG(1) << "Checking if can merge " << url1.spec() << " with " << url2.spec(); | |
| 30 // All Google URLs are considered the same one. | |
| 31 if (google_util::IsGoogleHostname(url1.host(), | |
| 32 google_util::DISALLOW_SUBDOMAIN)) { | |
| 33 return google_util::IsGoogleHostname(url2.host(), | |
| 34 google_util::DISALLOW_SUBDOMAIN); | |
| 35 } | |
| 36 // Otherwise URLs must have the same domain. | |
| 37 return net::RegistryControlledDomainService::SameDomainOrHost(url1, url2); | |
| 38 } | |
| 39 | |
| 40 } // namespace | |
| 41 | |
| 42 ProtectorService::ProtectorService(Profile* profile) | |
| 43 : profile_(profile), | |
| 44 has_active_change_(false) { | |
| 45 // Start observing pref changes. | |
| 46 prefs_watcher_.reset(new ProtectedPrefsWatcher(profile)); | |
| 47 } | |
| 48 | |
| 49 ProtectorService::~ProtectorService() { | |
| 50 DCHECK(!IsShowingChange()); // Should have been dismissed by Shutdown. | |
| 51 } | |
| 52 | |
| 53 void ProtectorService::ShowChange(BaseSettingChange* change) { | |
| 54 DCHECK(change); | |
| 55 // Change instance will either be owned by |this| or deleted after this call. | |
| 56 scoped_ptr<BaseSettingChange> change_ptr(change); | |
| 57 | |
| 58 DVLOG(1) << "Init change"; | |
| 59 if (!protector::IsEnabled()) { | |
| 60 change_ptr->InitWhenDisabled(profile_); | |
| 61 return; | |
| 62 } else if (!change_ptr->Init(profile_)) { | |
| 63 LOG(WARNING) << "Error while initializing, dismissing change"; | |
| 64 return; | |
| 65 } | |
| 66 | |
| 67 Item* item_to_merge_with = FindItemToMergeWith(change_ptr.get()); | |
| 68 if (item_to_merge_with) { | |
| 69 // CompositeSettingsChange takes ownership of merged changes. | |
| 70 BaseSettingChange* existing_change = item_to_merge_with->change.release(); | |
| 71 CompositeSettingsChange* merged_change = | |
| 72 existing_change->MergeWith(change_ptr.release()); | |
| 73 item_to_merge_with->change.reset(merged_change); | |
| 74 item_to_merge_with->was_merged = true; | |
| 75 if (item_to_merge_with->error->GetBubbleView()) | |
| 76 item_to_merge_with->show_when_merged = true; | |
| 77 // Remove old GlobalError instance. Later in OnRemovedFromProfile() a new | |
| 78 // GlobalError instance will be created for the composite change. | |
| 79 item_to_merge_with->error->RemoveFromProfile(); | |
| 80 } else if (change->IsUserVisible()) { | |
| 81 Item new_item; | |
| 82 SettingsChangeGlobalError* error = | |
| 83 new SettingsChangeGlobalError(change_ptr.get(), this); | |
| 84 new_item.error.reset(error); | |
| 85 new_item.change.reset(change_ptr.release()); | |
| 86 items_.push_back(new_item); | |
| 87 // Do not show the bubble immediately if another one is active. | |
| 88 // TODO(robertshield): Add desktop context to protector, crbug.com/153771 | |
| 89 error->AddToProfile(profile_, !has_active_change_, | |
| 90 chrome::HOST_DESKTOP_TYPE_NATIVE); | |
| 91 has_active_change_ = true; | |
| 92 } else { | |
| 93 VLOG(1) << "Not showing a change because it's not user-visible."; | |
| 94 } | |
| 95 } | |
| 96 | |
| 97 bool ProtectorService::IsShowingChange() const { | |
| 98 return !items_.empty(); | |
| 99 } | |
| 100 | |
| 101 void ProtectorService::ApplyChange(BaseSettingChange* change, | |
| 102 Browser* browser) { | |
| 103 change->Apply(browser); | |
| 104 DismissChange(change); | |
| 105 } | |
| 106 | |
| 107 void ProtectorService::DiscardChange(BaseSettingChange* change, | |
| 108 Browser* browser) { | |
| 109 change->Discard(browser); | |
| 110 DismissChange(change); | |
| 111 } | |
| 112 | |
| 113 void ProtectorService::DismissChange(BaseSettingChange* change) { | |
| 114 Items::iterator item = std::find_if(items_.begin(), items_.end(), | |
| 115 MatchItemByChange(change)); | |
| 116 DCHECK(item != items_.end()); | |
| 117 item->error->RemoveFromProfile(); | |
| 118 } | |
| 119 | |
| 120 void ProtectorService::OpenTab(const GURL& url, Browser* browser) { | |
| 121 DCHECK(browser); | |
| 122 chrome::ShowSingletonTab(browser, url); | |
| 123 } | |
| 124 | |
| 125 ProtectedPrefsWatcher* ProtectorService::GetPrefsWatcher() { | |
| 126 return prefs_watcher_.get(); | |
| 127 } | |
| 128 | |
| 129 void ProtectorService::StopWatchingPrefsForTesting() { | |
| 130 prefs_watcher_.reset(); | |
| 131 } | |
| 132 | |
| 133 ProtectorService::Item* ProtectorService::FindItemToMergeWith( | |
| 134 const BaseSettingChange* change) { | |
| 135 if (!change->CanBeMerged()) | |
| 136 return NULL; | |
| 137 GURL url = change->GetNewSettingURL(); | |
| 138 for (Items::iterator item = items_.begin(); item != items_.end(); item++) { | |
| 139 if (item->change->CanBeMerged() && | |
| 140 CanMerge(url, item->change->GetNewSettingURL())) | |
| 141 return &*item; | |
| 142 } | |
| 143 return NULL; | |
| 144 } | |
| 145 | |
| 146 void ProtectorService::Shutdown() { | |
| 147 while (IsShowingChange()) | |
| 148 items_[0].error->RemoveFromProfile(); | |
| 149 } | |
| 150 | |
| 151 void ProtectorService::OnApplyChange(SettingsChangeGlobalError* error, | |
| 152 Browser* browser) { | |
| 153 DVLOG(1) << "Apply change"; | |
| 154 error->change()->Apply(browser); | |
| 155 has_active_change_ = false; | |
| 156 } | |
| 157 | |
| 158 void ProtectorService::OnDiscardChange(SettingsChangeGlobalError* error, | |
| 159 Browser* browser) { | |
| 160 DVLOG(1) << "Discard change"; | |
| 161 error->change()->Discard(browser); | |
| 162 has_active_change_ = false; | |
| 163 } | |
| 164 | |
| 165 void ProtectorService::OnDecisionTimeout(SettingsChangeGlobalError* error) { | |
| 166 DVLOG(1) << "Timeout"; | |
| 167 error->change()->Timeout(); | |
| 168 } | |
| 169 | |
| 170 void ProtectorService::OnRemovedFromProfile(SettingsChangeGlobalError* error) { | |
| 171 Items::iterator item = std::find_if(items_.begin(), items_.end(), | |
| 172 MatchItemByError(error)); | |
| 173 DCHECK(item != items_.end()); | |
| 174 | |
| 175 if (item->was_merged) { | |
| 176 bool show_new_error = !has_active_change_ || item->show_when_merged; | |
| 177 item->was_merged = false; | |
| 178 item->show_when_merged = false; | |
| 179 // Item was merged with another change instance and error has been removed, | |
| 180 // create a new one for the composite change. | |
| 181 item->error.reset(new SettingsChangeGlobalError(item->change.get(), this)); | |
| 182 // TODO(robertshield): Add desktop context to protector, crbug.com/153771 | |
| 183 item->error->AddToProfile(profile_, show_new_error, | |
| 184 chrome::HOST_DESKTOP_TYPE_NATIVE); | |
| 185 has_active_change_ = true; | |
| 186 return; | |
| 187 } | |
| 188 | |
| 189 items_.erase(item); | |
| 190 | |
| 191 // If no other change is shown and there are changes that haven't been shown | |
| 192 // yet, show the first one. | |
| 193 if (!has_active_change_) { | |
| 194 for (item = items_.begin(); item != items_.end(); ++item) { | |
| 195 if (!item->error->HasShownBubbleView()) { | |
| 196 // TODO(robertshield): Add desktop context to protector, | |
| 197 // crbug.com/153771 | |
| 198 item->error->ShowBubble(chrome::HOST_DESKTOP_TYPE_NATIVE); | |
| 199 has_active_change_ = true; | |
| 200 return; | |
| 201 } | |
| 202 } | |
| 203 } | |
| 204 } | |
| 205 | |
| 206 BaseSettingChange* ProtectorService::GetLastChange() { | |
| 207 return items_.empty() ? NULL : items_.back().change.get(); | |
| 208 } | |
| 209 | |
| 210 ProtectorService::Item::Item() | |
| 211 : was_merged(false), | |
| 212 show_when_merged(false) { | |
| 213 } | |
| 214 | |
| 215 ProtectorService::Item::~Item() { | |
| 216 } | |
| 217 | |
| 218 ProtectorService::MatchItemByChange::MatchItemByChange( | |
| 219 const BaseSettingChange* other) : other_(other) { | |
| 220 } | |
| 221 | |
| 222 bool ProtectorService::MatchItemByChange::operator()( | |
| 223 const ProtectorService::Item& item) { | |
| 224 return item.change->Contains(other_); | |
| 225 } | |
| 226 | |
| 227 ProtectorService::MatchItemByError::MatchItemByError( | |
| 228 const SettingsChangeGlobalError* other) : other_(other) { | |
| 229 } | |
| 230 | |
| 231 bool ProtectorService::MatchItemByError::operator()( | |
| 232 const ProtectorService::Item& item) { | |
| 233 return other_ == item.error.get(); | |
| 234 } | |
| 235 | |
| 236 } // namespace protector | |
| OLD | NEW |