Chromium Code Reviews| Index: chrome/browser/google/google_url_tracker.cc |
| =================================================================== |
| --- chrome/browser/google/google_url_tracker.cc (revision 132905) |
| +++ chrome/browser/google/google_url_tracker.cc (working copy) |
| @@ -32,20 +32,15 @@ |
| #include "net/url_request/url_request_status.h" |
| #include "ui/base/l10n/l10n_util.h" |
| -using content::NavigationController; |
| -using content::OpenURLParams; |
| -using content::Referrer; |
| -using content::WebContents; |
| - |
| namespace { |
| -InfoBarDelegate* CreateInfoBar(InfoBarTabHelper* infobar_helper, |
| - GoogleURLTracker* google_url_tracker, |
| - const GURL& new_google_url) { |
| - InfoBarDelegate* infobar = new GoogleURLTrackerInfoBarDelegate(infobar_helper, |
| +GoogleURLTrackerInfoBarDelegate* CreateInfoBar( |
| + InfoBarTabHelper* infobar_helper, |
| + const GURL& search_url, |
| + GoogleURLTracker* google_url_tracker, |
| + const GURL& new_google_url) { |
| + return new GoogleURLTrackerInfoBarDelegate(infobar_helper, search_url, |
| google_url_tracker, new_google_url); |
| - infobar_helper->AddInfoBar(infobar); |
| - return infobar; |
| } |
| } // namespace |
| @@ -54,22 +49,25 @@ |
| GoogleURLTrackerInfoBarDelegate::GoogleURLTrackerInfoBarDelegate( |
| InfoBarTabHelper* infobar_helper, |
| + const GURL& search_url, |
| GoogleURLTracker* google_url_tracker, |
| const GURL& new_google_url) |
| : ConfirmInfoBarDelegate(infobar_helper), |
| + map_key_(infobar_helper), |
| + search_url_(search_url), |
| google_url_tracker_(google_url_tracker), |
| - new_google_url_(new_google_url) { |
| + new_google_url_(new_google_url), |
| + showing_(false) { |
| } |
| bool GoogleURLTrackerInfoBarDelegate::Accept() { |
| google_url_tracker_->AcceptGoogleURL(new_google_url_); |
| - google_url_tracker_->RedoSearch(); |
| - return true; |
| + return false; |
| } |
| bool GoogleURLTrackerInfoBarDelegate::Cancel() { |
| google_url_tracker_->CancelGoogleURL(new_google_url_); |
| - return true; |
| + return false; |
| } |
| string16 GoogleURLTrackerInfoBarDelegate::GetLinkText() const { |
| @@ -78,18 +76,62 @@ |
| bool GoogleURLTrackerInfoBarDelegate::LinkClicked( |
| WindowOpenDisposition disposition) { |
| - OpenURLParams params( |
| - google_util::AppendGoogleLocaleParam(GURL( |
| - "https://www.google.com/support/chrome/bin/answer.py?answer=1618699")), |
| - Referrer(), |
| + content::OpenURLParams params(google_util::AppendGoogleLocaleParam(GURL( |
| + "https://www.google.com/support/chrome/bin/answer.py?answer=1618699")), |
| + content::Referrer(), |
| (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition, |
| content::PAGE_TRANSITION_LINK, false); |
| owner()->web_contents()->OpenURL(params); |
| return false; |
| } |
| +void GoogleURLTrackerInfoBarDelegate::Show() { |
| + owner()->AddInfoBar(this); |
| + showing_ = true; |
| +} |
| + |
| +void GoogleURLTrackerInfoBarDelegate::Close(bool redo_search) { |
| + if (!showing_) { |
| + // We haven't been added to a tab, so just delete ourselves. |
| + delete this; |
| + return; |
| + } |
| + |
| + // Synchronously remove ourselves from the URL tracker's list, because the |
| + // RemoveInfoBar() call below may result in either a synchronous or an |
| + // asynchronous call back to InfoBarClosed(), and it's easier to handle when |
| + // we just guarantee the removal is synchronous. |
| + google_url_tracker_->InfoBarClosed(map_key_); |
| + google_url_tracker_ = NULL; |
| + |
| + // If we were showing in a background tab that was then closed, we could have |
| + // been leaked, and subsequently reached here due to |
| + // GoogleURLTracker::CloseAllInfoBars(). In this case our owner is now NULL |
| + // so we should just do nothing. |
| + // TODO(pkasting): This can go away once the InfoBar ownership model is fixed |
| + // so that infobars in background tabs don't leak on tab closure. |
|
Ilya Sherman
2012/04/24 00:30:47
nit: Is there a bug tracking this that we could li
|
| + if (!owner()) |
| + return; |
| + |
| + if (redo_search) { |
| + // Re-do the user's search on the new domain. |
| + url_canon::Replacements<char> replacements; |
| + const std::string& host(new_google_url_.host()); |
| + replacements.SetHost(host.data(), url_parse::Component(0, host.length())); |
| + GURL new_search_url(search_url_.ReplaceComponents(replacements)); |
| + if (new_search_url.is_valid()) { |
| + content::OpenURLParams params(new_search_url, content::Referrer(), |
| + CURRENT_TAB, content::PAGE_TRANSITION_GENERATED, false); |
| + owner()->web_contents()->OpenURL(params); |
| + } |
| + } |
| + |
| + owner()->RemoveInfoBar(this); |
| +} |
| + |
| GoogleURLTrackerInfoBarDelegate::~GoogleURLTrackerInfoBarDelegate() { |
| - google_url_tracker_->InfoBarClosed(); |
| + if (google_url_tracker_) |
|
Ilya Sherman
2012/04/24 00:30:47
nit: Should this also check the state of |showing_
Peter Kasting
2012/04/24 01:53:01
No. The infobar is present in the tracker's map r
|
| + google_url_tracker_->InfoBarClosed(map_key_); |
| } |
| string16 GoogleURLTrackerInfoBarDelegate::GetMessageText() const { |
| @@ -128,9 +170,7 @@ |
| in_startup_sleep_(true), |
| already_fetched_(false), |
| need_to_fetch_(false), |
| - need_to_prompt_(false), |
| - controller_(NULL), |
| - infobar_(NULL) { |
| + need_to_prompt_(false) { |
| net::NetworkChangeNotifier::AddIPAddressObserver(this); |
| // Because this function can be called during startup, when kicking off a URL |
| @@ -153,18 +193,20 @@ |
| GoogleURLTracker::~GoogleURLTracker() { |
| net::NetworkChangeNotifier::RemoveIPAddressObserver(this); |
| + // We should only reach here after any tabs and their infobars have been torn |
| + // down. |
| + DCHECK(infobars_.empty()); |
| } |
| // static |
| GURL GoogleURLTracker::GoogleURL() { |
| - const GoogleURLTracker* const tracker = |
| - g_browser_process->google_url_tracker(); |
| + const GoogleURLTracker* tracker = g_browser_process->google_url_tracker(); |
| return tracker ? tracker->google_url_ : GURL(kDefaultGoogleHomepage); |
| } |
| // static |
| void GoogleURLTracker::RequestServerCheck() { |
| - GoogleURLTracker* const tracker = g_browser_process->google_url_tracker(); |
| + GoogleURLTracker* tracker = g_browser_process->google_url_tracker(); |
| if (tracker) |
| tracker->SetNeedToFetch(); |
| } |
| @@ -193,35 +235,22 @@ |
| content::NotificationService::AllSources(), |
| content::NotificationService::NoDetails()); |
| need_to_prompt_ = false; |
| + CloseAllInfoBars(true); |
| } |
| void GoogleURLTracker::CancelGoogleURL(const GURL& new_google_url) { |
| g_browser_process->local_state()->SetString(prefs::kLastPromptedGoogleURL, |
| new_google_url.spec()); |
| need_to_prompt_ = false; |
| + CloseAllInfoBars(false); |
| } |
| -void GoogleURLTracker::InfoBarClosed() { |
| - registrar_.RemoveAll(); |
| - controller_ = NULL; |
| - infobar_ = NULL; |
| - search_url_ = GURL(); |
| +void GoogleURLTracker::InfoBarClosed(const InfoBarTabHelper* infobar_helper) { |
| + InfoBars::iterator i(infobars_.find(infobar_helper)); |
|
Ilya Sherman
2012/04/24 00:30:47
nit: Unless you're particularly attached to "i" he
|
| + DCHECK(i != infobars_.end()); |
| + infobars_.erase(i); |
| } |
| -void GoogleURLTracker::RedoSearch() { |
| - // Re-do the user's search on the new domain. |
| - DCHECK(controller_); |
| - url_canon::Replacements<char> replacements; |
| - replacements.SetHost(google_url_.host().data(), |
| - url_parse::Component(0, google_url_.host().length())); |
| - GURL new_search_url(search_url_.ReplaceComponents(replacements)); |
| - if (new_search_url.is_valid()) { |
| - OpenURLParams params(new_search_url, Referrer(), CURRENT_TAB, |
| - content::PAGE_TRANSITION_GENERATED, false); |
| - controller_->GetWebContents()->OpenURL(params); |
| - } |
| -} |
| - |
| void GoogleURLTracker::SetNeedToFetch() { |
| need_to_fetch_ = true; |
| StartFetchIfDesirable(); |
| @@ -291,7 +320,6 @@ |
| GURL last_prompted_url( |
| g_browser_process->local_state()->GetString( |
| prefs::kLastPromptedGoogleURL)); |
| - need_to_prompt_ = false; |
| if (last_prompted_url.is_empty()) { |
| // On the very first run of Chrome, when we've never looked up the URL at |
| @@ -313,6 +341,10 @@ |
| } |
| need_to_prompt_ = true; |
| + |
| + // Any open infobars are pointing at the wrong Google URL. (This can happen |
| + // if an infobar has been sitting open and then our IP address changes.) |
| + CloseAllInfoBars(false); |
| } |
| void GoogleURLTracker::Observe(int type, |
| @@ -320,22 +352,37 @@ |
| const content::NotificationDetails& details) { |
| switch (type) { |
| case content::NOTIFICATION_NAV_ENTRY_PENDING: { |
| - NavigationController* controller = |
| - content::Source<NavigationController>(source).ptr(); |
| - OnNavigationPending(source, controller->GetPendingEntry()->GetURL()); |
| + content::NavigationController* controller = |
| + content::Source<content::NavigationController>(source).ptr(); |
| + content::WebContents* contents = controller->GetWebContents(); |
| + OnNavigationPending(source, |
| + content::Source<content::WebContents>(contents), |
| + TabContentsWrapper::GetCurrentWrapperForContents(contents)-> |
| + infobar_tab_helper(), controller->GetPendingEntry()->GetURL()); |
|
Ilya Sherman
2012/04/24 00:30:47
nit: Maybe move the last arg to a new line, since
|
| break; |
| } |
| - case content::NOTIFICATION_NAV_ENTRY_COMMITTED: |
| - OnNavigationCommittedOrTabClosed( |
| - content::Source<NavigationController>(source).ptr()-> |
| - GetWebContents(), type); |
| + case content::NOTIFICATION_NAV_ENTRY_COMMITTED: { |
| + content::WebContents* contents = |
| + content::Source<content::NavigationController>(source)-> |
| + GetWebContents(); |
| + OnNavigationCommittedOrTabClosed(source, |
| + content::Source<content::WebContents>(contents), |
| + TabContentsWrapper::GetCurrentWrapperForContents(contents)-> |
| + infobar_tab_helper(), type); |
| break; |
| + } |
| - case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: |
| + case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { |
| + content::WebContents* contents = |
| + content::Source<content::WebContents>(source).ptr(); |
| OnNavigationCommittedOrTabClosed( |
| - content::Source<content::WebContents>(source).ptr(), type); |
| + content::Source<content::NavigationController>(&contents-> |
| + GetController()), source, |
| + TabContentsWrapper::GetCurrentWrapperForContents(contents)-> |
| + infobar_tab_helper(), type); |
| break; |
| + } |
| default: |
| NOTREACHED() << "Unknown notification received:" << type; |
| @@ -348,7 +395,7 @@ |
| } |
| void GoogleURLTracker::SearchCommitted() { |
| - if (registrar_.IsEmpty() && (need_to_prompt_ || fetcher_.get())) { |
| + if (need_to_prompt_) { |
| // This notification will fire a bit later in the same call chain we're |
| // currently in. |
| registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING, |
| @@ -358,46 +405,58 @@ |
| void GoogleURLTracker::OnNavigationPending( |
| const content::NotificationSource& source, |
| - const GURL& pending_url) { |
| - controller_ = content::Source<NavigationController>(source).ptr(); |
| - search_url_ = pending_url; |
| + const content::NotificationSource& contents_source, |
| + InfoBarTabHelper* infobar_helper, |
| + const GURL& search_url) { |
| registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_PENDING, |
| content::NotificationService::AllBrowserContextsAndSources()); |
| - // Start listening for the commit notification. We also need to listen for the |
| - // tab close command since that means the load will never commit. |
| - registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
| - content::Source<NavigationController>(controller_)); |
| - registrar_.Add( |
| - this, |
| - content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
| - content::Source<content::WebContents>(controller_->GetWebContents())); |
| + |
| + if (registrar_.IsRegistered(this, |
| + content::NOTIFICATION_WEB_CONTENTS_DESTROYED, contents_source)) { |
| + // If the previous load hasn't committed and the user triggers a new load, |
| + // we don't need to re-register our listeners; just kill the old, |
| + // never-shown infobar (to be replaced by a new one below). |
| + InfoBars::iterator i(infobars_.find(infobar_helper)); |
| + DCHECK(i != infobars_.end()); |
| + i->second->Close(false); |
| + } else { |
| + // Start listening for the commit notification. We also need to listen for |
| + // the tab close command since that means the load will never commit. Note |
| + // that in this case we don't need to close any previous infobar for this |
| + // tab since this navigation will close it. |
| + registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, source); |
| + registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
| + contents_source); |
| + } |
| + |
| + infobars_[infobar_helper] = (*infobar_creator_)(infobar_helper, search_url, |
| + this, fetched_google_url_); |
| } |
| void GoogleURLTracker::OnNavigationCommittedOrTabClosed( |
| - WebContents* web_contents, |
| + const content::NotificationSource& source, |
| + const content::NotificationSource& contents_source, |
| + InfoBarTabHelper* infobar_helper, |
| int type) { |
| - registrar_.RemoveAll(); |
| + registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, source); |
| + registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
| + contents_source); |
| - if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) { |
| - ShowGoogleURLInfoBarIfNecessary(web_contents); |
| - } else { |
| - controller_ = NULL; |
| - infobar_ = NULL; |
| - } |
| + InfoBars::iterator i(infobars_.find(infobar_helper)); |
| + DCHECK(i != infobars_.end()); |
| + DCHECK(need_to_prompt_); |
| + if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) |
| + i->second->Show(); |
| + else |
| + i->second->Close(false); // Close manually since it's not added to a tab. |
| } |
| -void GoogleURLTracker::ShowGoogleURLInfoBarIfNecessary( |
| - WebContents* web_contents) { |
| - if (!need_to_prompt_) |
| - return; |
| - DCHECK(!fetched_google_url_.is_empty()); |
| +void GoogleURLTracker::CloseAllInfoBars(bool redo_searches) { |
| + // Close all infobars, whether they've been added to tabs or not. |
| + while (!infobars_.empty()) |
| + infobars_.begin()->second->Close(redo_searches); |
| - // |tab_contents| can be NULL during tests. |
| - InfoBarTabHelper* infobar_helper = NULL; |
| - if (web_contents) { |
| - TabContentsWrapper* wrapper = |
| - TabContentsWrapper::GetCurrentWrapperForContents(web_contents); |
| - infobar_helper = wrapper->infobar_tab_helper(); |
| - } |
| - infobar_ = (*infobar_creator_)(infobar_helper, this, fetched_google_url_); |
| + // Any registered listeners for NAV_ENTRY_COMMITTED and TAB_CLOSED are now |
| + // irrelevant as the associated infobars are gone. |
|
Ilya Sherman
2012/04/24 00:30:47
nit: You don't mention NAV_ENTRY_PENDING in this c
Peter Kasting
2012/04/24 01:53:01
The reason for that is that it's (supposed to be)
|
| + registrar_.RemoveAll(); |
| } |