OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/google/google_url_tracker.h" | 5 #include "chrome/browser/google/google_url_tracker.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
11 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
13 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
14 #include "chrome/browser/browser_process.h" | 14 #include "chrome/browser/browser_process.h" |
15 #include "chrome/browser/google/google_url_tracker_factory.h" | 15 #include "chrome/browser/google/google_url_tracker_factory.h" |
16 #include "chrome/browser/google/google_util.h" | 16 #include "chrome/browser/google/google_util.h" |
17 #include "chrome/browser/infobars/infobar_tab_helper.h" | 17 #include "chrome/browser/infobars/infobar_tab_helper.h" |
18 #include "chrome/browser/prefs/pref_service.h" | 18 #include "chrome/browser/prefs/pref_service.h" |
19 #include "chrome/browser/profiles/profile.h" | 19 #include "chrome/browser/profiles/profile.h" |
20 #include "chrome/browser/search_engines/template_url.h" | 20 #include "chrome/browser/search_engines/template_url.h" |
21 #include "chrome/browser/ui/tab_contents/tab_contents.h" | 21 #include "chrome/browser/ui/tab_contents/tab_contents.h" |
22 #include "chrome/common/chrome_notification_types.h" | 22 #include "chrome/common/chrome_notification_types.h" |
23 #include "chrome/common/chrome_switches.h" | 23 #include "chrome/common/chrome_switches.h" |
24 #include "chrome/common/pref_names.h" | 24 #include "chrome/common/pref_names.h" |
25 #include "content/public/browser/navigation_controller.h" | 25 #include "content/public/browser/navigation_controller.h" |
| 26 #include "content/public/browser/navigation_details.h" |
26 #include "content/public/browser/navigation_entry.h" | 27 #include "content/public/browser/navigation_entry.h" |
27 #include "content/public/browser/notification_service.h" | 28 #include "content/public/browser/notification_service.h" |
28 #include "content/public/browser/web_contents.h" | 29 #include "content/public/browser/web_contents.h" |
29 #include "content/public/common/url_fetcher.h" | 30 #include "content/public/common/url_fetcher.h" |
30 #include "grit/generated_resources.h" | 31 #include "grit/generated_resources.h" |
31 #include "net/base/load_flags.h" | 32 #include "net/base/load_flags.h" |
32 #include "net/base/net_util.h" | 33 #include "net/base/net_util.h" |
33 #include "net/url_request/url_request_context_getter.h" | 34 #include "net/url_request/url_request_context_getter.h" |
34 #include "net/url_request/url_request_status.h" | 35 #include "net/url_request/url_request_status.h" |
35 #include "ui/base/l10n/l10n_util.h" | 36 #include "ui/base/l10n/l10n_util.h" |
36 | 37 |
37 namespace { | 38 namespace { |
38 | 39 |
39 GoogleURLTrackerInfoBarDelegate* CreateInfoBar( | 40 GoogleURLTrackerInfoBarDelegate* CreateInfoBar( |
40 InfoBarTabHelper* infobar_helper, | 41 InfoBarTabHelper* infobar_helper, |
41 const GURL& search_url, | |
42 GoogleURLTracker* google_url_tracker, | 42 GoogleURLTracker* google_url_tracker, |
43 const GURL& new_google_url) { | 43 const GURL& new_google_url) { |
44 return new GoogleURLTrackerInfoBarDelegate(infobar_helper, search_url, | 44 return new GoogleURLTrackerInfoBarDelegate(infobar_helper, google_url_tracker, |
45 google_url_tracker, new_google_url); | 45 new_google_url); |
46 } | 46 } |
47 | 47 |
48 string16 GetHost(const GURL& url) { | 48 string16 GetHost(const GURL& url) { |
49 DCHECK(url.is_valid()); | 49 DCHECK(url.is_valid()); |
50 return net::StripWWW(UTF8ToUTF16(url.host())); | 50 return net::StripWWW(UTF8ToUTF16(url.host())); |
51 } | 51 } |
52 | 52 |
53 } // namespace | 53 } // namespace |
54 | 54 |
55 // GoogleURLTrackerInfoBarDelegate -------------------------------------------- | 55 // GoogleURLTrackerInfoBarDelegate -------------------------------------------- |
56 | 56 |
57 GoogleURLTrackerInfoBarDelegate::GoogleURLTrackerInfoBarDelegate( | 57 GoogleURLTrackerInfoBarDelegate::GoogleURLTrackerInfoBarDelegate( |
58 InfoBarTabHelper* infobar_helper, | 58 InfoBarTabHelper* infobar_helper, |
59 const GURL& search_url, | |
60 GoogleURLTracker* google_url_tracker, | 59 GoogleURLTracker* google_url_tracker, |
61 const GURL& new_google_url) | 60 const GURL& new_google_url) |
62 : ConfirmInfoBarDelegate(infobar_helper), | 61 : ConfirmInfoBarDelegate(infobar_helper), |
63 map_key_(infobar_helper), | 62 map_key_(infobar_helper), |
64 search_url_(search_url), | |
65 google_url_tracker_(google_url_tracker), | 63 google_url_tracker_(google_url_tracker), |
66 new_google_url_(new_google_url), | 64 new_google_url_(new_google_url), |
67 showing_(false) { | 65 showing_(false), |
| 66 pending_id_(0) { |
68 } | 67 } |
69 | 68 |
70 bool GoogleURLTrackerInfoBarDelegate::Accept() { | 69 bool GoogleURLTrackerInfoBarDelegate::Accept() { |
71 google_url_tracker_->AcceptGoogleURL(new_google_url_, true); | 70 google_url_tracker_->AcceptGoogleURL(new_google_url_, true); |
72 return false; | 71 return false; |
73 } | 72 } |
74 | 73 |
75 bool GoogleURLTrackerInfoBarDelegate::Cancel() { | 74 bool GoogleURLTrackerInfoBarDelegate::Cancel() { |
76 google_url_tracker_->CancelGoogleURL(new_google_url_); | 75 google_url_tracker_->CancelGoogleURL(new_google_url_); |
77 return false; | 76 return false; |
78 } | 77 } |
79 | 78 |
80 string16 GoogleURLTrackerInfoBarDelegate::GetLinkText() const { | 79 string16 GoogleURLTrackerInfoBarDelegate::GetLinkText() const { |
81 return l10n_util::GetStringUTF16(IDS_LEARN_MORE); | 80 return l10n_util::GetStringUTF16(IDS_LEARN_MORE); |
82 } | 81 } |
83 | 82 |
84 bool GoogleURLTrackerInfoBarDelegate::LinkClicked( | 83 bool GoogleURLTrackerInfoBarDelegate::LinkClicked( |
85 WindowOpenDisposition disposition) { | 84 WindowOpenDisposition disposition) { |
86 content::OpenURLParams params(google_util::AppendGoogleLocaleParam(GURL( | 85 content::OpenURLParams params(google_util::AppendGoogleLocaleParam(GURL( |
87 "https://www.google.com/support/chrome/bin/answer.py?answer=1618699")), | 86 "https://www.google.com/support/chrome/bin/answer.py?answer=1618699")), |
88 content::Referrer(), | 87 content::Referrer(), |
89 (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition, | 88 (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition, |
90 content::PAGE_TRANSITION_LINK, false); | 89 content::PAGE_TRANSITION_LINK, false); |
91 owner()->web_contents()->OpenURL(params); | 90 owner()->web_contents()->OpenURL(params); |
92 return false; | 91 return false; |
93 } | 92 } |
94 | 93 |
| 94 bool GoogleURLTrackerInfoBarDelegate::ShouldExpireInternal( |
| 95 const content::LoadCommittedDetails& details) const { |
| 96 int unique_id = details.entry->GetUniqueID(); |
| 97 return (unique_id != contents_unique_id()) && (unique_id != pending_id_); |
| 98 } |
| 99 |
95 void GoogleURLTrackerInfoBarDelegate::SetGoogleURL(const GURL& new_google_url) { | 100 void GoogleURLTrackerInfoBarDelegate::SetGoogleURL(const GURL& new_google_url) { |
96 DCHECK_EQ(GetHost(new_google_url_), GetHost(new_google_url)); | 101 DCHECK_EQ(GetHost(new_google_url_), GetHost(new_google_url)); |
97 new_google_url_ = new_google_url; | 102 new_google_url_ = new_google_url; |
98 } | 103 } |
99 | 104 |
100 void GoogleURLTrackerInfoBarDelegate::Show() { | 105 void GoogleURLTrackerInfoBarDelegate::Show(const GURL& search_url) { |
101 showing_ = true; | 106 if (!owner()) |
102 owner()->AddInfoBar(this); // May delete |this| on failure! | 107 return; |
| 108 StoreActiveEntryUniqueID(owner()); |
| 109 search_url_ = search_url; |
| 110 pending_id_ = 0; |
| 111 if (!showing_) { |
| 112 showing_ = true; |
| 113 owner()->AddInfoBar(this); // May delete |this| on failure! |
| 114 } |
103 } | 115 } |
104 | 116 |
105 void GoogleURLTrackerInfoBarDelegate::Close(bool redo_search) { | 117 void GoogleURLTrackerInfoBarDelegate::Close(bool redo_search) { |
106 if (redo_search && owner()) { | |
107 // Re-do the user's search on the new domain. | |
108 url_canon::Replacements<char> replacements; | |
109 const std::string& host(new_google_url_.host()); | |
110 replacements.SetHost(host.data(), url_parse::Component(0, host.length())); | |
111 GURL new_search_url(search_url_.ReplaceComponents(replacements)); | |
112 if (new_search_url.is_valid()) { | |
113 content::OpenURLParams params(new_search_url, content::Referrer(), | |
114 CURRENT_TAB, content::PAGE_TRANSITION_GENERATED, false); | |
115 owner()->web_contents()->OpenURL(params); | |
116 } | |
117 } | |
118 | |
119 if (!showing_) { | 118 if (!showing_) { |
120 // We haven't been added to a tab, so just delete ourselves. | 119 // We haven't been added to a tab, so just delete ourselves. |
121 delete this; | 120 delete this; |
122 return; | 121 return; |
123 } | 122 } |
124 | 123 |
125 // Synchronously remove ourselves from the URL tracker's list, because the | 124 // Synchronously remove ourselves from the URL tracker's list, because the |
126 // RemoveInfoBar() call below may result in either a synchronous or an | 125 // RemoveInfoBar() call below may result in either a synchronous or an |
127 // asynchronous call back to InfoBarClosed(), and it's easier to handle when | 126 // asynchronous call back to InfoBarClosed(), and it's easier to handle when |
128 // we just guarantee the removal is synchronous. | 127 // we just guarantee the removal is synchronous. |
129 google_url_tracker_->InfoBarClosed(map_key_); | 128 google_url_tracker_->InfoBarClosed(map_key_); |
130 google_url_tracker_ = NULL; | 129 google_url_tracker_ = NULL; |
131 | 130 |
132 // If we're already animating closed, we won't have an owner. Do nothing in | 131 // If we're already animating closed, we won't have an owner. Do nothing in |
133 // this case. | 132 // this case. |
134 // TODO(pkasting): For now, this can also happen if we were showing in a | 133 // TODO(pkasting): For now, this can also happen if we were showing in a |
135 // background tab that was then closed, in which case we'll have leaked and | 134 // background tab that was then closed, in which case we'll have leaked and |
136 // subsequently reached here due to GoogleURLTracker::CloseAllInfoBars(). | 135 // subsequently reached here due to GoogleURLTracker::CloseAllInfoBars(). |
137 // This case will no longer happen once infobars are refactored to own their | 136 // This case will no longer happen once infobars are refactored to own their |
138 // delegates. | 137 // delegates. |
139 if (owner()) | 138 if (!owner()) |
140 owner()->RemoveInfoBar(this); | 139 return; |
| 140 |
| 141 if (redo_search) { |
| 142 // Re-do the user's search on the new domain. |
| 143 DCHECK(search_url_.is_valid()); |
| 144 url_canon::Replacements<char> replacements; |
| 145 const std::string& host(new_google_url_.host()); |
| 146 replacements.SetHost(host.data(), url_parse::Component(0, host.length())); |
| 147 GURL new_search_url(search_url_.ReplaceComponents(replacements)); |
| 148 if (new_search_url.is_valid()) { |
| 149 content::OpenURLParams params(new_search_url, content::Referrer(), |
| 150 CURRENT_TAB, content::PAGE_TRANSITION_GENERATED, false); |
| 151 owner()->web_contents()->OpenURL(params); |
| 152 } |
| 153 } |
| 154 |
| 155 owner()->RemoveInfoBar(this); |
141 } | 156 } |
142 | 157 |
143 GoogleURLTrackerInfoBarDelegate::~GoogleURLTrackerInfoBarDelegate() { | 158 GoogleURLTrackerInfoBarDelegate::~GoogleURLTrackerInfoBarDelegate() { |
144 if (google_url_tracker_) | 159 if (google_url_tracker_) |
145 google_url_tracker_->InfoBarClosed(map_key_); | 160 google_url_tracker_->InfoBarClosed(map_key_); |
146 } | 161 } |
147 | 162 |
148 string16 GoogleURLTrackerInfoBarDelegate::GetMessageText() const { | 163 string16 GoogleURLTrackerInfoBarDelegate::GetMessageText() const { |
149 return l10n_util::GetStringFUTF16(IDS_GOOGLE_URL_TRACKER_INFOBAR_MESSAGE, | 164 return l10n_util::GetStringFUTF16(IDS_GOOGLE_URL_TRACKER_INFOBAR_MESSAGE, |
150 GetHost(new_google_url_), GetHost(google_url_tracker_->google_url_)); | 165 GetHost(new_google_url_), GetHost(google_url_tracker_->google_url_)); |
151 } | 166 } |
152 | 167 |
153 string16 GoogleURLTrackerInfoBarDelegate::GetButtonLabel( | 168 string16 GoogleURLTrackerInfoBarDelegate::GetButtonLabel( |
154 InfoBarButton button) const { | 169 InfoBarButton button) const { |
155 bool new_host = (button == BUTTON_OK); | 170 bool new_host = (button == BUTTON_OK); |
156 return l10n_util::GetStringFUTF16(new_host ? | 171 return l10n_util::GetStringFUTF16(new_host ? |
157 IDS_GOOGLE_URL_TRACKER_INFOBAR_SWITCH : | 172 IDS_GOOGLE_URL_TRACKER_INFOBAR_SWITCH : |
158 IDS_GOOGLE_URL_TRACKER_INFOBAR_DONT_SWITCH, | 173 IDS_GOOGLE_URL_TRACKER_INFOBAR_DONT_SWITCH, |
159 GetHost(new_host ? new_google_url_ : google_url_tracker_->google_url_)); | 174 GetHost(new_host ? new_google_url_ : google_url_tracker_->google_url_)); |
160 } | 175 } |
161 | 176 |
162 | 177 |
| 178 // GoogleURLTracker::MapEntry ------------------------------------------------- |
| 179 |
| 180 // Note that we have to initialize at least the NotificationSources explicitly |
| 181 // lest this not compile, because NotificationSource has no null constructor. |
| 182 GoogleURLTracker::MapEntry::MapEntry() |
| 183 : navigation_controller_source( |
| 184 content::Source<content::NavigationController>(NULL)), |
| 185 tab_contents_source(content::Source<TabContents>(NULL)) { |
| 186 NOTREACHED(); |
| 187 } |
| 188 |
| 189 GoogleURLTracker::MapEntry::MapEntry( |
| 190 GoogleURLTrackerInfoBarDelegate* infobar, |
| 191 const content::NotificationSource& navigation_controller_source, |
| 192 const content::NotificationSource& tab_contents_source) |
| 193 : infobar(infobar), |
| 194 navigation_controller_source(navigation_controller_source), |
| 195 tab_contents_source(tab_contents_source) { |
| 196 } |
| 197 |
| 198 GoogleURLTracker::MapEntry::~MapEntry() { |
| 199 } |
| 200 |
| 201 |
163 // GoogleURLTracker ----------------------------------------------------------- | 202 // GoogleURLTracker ----------------------------------------------------------- |
164 | 203 |
165 const char GoogleURLTracker::kDefaultGoogleHomepage[] = | 204 const char GoogleURLTracker::kDefaultGoogleHomepage[] = |
166 "http://www.google.com/"; | 205 "http://www.google.com/"; |
167 const char GoogleURLTracker::kSearchDomainCheckURL[] = | 206 const char GoogleURLTracker::kSearchDomainCheckURL[] = |
168 "https://www.google.com/searchdomaincheck?format=url&type=chrome"; | 207 "https://www.google.com/searchdomaincheck?format=url&type=chrome"; |
169 | 208 |
170 GoogleURLTracker::GoogleURLTracker(Profile* profile, Mode mode) | 209 GoogleURLTracker::GoogleURLTracker(Profile* profile, Mode mode) |
171 : profile_(profile), | 210 : profile_(profile), |
172 infobar_creator_(&CreateInfoBar), | 211 infobar_creator_(&CreateInfoBar), |
173 google_url_(mode == UNIT_TEST_MODE ? kDefaultGoogleHomepage : | 212 google_url_(mode == UNIT_TEST_MODE ? kDefaultGoogleHomepage : |
174 profile->GetPrefs()->GetString(prefs::kLastKnownGoogleURL)), | 213 profile->GetPrefs()->GetString(prefs::kLastKnownGoogleURL)), |
175 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), | 214 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), |
176 fetcher_id_(0), | 215 fetcher_id_(0), |
177 in_startup_sleep_(true), | 216 in_startup_sleep_(true), |
178 already_fetched_(false), | 217 already_fetched_(false), |
179 need_to_fetch_(false), | 218 need_to_fetch_(false), |
180 need_to_prompt_(false) { | 219 need_to_prompt_(false), |
| 220 search_committed_(false) { |
181 net::NetworkChangeNotifier::AddIPAddressObserver(this); | 221 net::NetworkChangeNotifier::AddIPAddressObserver(this); |
182 | 222 |
183 // Because this function can be called during startup, when kicking off a URL | 223 // Because this function can be called during startup, when kicking off a URL |
184 // fetch can eat up 20 ms of time, we delay five seconds, which is hopefully | 224 // fetch can eat up 20 ms of time, we delay five seconds, which is hopefully |
185 // long enough to be after startup, but still get results back quickly. | 225 // long enough to be after startup, but still get results back quickly. |
186 // Ideally, instead of this timer, we'd do something like "check if the | 226 // Ideally, instead of this timer, we'd do something like "check if the |
187 // browser is starting up, and if so, come back later", but there is currently | 227 // browser is starting up, and if so, come back later", but there is currently |
188 // no function to do this. | 228 // no function to do this. |
189 // | 229 // |
190 // In UNIT_TEST mode, where we want to explicitly control when the tracker | 230 // In UNIT_TEST mode, where we want to explicitly control when the tracker |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 // existing infobars open and quietly point their "new Google URL"s at the | 332 // existing infobars open and quietly point their "new Google URL"s at the |
293 // new URL (for e.g. scheme changes). Otherwise we go ahead and close the | 333 // new URL (for e.g. scheme changes). Otherwise we go ahead and close the |
294 // existing infobars since their message is out-of-date. | 334 // existing infobars since their message is out-of-date. |
295 if (!url.is_valid()) // Note: |url| is the previous |fetched_google_url_|. | 335 if (!url.is_valid()) // Note: |url| is the previous |fetched_google_url_|. |
296 return; | 336 return; |
297 if (fetched_host != GetHost(url)) { | 337 if (fetched_host != GetHost(url)) { |
298 CloseAllInfoBars(false); | 338 CloseAllInfoBars(false); |
299 } else if (fetched_google_url_ != url) { | 339 } else if (fetched_google_url_ != url) { |
300 for (InfoBarMap::iterator i(infobar_map_.begin()); | 340 for (InfoBarMap::iterator i(infobar_map_.begin()); |
301 i != infobar_map_.end(); ++i) | 341 i != infobar_map_.end(); ++i) |
302 i->second->SetGoogleURL(fetched_google_url_); | 342 i->second.infobar->SetGoogleURL(fetched_google_url_); |
303 } | 343 } |
304 } | 344 } |
305 } | 345 } |
306 | 346 |
307 void GoogleURLTracker::Observe(int type, | 347 void GoogleURLTracker::Observe(int type, |
308 const content::NotificationSource& source, | 348 const content::NotificationSource& source, |
309 const content::NotificationDetails& details) { | 349 const content::NotificationDetails& details) { |
310 switch (type) { | 350 switch (type) { |
311 case content::NOTIFICATION_NAV_ENTRY_PENDING: { | 351 case content::NOTIFICATION_NAV_ENTRY_PENDING: { |
312 content::NavigationController* controller = | 352 content::NavigationController* controller = |
313 content::Source<content::NavigationController>(source).ptr(); | 353 content::Source<content::NavigationController>(source).ptr(); |
314 TabContents* tab_contents = | 354 TabContents* tab_contents = |
315 TabContents::FromWebContents(controller->GetWebContents()); | 355 TabContents::FromWebContents(controller->GetWebContents()); |
316 OnNavigationPending(source, | 356 OnNavigationPending(source, content::Source<TabContents>(tab_contents), |
317 content::Source<TabContents>(tab_contents), | |
318 tab_contents->infobar_tab_helper(), | 357 tab_contents->infobar_tab_helper(), |
319 controller->GetPendingEntry()->GetURL()); | 358 controller->GetPendingEntry()->GetUniqueID()); |
320 break; | 359 break; |
321 } | 360 } |
322 | 361 |
323 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: { | 362 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: { |
324 TabContents* tab_contents = TabContents::FromWebContents( | 363 content::NavigationController* controller = |
325 content::Source<content::NavigationController>(source)-> | 364 content::Source<content::NavigationController>(source).ptr(); |
326 GetWebContents()); | 365 OnNavigationCommittedOrTabClosed( |
327 OnNavigationCommittedOrTabClosed(source, | 366 TabContents::FromWebContents(controller->GetWebContents())-> |
328 content::Source<TabContents>(tab_contents), | 367 infobar_tab_helper(), |
329 tab_contents->infobar_tab_helper(), true); | 368 controller->GetActiveEntry()->GetURL()); |
330 break; | 369 break; |
331 } | 370 } |
332 | 371 |
333 case chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED: { | 372 case chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED: { |
334 TabContents* tab_contents = content::Source<TabContents>(source).ptr(); | |
335 OnNavigationCommittedOrTabClosed( | 373 OnNavigationCommittedOrTabClosed( |
336 content::Source<content::NavigationController>( | 374 content::Source<TabContents>(source)->infobar_tab_helper(), GURL()); |
337 &tab_contents->web_contents()->GetController()), source, | |
338 tab_contents->infobar_tab_helper(), false); | |
339 break; | 375 break; |
340 } | 376 } |
341 | 377 |
342 case chrome::NOTIFICATION_INSTANT_COMMITTED: { | 378 case chrome::NOTIFICATION_INSTANT_COMMITTED: { |
343 TabContents* tab_contents = content::Source<TabContents>(source).ptr(); | 379 TabContents* tab_contents = content::Source<TabContents>(source).ptr(); |
344 content::WebContents* web_contents = tab_contents->web_contents(); | 380 content::WebContents* web_contents = tab_contents->web_contents(); |
345 content::Source<content::NavigationController> source( | 381 content::Source<content::NavigationController> source( |
346 &web_contents->GetController()); | 382 &web_contents->GetController()); |
347 content::Source<TabContents> tab_contents_source(tab_contents); | |
348 InfoBarTabHelper* infobar_helper = tab_contents->infobar_tab_helper(); | 383 InfoBarTabHelper* infobar_helper = tab_contents->infobar_tab_helper(); |
349 OnNavigationPending(source, tab_contents_source, infobar_helper, | 384 OnNavigationPending(source, content::Source<TabContents>(tab_contents), |
350 web_contents->GetURL()); | 385 infobar_helper, 0); |
351 OnNavigationCommittedOrTabClosed(source, tab_contents_source, | 386 OnNavigationCommittedOrTabClosed(infobar_helper, web_contents->GetURL()); |
352 infobar_helper, true); | |
353 break; | 387 break; |
354 } | 388 } |
355 | 389 |
356 default: | 390 default: |
357 NOTREACHED() << "Unknown notification received:" << type; | 391 NOTREACHED() << "Unknown notification received:" << type; |
358 } | 392 } |
359 } | 393 } |
360 | 394 |
361 void GoogleURLTracker::OnIPAddressChanged() { | 395 void GoogleURLTracker::OnIPAddressChanged() { |
362 already_fetched_ = false; | 396 already_fetched_ = false; |
(...skipping 23 matching lines...) Expand all Loading... |
386 } | 420 } |
387 | 421 |
388 void GoogleURLTracker::CancelGoogleURL(const GURL& new_google_url) { | 422 void GoogleURLTracker::CancelGoogleURL(const GURL& new_google_url) { |
389 profile_->GetPrefs()->SetString(prefs::kLastPromptedGoogleURL, | 423 profile_->GetPrefs()->SetString(prefs::kLastPromptedGoogleURL, |
390 new_google_url.spec()); | 424 new_google_url.spec()); |
391 need_to_prompt_ = false; | 425 need_to_prompt_ = false; |
392 CloseAllInfoBars(false); | 426 CloseAllInfoBars(false); |
393 } | 427 } |
394 | 428 |
395 void GoogleURLTracker::InfoBarClosed(const InfoBarTabHelper* infobar_helper) { | 429 void GoogleURLTracker::InfoBarClosed(const InfoBarTabHelper* infobar_helper) { |
| 430 DCHECK(!search_committed_); |
396 InfoBarMap::iterator i(infobar_map_.find(infobar_helper)); | 431 InfoBarMap::iterator i(infobar_map_.find(infobar_helper)); |
397 DCHECK(i != infobar_map_.end()); | 432 DCHECK(i != infobar_map_.end()); |
| 433 const MapEntry& map_entry = i->second; |
| 434 |
| 435 UnregisterForEntrySpecificNotifications(map_entry, false); |
398 infobar_map_.erase(i); | 436 infobar_map_.erase(i); |
| 437 |
| 438 // Our global listeners for these other notifications should be in place iff |
| 439 // we have any non-showing infobars. |
| 440 for (InfoBarMap::const_iterator i(infobar_map_.begin()); |
| 441 i != infobar_map_.end(); ++i) { |
| 442 if (!i->second.infobar->showing()) { |
| 443 DCHECK(registrar_.IsRegistered(this, |
| 444 content::NOTIFICATION_NAV_ENTRY_PENDING, |
| 445 content::NotificationService::AllBrowserContextsAndSources())); |
| 446 return; |
| 447 } |
| 448 } |
| 449 if (registrar_.IsRegistered(this, content::NOTIFICATION_NAV_ENTRY_PENDING, |
| 450 content::NotificationService::AllBrowserContextsAndSources())) { |
| 451 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_PENDING, |
| 452 content::NotificationService::AllBrowserContextsAndSources()); |
| 453 registrar_.Remove(this, chrome::NOTIFICATION_INSTANT_COMMITTED, |
| 454 content::NotificationService::AllBrowserContextsAndSources()); |
| 455 } |
399 } | 456 } |
400 | 457 |
401 void GoogleURLTracker::SetNeedToFetch() { | 458 void GoogleURLTracker::SetNeedToFetch() { |
402 need_to_fetch_ = true; | 459 need_to_fetch_ = true; |
403 StartFetchIfDesirable(); | 460 StartFetchIfDesirable(); |
404 } | 461 } |
405 | 462 |
406 void GoogleURLTracker::FinishSleep() { | 463 void GoogleURLTracker::FinishSleep() { |
407 in_startup_sleep_ = false; | 464 in_startup_sleep_ = false; |
408 StartFetchIfDesirable(); | 465 StartFetchIfDesirable(); |
(...skipping 30 matching lines...) Expand all Loading... |
439 | 496 |
440 // Configure to max_retries at most kMaxRetries times for 5xx errors. | 497 // Configure to max_retries at most kMaxRetries times for 5xx errors. |
441 static const int kMaxRetries = 5; | 498 static const int kMaxRetries = 5; |
442 fetcher_->SetMaxRetries(kMaxRetries); | 499 fetcher_->SetMaxRetries(kMaxRetries); |
443 | 500 |
444 fetcher_->Start(); | 501 fetcher_->Start(); |
445 } | 502 } |
446 | 503 |
447 void GoogleURLTracker::SearchCommitted() { | 504 void GoogleURLTracker::SearchCommitted() { |
448 if (need_to_prompt_) { | 505 if (need_to_prompt_) { |
449 // This notification will fire a bit later in the same call chain we're | 506 search_committed_ = true; |
| 507 // These notifications will fire a bit later in the same call chain we're |
450 // currently in. | 508 // currently in. |
451 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING, | 509 if (!registrar_.IsRegistered(this, content::NOTIFICATION_NAV_ENTRY_PENDING, |
452 content::NotificationService::AllBrowserContextsAndSources()); | 510 content::NotificationService::AllBrowserContextsAndSources())) { |
453 registrar_.Add(this, chrome::NOTIFICATION_INSTANT_COMMITTED, | 511 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING, |
454 content::NotificationService::AllBrowserContextsAndSources()); | 512 content::NotificationService::AllBrowserContextsAndSources()); |
| 513 registrar_.Add(this, chrome::NOTIFICATION_INSTANT_COMMITTED, |
| 514 content::NotificationService::AllBrowserContextsAndSources()); |
| 515 } |
455 } | 516 } |
456 } | 517 } |
457 | 518 |
458 void GoogleURLTracker::OnNavigationPending( | 519 void GoogleURLTracker::OnNavigationPending( |
459 const content::NotificationSource& navigation_controller_source, | 520 const content::NotificationSource& navigation_controller_source, |
460 const content::NotificationSource& tab_contents_source, | 521 const content::NotificationSource& tab_contents_source, |
461 InfoBarTabHelper* infobar_helper, | 522 InfoBarTabHelper* infobar_helper, |
462 const GURL& search_url) { | 523 int pending_id) { |
463 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_PENDING, | 524 InfoBarMap::iterator i(infobar_map_.find(infobar_helper)); |
464 content::NotificationService::AllBrowserContextsAndSources()); | |
465 registrar_.Remove(this, chrome::NOTIFICATION_INSTANT_COMMITTED, | |
466 content::NotificationService::AllBrowserContextsAndSources()); | |
467 | 525 |
468 if (registrar_.IsRegistered(this, | 526 if (search_committed_) { |
469 chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED, tab_contents_source)) { | 527 search_committed_ = false; |
470 // If the previous load hasn't committed and the user triggers a new load, | 528 // Whether there's an existing infobar or not, we need to listen for the |
471 // we don't need to re-register our listeners; just kill the old, | 529 // load to commit, so we can show and/or update the infobar when it does. |
472 // never-shown infobar (to be replaced by a new one below). | 530 // (We may already be registered for this if there is an existing infobar |
473 InfoBarMap::iterator i(infobar_map_.find(infobar_helper)); | 531 // that had a previous pending search that hasn't yet committed.) |
474 DCHECK(i != infobar_map_.end()); | 532 if (!registrar_.IsRegistered(this, |
475 i->second->Close(false); | 533 content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
| 534 navigation_controller_source)) { |
| 535 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
| 536 navigation_controller_source); |
| 537 } |
| 538 if (i == infobar_map_.end()) { |
| 539 // This is a search on a tab that doesn't have one of our infobars, so add |
| 540 // one. Note that we only listen for the tab's destruction on this path; |
| 541 // if there was already an infobar, then either it's not yet showing and |
| 542 // we're already registered for this, or it is showing and its owner will |
| 543 // handle tearing it down when the tab is destroyed. |
| 544 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED, |
| 545 tab_contents_source); |
| 546 infobar_map_.insert(std::make_pair(infobar_helper, MapEntry( |
| 547 (*infobar_creator_)(infobar_helper, this, fetched_google_url_), |
| 548 navigation_controller_source, tab_contents_source))); |
| 549 } else { |
| 550 // This is a new search on a tab where we already have an infobar (which |
| 551 // may or may not be showing). |
| 552 i->second.infobar->set_pending_id(pending_id); |
| 553 } |
| 554 } else if (i != infobar_map_.end()){ |
| 555 if (i->second.infobar->showing()) { |
| 556 // This is a non-search navigation on a tab with a visible infobar. If |
| 557 // there was a previous pending search on this tab, this means it won't |
| 558 // commit, so undo anything we did in response to seeing that. Note that |
| 559 // if there was no pending search on this tab, these statements are |
| 560 // effectively a no-op. |
| 561 // |
| 562 // If this navigation actually commits, that will trigger the infobar's |
| 563 // owner to expire the infobar if need be. If it doesn't commit, then |
| 564 // simply leaving the infobar as-is will have been the right thing. |
| 565 UnregisterForEntrySpecificNotifications(i->second, false); |
| 566 i->second.infobar->set_pending_id(0); |
| 567 } else { |
| 568 // Non-search navigation on a tab with a not-yet-shown infobar. This |
| 569 // means the original search won't commit, so close the infobar. |
| 570 i->second.infobar->Close(false); |
| 571 } |
476 } else { | 572 } else { |
477 // Start listening for the commit notification. We also need to listen for | 573 // Non-search navigation on a tab without one of our infobars. This is |
478 // the tab close command since that means the load will never commit. Note | 574 // irrelevant to us. |
479 // that in this case we don't need to close any previous infobar for this | |
480 // tab since this navigation will close it. | |
481 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
482 navigation_controller_source); | |
483 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED, | |
484 tab_contents_source); | |
485 } | 575 } |
486 | |
487 infobar_map_[infobar_helper] = (*infobar_creator_)(infobar_helper, search_url, | |
488 this, fetched_google_url_); | |
489 } | 576 } |
490 | 577 |
491 void GoogleURLTracker::OnNavigationCommittedOrTabClosed( | 578 void GoogleURLTracker::OnNavigationCommittedOrTabClosed( |
492 const content::NotificationSource& navigation_controller_source, | |
493 const content::NotificationSource& tab_contents_source, | |
494 const InfoBarTabHelper* infobar_helper, | 579 const InfoBarTabHelper* infobar_helper, |
495 bool navigated) { | 580 const GURL& search_url) { |
496 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
497 navigation_controller_source); | |
498 registrar_.Remove(this, chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED, | |
499 tab_contents_source); | |
500 | |
501 InfoBarMap::iterator i(infobar_map_.find(infobar_helper)); | 581 InfoBarMap::iterator i(infobar_map_.find(infobar_helper)); |
502 DCHECK(i != infobar_map_.end()); | 582 DCHECK(i != infobar_map_.end()); |
503 DCHECK(need_to_prompt_); | 583 const MapEntry& map_entry = i->second; |
504 if (navigated) | 584 |
505 i->second->Show(); | 585 if (!search_url.is_valid()) { |
506 else | 586 // Tab closed, or we somehow tried to navigate to an invalid URL (?!). |
507 i->second->Close(false); // Close manually since it's not added to a tab. | 587 // InfoBarClosed() will take care of unregistering the notifications for |
| 588 // this tab. |
| 589 map_entry.infobar->Close(false); |
| 590 return; |
| 591 } |
| 592 |
| 593 // We're getting called because of a commit notification, so pass true for |
| 594 // |must_be_listening_for_commit|. |
| 595 UnregisterForEntrySpecificNotifications(map_entry, true); |
| 596 map_entry.infobar->Show(search_url); |
508 } | 597 } |
509 | 598 |
510 void GoogleURLTracker::CloseAllInfoBars(bool redo_searches) { | 599 void GoogleURLTracker::CloseAllInfoBars(bool redo_searches) { |
511 // Close all infobars, whether they've been added to tabs or not. | 600 // Close all infobars, whether they've been added to tabs or not. |
512 while (!infobar_map_.empty()) | 601 while (!infobar_map_.empty()) |
513 infobar_map_.begin()->second->Close(redo_searches); | 602 infobar_map_.begin()->second.infobar->Close(redo_searches); |
| 603 } |
514 | 604 |
515 // Any registered listeners for NAV_ENTRY_COMMITTED and TAB_CLOSED are now | 605 void GoogleURLTracker::UnregisterForEntrySpecificNotifications( |
516 // irrelevant as the associated infobars are gone. | 606 const MapEntry& map_entry, |
517 registrar_.RemoveAll(); | 607 bool must_be_listening_for_commit) { |
| 608 // For tabs with non-showing infobars, we should always be listening for both |
| 609 // these notifications. For tabs with showing infobars, we may be listening |
| 610 // for NOTIFICATION_NAV_ENTRY_COMMITTED if the user has performed a new search |
| 611 // on this tab. |
| 612 if (registrar_.IsRegistered(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
| 613 map_entry.navigation_controller_source)) { |
| 614 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
| 615 map_entry.navigation_controller_source); |
| 616 } else { |
| 617 DCHECK(!must_be_listening_for_commit); |
| 618 DCHECK(map_entry.infobar->showing()); |
| 619 } |
| 620 const bool registered_for_tab_contents_destroyed = |
| 621 registrar_.IsRegistered(this, chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED, |
| 622 map_entry.tab_contents_source); |
| 623 DCHECK_NE(registered_for_tab_contents_destroyed, |
| 624 map_entry.infobar->showing()); |
| 625 if (registered_for_tab_contents_destroyed) { |
| 626 registrar_.Remove(this, chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED, |
| 627 map_entry.tab_contents_source); |
| 628 } |
518 } | 629 } |
OLD | NEW |