Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2013 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_frame/turndown_prompt/turndown_prompt.h" | |
| 6 | |
| 7 #include <atlbase.h> | |
| 8 #include <shlguid.h> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/compiler_specific.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/memory/scoped_ptr.h" | |
| 14 #include "base/path_service.h" | |
| 15 #include "base/win/scoped_bstr.h" | |
| 16 #include "base/win/scoped_comptr.h" | |
| 17 #include "base/win/win_util.h" | |
| 18 #include "chrome/installer/util/browser_distribution.h" | |
| 19 #include "chrome/installer/util/google_update_settings.h" | |
| 20 #include "chrome/installer/util/install_util.h" | |
| 21 #include "chrome_frame/infobars/infobar_manager.h" | |
| 22 #include "chrome_frame/policy_settings.h" | |
| 23 #include "chrome_frame/ready_mode/internal/ready_mode_web_browser_adapter.h" | |
| 24 #include "chrome_frame/ready_mode/internal/url_launcher.h" | |
| 25 #include "chrome_frame/turndown_prompt/reshow_state.h" | |
| 26 #include "chrome_frame/turndown_prompt/turndown_prompt_content.h" | |
| 27 #include "chrome_frame/utils.h" | |
| 28 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | |
| 29 | |
| 30 namespace { | |
| 31 | |
| 32 // Time between showingings of the turndown prompt. | |
|
robertshield
2013/06/19 23:36:33
Too many ings
grt (UTC plus 2)
2013/06/20 19:55:29
Done.
| |
| 33 const int kTurndownPromptReshowDeltaMinutes = 60 * 24 * 7; | |
| 34 | |
| 35 void UninstallChromeFrame(); | |
| 36 | |
| 37 // Manages the Turndown UI in response to browsing ChromeFrame-rendered | |
| 38 // pages. | |
| 39 class BrowserObserver : public ReadyModeWebBrowserAdapter::Observer { | |
| 40 public: | |
| 41 BrowserObserver(IWebBrowser2* web_browser, | |
| 42 ReadyModeWebBrowserAdapter* adapter); | |
| 43 | |
| 44 // ReadyModeWebBrowserAdapter::Observer implementation | |
| 45 virtual void OnNavigateTo(const std::wstring& url); | |
| 46 virtual void OnRenderInChromeFrame(const std::wstring& url); | |
| 47 virtual void OnRenderInHost(const std::wstring& url); | |
| 48 | |
| 49 private: | |
| 50 // Shows the turndown prompt if it hasn't been seen since the reshow delta. | |
|
robertshield
2013/06/19 23:36:33
reshow delta -> kTurndownPromptReshowDeltaMinutes
grt (UTC plus 2)
2013/06/20 19:55:29
Done.
| |
| 51 void ShowPrompt(); | |
| 52 void Hide(); | |
| 53 InfobarManager* GetInfobarManager(); | |
|
robertshield
2013/06/19 23:36:33
The pointer this returns has a non-obvious life-cy
grt (UTC plus 2)
2013/06/20 19:55:29
Done.
| |
| 54 | |
| 55 GURL rendered_url_; | |
| 56 base::win::ScopedComPtr<IWebBrowser2> web_browser_; | |
| 57 ReadyModeWebBrowserAdapter* adapter_; | |
| 58 | |
| 59 DISALLOW_COPY_AND_ASSIGN(BrowserObserver); | |
| 60 }; | |
| 61 | |
| 62 // Implements launching of a URL in an instance of IWebBrowser2. | |
| 63 class UrlLauncherImpl : public UrlLauncher { | |
| 64 public: | |
| 65 explicit UrlLauncherImpl(IWebBrowser2* web_browser); | |
| 66 | |
| 67 // UrlLauncher implementation | |
| 68 void LaunchUrl(const std::wstring& url); | |
| 69 | |
| 70 private: | |
| 71 base::win::ScopedComPtr<IWebBrowser2> web_browser_; | |
| 72 }; | |
| 73 | |
| 74 UrlLauncherImpl::UrlLauncherImpl(IWebBrowser2* web_browser) { | |
| 75 DCHECK(web_browser); | |
| 76 web_browser_ = web_browser; | |
| 77 } | |
| 78 | |
| 79 void UrlLauncherImpl::LaunchUrl(const std::wstring& url) { | |
| 80 VARIANT flags = { VT_I4 }; | |
| 81 V_I4(&flags) = navOpenInNewWindow; | |
| 82 base::win::ScopedBstr location(url.c_str()); | |
| 83 | |
| 84 HRESULT hr = web_browser_->Navigate(location, &flags, NULL, NULL, NULL); | |
| 85 DLOG_IF(ERROR, FAILED(hr)) << "Failed to invoke Navigate on IWebBrowser2. " | |
| 86 << "Error: " << hr; | |
| 87 } | |
| 88 | |
| 89 BrowserObserver::BrowserObserver(IWebBrowser2* web_browser, | |
| 90 ReadyModeWebBrowserAdapter* adapter) | |
| 91 : web_browser_(web_browser), | |
| 92 adapter_(adapter) { | |
| 93 } | |
| 94 | |
| 95 void BrowserObserver::OnNavigateTo(const std::wstring& url) { | |
| 96 if (!net::registry_controlled_domains::SameDomainOrHost( | |
| 97 GURL(url), | |
| 98 rendered_url_, | |
| 99 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES)) { | |
| 100 rendered_url_ = GURL(); | |
| 101 Hide(); | |
| 102 } | |
| 103 } | |
| 104 | |
| 105 void BrowserObserver::OnRenderInChromeFrame(const std::wstring& url) { | |
| 106 ShowPrompt(); | |
| 107 rendered_url_ = GURL(url); | |
| 108 } | |
| 109 | |
| 110 void BrowserObserver::OnRenderInHost(const std::wstring& url) { | |
| 111 Hide(); | |
| 112 rendered_url_ = GURL(url); | |
| 113 } | |
| 114 | |
| 115 void BrowserObserver::ShowPrompt() { | |
| 116 BrowserDistribution* dist = | |
| 117 BrowserDistribution::GetSpecificDistribution( | |
| 118 BrowserDistribution::CHROME_FRAME); | |
| 119 turndown_prompt::ReshowState reshow_state( | |
| 120 dist->GetStateKey(), | |
| 121 base::TimeDelta::FromMinutes(kTurndownPromptReshowDeltaMinutes)); | |
| 122 | |
| 123 // Short-circuit if the prompt shouldn't be shown again yet. | |
| 124 if (!reshow_state.HasReshowDeltaExpired(base::Time::Now())) | |
| 125 return; | |
| 126 | |
| 127 // This pointer is self-managed and not guaranteed to survive handling of | |
| 128 // Windows events. | |
|
robertshield
2013/06/19 23:36:33
As an unfamiliar reader, I don't know how to parse
grt (UTC plus 2)
2013/06/20 19:55:29
Done.
| |
| 129 InfobarManager* infobar_manager = GetInfobarManager(); | |
| 130 | |
| 131 if (infobar_manager) { | |
| 132 // Owned by infobar_content | |
| 133 scoped_ptr<UrlLauncher> url_launcher(new UrlLauncherImpl(web_browser_)); | |
| 134 | |
| 135 // Owned by infobar_manager | |
| 136 scoped_ptr<InfobarContent> infobar_content(new TurndownPromptContent( | |
| 137 url_launcher.release(), | |
| 138 base::Bind(&UninstallChromeFrame))); | |
| 139 | |
| 140 if (infobar_manager->Show(infobar_content.release(), TOP_INFOBAR)) { | |
| 141 // Update state in the registry that the prompt was shown. | |
| 142 reshow_state.MarkShown(base::Time::Now()); | |
|
robertshield
2013/06/19 23:36:33
Random thought: if I open two tabs both rendering
grt (UTC plus 2)
2013/06/20 19:55:29
I think this is possible.
robertshield
2013/06/20 21:45:10
Yeah, was simply musing. I don't have an immediate
| |
| 143 } | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 void BrowserObserver::Hide() { | |
| 148 InfobarManager* infobar_manager = GetInfobarManager(); | |
| 149 if (infobar_manager) | |
| 150 infobar_manager->HideAll(); | |
| 151 } | |
| 152 | |
| 153 InfobarManager* BrowserObserver::GetInfobarManager() { | |
| 154 HRESULT hr = NOERROR; | |
| 155 | |
| 156 base::win::ScopedComPtr<IOleWindow> ole_window; | |
| 157 hr = DoQueryService(SID_SShellBrowser, web_browser_, ole_window.Receive()); | |
| 158 if (FAILED(hr) || ole_window == NULL) { | |
| 159 DLOG(ERROR) << "Failed to query SID_SShellBrowser from IWebBrowser2. " | |
| 160 << "Error: " << hr; | |
| 161 return NULL; | |
| 162 } | |
| 163 | |
| 164 HWND web_browserhwnd = NULL; | |
|
robertshield
2013/06/19 23:36:33
nit: web_browser_hwnd
grt (UTC plus 2)
2013/06/20 19:55:29
Done.
| |
| 165 hr = ole_window->GetWindow(&web_browserhwnd); | |
| 166 if (FAILED(hr) || web_browserhwnd == NULL) { | |
| 167 DLOG(ERROR) << "Failed to query HWND from IOleWindow. " | |
| 168 << "Error: " << hr; | |
| 169 return NULL; | |
| 170 } | |
| 171 | |
| 172 return InfobarManager::Get(web_browserhwnd); | |
| 173 } | |
| 174 | |
| 175 // Attempts to create a ReadyModeWebBrowserAdapter instance. | |
| 176 bool CreateWebBrowserAdapter(ReadyModeWebBrowserAdapter** pointer) { | |
|
robertshield
2013/06/19 23:36:33
nit: pointer -> adapter
grt (UTC plus 2)
2013/06/20 19:55:29
Done.
| |
| 177 *pointer = NULL; | |
| 178 | |
| 179 CComObject<ReadyModeWebBrowserAdapter>* com_object; | |
| 180 HRESULT hr = | |
| 181 CComObject<ReadyModeWebBrowserAdapter>::CreateInstance(&com_object); | |
| 182 | |
| 183 if (FAILED(hr)) { | |
| 184 DLOG(ERROR) << "Failed to create instance of ReadyModeWebBrowserAdapter. " | |
| 185 << "Error: " << hr; | |
| 186 return false; | |
| 187 } | |
| 188 | |
| 189 com_object->AddRef(); | |
| 190 *pointer = com_object; | |
| 191 return true; | |
| 192 } | |
| 193 | |
| 194 // Attempts to install Turnown prompts in the provided web browser. | |
| 195 bool InstallPrompts(IWebBrowser2* web_browser) { | |
| 196 base::win::ScopedComPtr<ReadyModeWebBrowserAdapter, NULL> adapter; | |
| 197 | |
| 198 if (!CreateWebBrowserAdapter(adapter.Receive())) | |
| 199 return false; | |
| 200 | |
| 201 // Pass ownership of our delegate to the BrowserObserver | |
| 202 scoped_ptr<ReadyModeWebBrowserAdapter::Observer> browser_observer( | |
| 203 new BrowserObserver(web_browser, adapter)); | |
| 204 | |
| 205 // Owns the BrowserObserver | |
| 206 return adapter->Initialize(web_browser, browser_observer.release()); | |
| 207 } | |
| 208 | |
| 209 // Uninstalls Chrome Frame in response to user action. | |
| 210 void UninstallChromeFrame() { | |
| 211 // TODO(grt) Find and run the uninstaller. | |
| 212 } | |
| 213 | |
| 214 } // namespace | |
| 215 | |
| 216 namespace turndown_prompt { | |
| 217 | |
| 218 bool IsPromptSuppressed() { | |
| 219 // See if updates are disabled for Chrome Frame (check the binaries if | |
| 220 // multi-install). | |
|
robertshield
2013/06/19 23:36:33
I wonder if we should check the MSI bit as well?
grt (UTC plus 2)
2013/06/20 19:55:29
Done.
| |
| 221 BrowserDistribution* dist = | |
| 222 BrowserDistribution::GetSpecificDistribution( | |
| 223 BrowserDistribution::CHROME_FRAME); | |
| 224 | |
| 225 base::FilePath dll_path; | |
| 226 if (PathService::Get(base::DIR_MODULE, &dll_path)) { | |
| 227 bool system_level = | |
| 228 !InstallUtil::IsPerUserInstall(dll_path.value().c_str()); | |
| 229 bool multi_install = InstallUtil::IsMultiInstall(dist, system_level); | |
| 230 if (multi_install) { | |
| 231 dist = | |
| 232 BrowserDistribution::GetSpecificDistribution( | |
| 233 BrowserDistribution::CHROME_BINARIES); | |
| 234 } | |
| 235 if (GoogleUpdateSettings::GetAppUpdatePolicy(dist->GetAppGuid(), NULL) == | |
| 236 GoogleUpdateSettings::UPDATES_DISABLED) { | |
| 237 return true; | |
| 238 } | |
| 239 } | |
| 240 | |
| 241 // See if the prompt is explicitly suppressed via GP. | |
| 242 return PolicySettings::GetInstance()->suppress_turndown_prompt(); | |
| 243 } | |
| 244 | |
| 245 void Configure(IWebBrowser2* web_browser) { | |
| 246 if (!IsPromptSuppressed()) | |
| 247 InstallPrompts(web_browser); | |
| 248 } | |
| 249 | |
| 250 } // namespace turndown_prompt | |
| OLD | NEW |