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/installer/util/installation_state.h" |
| 22 #include "chrome_frame/infobars/infobar_manager.h" |
| 23 #include "chrome_frame/policy_settings.h" |
| 24 #include "chrome_frame/ready_mode/internal/ready_mode_web_browser_adapter.h" |
| 25 #include "chrome_frame/ready_mode/internal/url_launcher.h" |
| 26 #include "chrome_frame/turndown_prompt/reshow_state.h" |
| 27 #include "chrome_frame/turndown_prompt/turndown_prompt_content.h" |
| 28 #include "chrome_frame/utils.h" |
| 29 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| 30 |
| 31 namespace { |
| 32 |
| 33 // Time between showings of the turndown prompt. |
| 34 const int kTurndownPromptReshowDeltaMinutes = 60 * 24 * 7; |
| 35 |
| 36 void UninstallChromeFrame(); |
| 37 |
| 38 // Manages the Turndown UI in response to browsing ChromeFrame-rendered |
| 39 // pages. |
| 40 class BrowserObserver : public ReadyModeWebBrowserAdapter::Observer { |
| 41 public: |
| 42 BrowserObserver(IWebBrowser2* web_browser, |
| 43 ReadyModeWebBrowserAdapter* adapter); |
| 44 |
| 45 // ReadyModeWebBrowserAdapter::Observer implementation |
| 46 virtual void OnNavigateTo(const std::wstring& url); |
| 47 virtual void OnRenderInChromeFrame(const std::wstring& url); |
| 48 virtual void OnRenderInHost(const std::wstring& url); |
| 49 |
| 50 private: |
| 51 // Shows the turndown prompt if it hasn't been seen since |
| 52 // kTurndownPromptReshowDeltaMinutes. |
| 53 void ShowPrompt(); |
| 54 void Hide(); |
| 55 // Returns a self-managed pointer that is not guaranteed to survive handling |
| 56 // of Windows events. For safety's sake, retrieve this pointer for each use |
| 57 // and do not store it for use outside of scope. |
| 58 InfobarManager* GetInfobarManager(); |
| 59 |
| 60 GURL rendered_url_; |
| 61 base::win::ScopedComPtr<IWebBrowser2> web_browser_; |
| 62 ReadyModeWebBrowserAdapter* adapter_; |
| 63 |
| 64 DISALLOW_COPY_AND_ASSIGN(BrowserObserver); |
| 65 }; |
| 66 |
| 67 // Implements launching of a URL in an instance of IWebBrowser2. |
| 68 class UrlLauncherImpl : public UrlLauncher { |
| 69 public: |
| 70 explicit UrlLauncherImpl(IWebBrowser2* web_browser); |
| 71 |
| 72 // UrlLauncher implementation |
| 73 void LaunchUrl(const std::wstring& url); |
| 74 |
| 75 private: |
| 76 base::win::ScopedComPtr<IWebBrowser2> web_browser_; |
| 77 }; |
| 78 |
| 79 UrlLauncherImpl::UrlLauncherImpl(IWebBrowser2* web_browser) { |
| 80 DCHECK(web_browser); |
| 81 web_browser_ = web_browser; |
| 82 } |
| 83 |
| 84 void UrlLauncherImpl::LaunchUrl(const std::wstring& url) { |
| 85 VARIANT flags = { VT_I4 }; |
| 86 V_I4(&flags) = navOpenInNewWindow; |
| 87 base::win::ScopedBstr location(url.c_str()); |
| 88 |
| 89 HRESULT hr = web_browser_->Navigate(location, &flags, NULL, NULL, NULL); |
| 90 DLOG_IF(ERROR, FAILED(hr)) << "Failed to invoke Navigate on IWebBrowser2. " |
| 91 << "Error: " << hr; |
| 92 } |
| 93 |
| 94 BrowserObserver::BrowserObserver(IWebBrowser2* web_browser, |
| 95 ReadyModeWebBrowserAdapter* adapter) |
| 96 : web_browser_(web_browser), |
| 97 adapter_(adapter) { |
| 98 } |
| 99 |
| 100 void BrowserObserver::OnNavigateTo(const std::wstring& url) { |
| 101 if (!net::registry_controlled_domains::SameDomainOrHost( |
| 102 GURL(url), |
| 103 rendered_url_, |
| 104 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES)) { |
| 105 rendered_url_ = GURL(); |
| 106 Hide(); |
| 107 } |
| 108 } |
| 109 |
| 110 void BrowserObserver::OnRenderInChromeFrame(const std::wstring& url) { |
| 111 ShowPrompt(); |
| 112 rendered_url_ = GURL(url); |
| 113 } |
| 114 |
| 115 void BrowserObserver::OnRenderInHost(const std::wstring& url) { |
| 116 Hide(); |
| 117 rendered_url_ = GURL(url); |
| 118 } |
| 119 |
| 120 void BrowserObserver::ShowPrompt() { |
| 121 BrowserDistribution* dist = |
| 122 BrowserDistribution::GetSpecificDistribution( |
| 123 BrowserDistribution::CHROME_FRAME); |
| 124 turndown_prompt::ReshowState reshow_state( |
| 125 dist->GetStateKey(), |
| 126 base::TimeDelta::FromMinutes(kTurndownPromptReshowDeltaMinutes)); |
| 127 |
| 128 // Short-circuit if the prompt shouldn't be shown again yet. |
| 129 if (!reshow_state.HasReshowDeltaExpired(base::Time::Now())) |
| 130 return; |
| 131 |
| 132 // This pointer is self-managed and not guaranteed to survive handling of |
| 133 // Windows events. For safety's sake, retrieve this pointer for each use and |
| 134 // do not store it for use outside of scope. |
| 135 InfobarManager* infobar_manager = GetInfobarManager(); |
| 136 |
| 137 if (infobar_manager) { |
| 138 // Owned by infobar_content |
| 139 scoped_ptr<UrlLauncher> url_launcher(new UrlLauncherImpl(web_browser_)); |
| 140 |
| 141 // Owned by infobar_manager |
| 142 scoped_ptr<InfobarContent> infobar_content(new TurndownPromptContent( |
| 143 url_launcher.release(), |
| 144 base::Bind(&UninstallChromeFrame))); |
| 145 |
| 146 if (infobar_manager->Show(infobar_content.release(), TOP_INFOBAR)) { |
| 147 // Update state in the registry that the prompt was shown. |
| 148 reshow_state.MarkShown(base::Time::Now()); |
| 149 } |
| 150 } |
| 151 } |
| 152 |
| 153 void BrowserObserver::Hide() { |
| 154 InfobarManager* infobar_manager = GetInfobarManager(); |
| 155 if (infobar_manager) |
| 156 infobar_manager->HideAll(); |
| 157 } |
| 158 |
| 159 InfobarManager* BrowserObserver::GetInfobarManager() { |
| 160 HRESULT hr = NOERROR; |
| 161 |
| 162 base::win::ScopedComPtr<IOleWindow> ole_window; |
| 163 hr = DoQueryService(SID_SShellBrowser, web_browser_, ole_window.Receive()); |
| 164 if (FAILED(hr) || ole_window == NULL) { |
| 165 DLOG(ERROR) << "Failed to query SID_SShellBrowser from IWebBrowser2. " |
| 166 << "Error: " << hr; |
| 167 return NULL; |
| 168 } |
| 169 |
| 170 HWND web_browser_hwnd = NULL; |
| 171 hr = ole_window->GetWindow(&web_browser_hwnd); |
| 172 if (FAILED(hr) || web_browser_hwnd == NULL) { |
| 173 DLOG(ERROR) << "Failed to query HWND from IOleWindow. " |
| 174 << "Error: " << hr; |
| 175 return NULL; |
| 176 } |
| 177 |
| 178 return InfobarManager::Get(web_browser_hwnd); |
| 179 } |
| 180 |
| 181 // Attempts to create a ReadyModeWebBrowserAdapter instance. |
| 182 bool CreateWebBrowserAdapter(ReadyModeWebBrowserAdapter** adapter) { |
| 183 *adapter = NULL; |
| 184 |
| 185 CComObject<ReadyModeWebBrowserAdapter>* com_object; |
| 186 HRESULT hr = |
| 187 CComObject<ReadyModeWebBrowserAdapter>::CreateInstance(&com_object); |
| 188 |
| 189 if (FAILED(hr)) { |
| 190 DLOG(ERROR) << "Failed to create instance of ReadyModeWebBrowserAdapter. " |
| 191 << "Error: " << hr; |
| 192 return false; |
| 193 } |
| 194 |
| 195 com_object->AddRef(); |
| 196 *adapter = com_object; |
| 197 return true; |
| 198 } |
| 199 |
| 200 // Attempts to install Turnown prompts in the provided web browser. |
| 201 bool InstallPrompts(IWebBrowser2* web_browser) { |
| 202 base::win::ScopedComPtr<ReadyModeWebBrowserAdapter, NULL> adapter; |
| 203 |
| 204 if (!CreateWebBrowserAdapter(adapter.Receive())) |
| 205 return false; |
| 206 |
| 207 // Pass ownership of our delegate to the BrowserObserver |
| 208 scoped_ptr<ReadyModeWebBrowserAdapter::Observer> browser_observer( |
| 209 new BrowserObserver(web_browser, adapter)); |
| 210 |
| 211 // Owns the BrowserObserver |
| 212 return adapter->Initialize(web_browser, browser_observer.release()); |
| 213 } |
| 214 |
| 215 // Uninstalls Chrome Frame in response to user action. |
| 216 void UninstallChromeFrame() { |
| 217 // TODO(grt) Find and run the uninstaller. |
| 218 } |
| 219 |
| 220 } // namespace |
| 221 |
| 222 namespace turndown_prompt { |
| 223 |
| 224 bool IsPromptSuppressed() { |
| 225 // See if this is an MSI install of GCF or if updates have been disabled. |
| 226 BrowserDistribution* dist = |
| 227 BrowserDistribution::GetSpecificDistribution( |
| 228 BrowserDistribution::CHROME_FRAME); |
| 229 |
| 230 base::FilePath dll_path; |
| 231 if (PathService::Get(base::DIR_MODULE, &dll_path)) { |
| 232 bool system_level = |
| 233 !InstallUtil::IsPerUserInstall(dll_path.value().c_str()); |
| 234 bool multi_install = false; |
| 235 |
| 236 installer::ProductState product_state; |
| 237 if (product_state.Initialize(system_level, dist)) { |
| 238 if (product_state.is_msi()) |
| 239 return true; |
| 240 multi_install = product_state.is_multi_install(); |
| 241 } |
| 242 |
| 243 if (multi_install) { |
| 244 dist = |
| 245 BrowserDistribution::GetSpecificDistribution( |
| 246 BrowserDistribution::CHROME_BINARIES); |
| 247 } |
| 248 if (GoogleUpdateSettings::GetAppUpdatePolicy(dist->GetAppGuid(), NULL) == |
| 249 GoogleUpdateSettings::UPDATES_DISABLED) { |
| 250 return true; |
| 251 } |
| 252 } |
| 253 |
| 254 // See if the prompt is explicitly suppressed via GP. |
| 255 return PolicySettings::GetInstance()->suppress_turndown_prompt(); |
| 256 } |
| 257 |
| 258 void Configure(IWebBrowser2* web_browser) { |
| 259 if (!IsPromptSuppressed()) |
| 260 InstallPrompts(web_browser); |
| 261 } |
| 262 |
| 263 } // namespace turndown_prompt |
OLD | NEW |