| 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/ui/webui/set_as_default_browser_ui.h" | |
| 6 | |
| 7 #include <string> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/bind_helpers.h" | |
| 12 #include "base/macros.h" | |
| 13 #include "base/memory/weak_ptr.h" | |
| 14 #include "base/metrics/histogram.h" | |
| 15 #include "chrome/browser/profiles/profile.h" | |
| 16 #include "chrome/browser/shell_integration.h" | |
| 17 #include "chrome/browser/ui/browser.h" | |
| 18 #include "chrome/browser/ui/browser_dialogs.h" | |
| 19 #include "chrome/browser/ui/browser_finder.h" | |
| 20 #include "chrome/browser/ui/browser_list.h" | |
| 21 #include "chrome/browser/ui/browser_list_observer.h" | |
| 22 #include "chrome/browser/ui/browser_window.h" | |
| 23 #include "chrome/browser/ui/chrome_pages.h" | |
| 24 #include "chrome/browser/ui/singleton_tabs.h" | |
| 25 #include "chrome/browser/ui/startup/default_browser_prompt.h" | |
| 26 #include "chrome/browser/ui/sync/sync_promo_ui.h" | |
| 27 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
| 28 #include "chrome/common/pref_names.h" | |
| 29 #include "chrome/common/url_constants.h" | |
| 30 #include "chrome/grit/chromium_strings.h" | |
| 31 #include "chrome/grit/generated_resources.h" | |
| 32 #include "chrome/grit/locale_settings.h" | |
| 33 #include "chrome/installer/util/install_util.h" | |
| 34 #include "components/prefs/pref_service.h" | |
| 35 #include "content/public/browser/browser_thread.h" | |
| 36 #include "content/public/browser/web_contents.h" | |
| 37 #include "content/public/browser/web_contents_delegate.h" | |
| 38 #include "content/public/browser/web_ui.h" | |
| 39 #include "content/public/browser/web_ui_data_source.h" | |
| 40 #include "content/public/browser/web_ui_message_handler.h" | |
| 41 #include "grit/browser_resources.h" | |
| 42 #include "ui/base/l10n/l10n_font_util.h" | |
| 43 #include "ui/base/l10n/l10n_util.h" | |
| 44 #include "ui/gfx/font.h" | |
| 45 #include "ui/views/widget/widget.h" | |
| 46 #include "ui/web_dialogs/web_dialog_delegate.h" | |
| 47 | |
| 48 using content::BrowserThread; | |
| 49 using content::WebContents; | |
| 50 using content::WebUIMessageHandler; | |
| 51 | |
| 52 namespace { | |
| 53 | |
| 54 const char kSetAsDefaultBrowserHistogram[] = "DefaultBrowser.InteractionResult"; | |
| 55 | |
| 56 // The enum permits registering in UMA the three possible outcomes (do not | |
| 57 // reorder these). | |
| 58 // ACCEPTED: user pressed Next and made Chrome default. | |
| 59 // DECLINED: user simply closed the dialog without making Chrome default. | |
| 60 // REGRETTED: user pressed Next but then elected a different default browser. | |
| 61 enum MakeChromeDefaultResult { | |
| 62 MAKE_CHROME_DEFAULT_ACCEPTED = 0, | |
| 63 MAKE_CHROME_DEFAULT_DECLINED = 1, | |
| 64 MAKE_CHROME_DEFAULT_REGRETTED = 2, | |
| 65 // MAKE_CHROME_DEFAULT_ACCEPTED_IMMERSE = 3, // Deprecated. | |
| 66 MAKE_CHROME_DEFAULT_MAX | |
| 67 }; | |
| 68 | |
| 69 content::WebUIDataSource* CreateSetAsDefaultBrowserUIHTMLSource() { | |
| 70 content::WebUIDataSource* data_source = content::WebUIDataSource::Create( | |
| 71 chrome::kChromeUIMetroFlowHost); | |
| 72 data_source->AddLocalizedString("page-title", IDS_METRO_FLOW_TAB_TITLE); | |
| 73 data_source->AddLocalizedString("flowTitle", IDS_METRO_FLOW_TITLE_SHORT); | |
| 74 data_source->AddLocalizedString("flowDescription", | |
| 75 IDS_METRO_FLOW_DESCRIPTION); | |
| 76 data_source->AddLocalizedString("flowNext", | |
| 77 IDS_METRO_FLOW_SET_DEFAULT); | |
| 78 data_source->AddLocalizedString("chromeLogoString", | |
| 79 IDS_METRO_FLOW_LOGO_STRING_ALT); | |
| 80 data_source->SetJsonPath("strings.js"); | |
| 81 data_source->AddResourcePath("set_as_default_browser.js", | |
| 82 IDR_SET_AS_DEFAULT_BROWSER_JS); | |
| 83 data_source->SetDefaultResource(IDR_SET_AS_DEFAULT_BROWSER_HTML); | |
| 84 return data_source; | |
| 85 } | |
| 86 | |
| 87 // A simple class serving as a delegate for passing down the result of the | |
| 88 // interaction. | |
| 89 class ResponseDelegate { | |
| 90 public: | |
| 91 virtual void SetDialogInteractionResult(MakeChromeDefaultResult result) = 0; | |
| 92 | |
| 93 protected: | |
| 94 virtual ~ResponseDelegate() { } | |
| 95 }; | |
| 96 | |
| 97 // Event handler for SetAsDefaultBrowserUI. Capable of setting Chrome as the | |
| 98 // default browser on button click, closing itself and triggering Chrome | |
| 99 // restart. | |
| 100 class SetAsDefaultBrowserHandler : public WebUIMessageHandler { | |
| 101 public: | |
| 102 explicit SetAsDefaultBrowserHandler( | |
| 103 const base::WeakPtr<ResponseDelegate>& response_delegate); | |
| 104 | |
| 105 // WebUIMessageHandler implementation. | |
| 106 void RegisterMessages() override; | |
| 107 | |
| 108 private: | |
| 109 // Handler for the 'Next' (or 'make Chrome the Metro browser') button. | |
| 110 void HandleLaunchSetDefaultBrowserFlow(const base::ListValue* args); | |
| 111 | |
| 112 // Close this web ui. | |
| 113 void ConcludeInteraction(MakeChromeDefaultResult interaction_result); | |
| 114 | |
| 115 void OnDefaultBrowserWorkerFinished( | |
| 116 shell_integration::DefaultWebClientState state); | |
| 117 | |
| 118 // The worker pointer is reference counted. While it is running, the | |
| 119 // message loops of the FILE and UI thread will hold references to it | |
| 120 // and it will be automatically freed once all its tasks have finished. | |
| 121 scoped_refptr<shell_integration::DefaultBrowserWorker> | |
| 122 default_browser_worker_; | |
| 123 base::WeakPtr<ResponseDelegate> response_delegate_; | |
| 124 | |
| 125 // Used to invalidate the DefaultBrowserWorker callback. | |
| 126 base::WeakPtrFactory<SetAsDefaultBrowserHandler> weak_ptr_factory_; | |
| 127 | |
| 128 DISALLOW_COPY_AND_ASSIGN(SetAsDefaultBrowserHandler); | |
| 129 }; | |
| 130 | |
| 131 SetAsDefaultBrowserHandler::SetAsDefaultBrowserHandler( | |
| 132 const base::WeakPtr<ResponseDelegate>& response_delegate) | |
| 133 : response_delegate_(response_delegate), weak_ptr_factory_(this) { | |
| 134 default_browser_worker_ = new shell_integration::DefaultBrowserWorker( | |
| 135 base::Bind(&SetAsDefaultBrowserHandler::OnDefaultBrowserWorkerFinished, | |
| 136 weak_ptr_factory_.GetWeakPtr())); | |
| 137 } | |
| 138 | |
| 139 void SetAsDefaultBrowserHandler::RegisterMessages() { | |
| 140 web_ui()->RegisterMessageCallback( | |
| 141 "SetAsDefaultBrowser:LaunchSetDefaultBrowserFlow", | |
| 142 base::Bind(&SetAsDefaultBrowserHandler::HandleLaunchSetDefaultBrowserFlow, | |
| 143 base::Unretained(this))); | |
| 144 } | |
| 145 | |
| 146 void SetAsDefaultBrowserHandler::HandleLaunchSetDefaultBrowserFlow( | |
| 147 const base::ListValue* args) { | |
| 148 default_browser_worker_->StartSetAsDefault(); | |
| 149 } | |
| 150 | |
| 151 void SetAsDefaultBrowserHandler::ConcludeInteraction( | |
| 152 MakeChromeDefaultResult interaction_result) { | |
| 153 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 154 | |
| 155 if (response_delegate_) | |
| 156 response_delegate_->SetDialogInteractionResult(interaction_result); | |
| 157 | |
| 158 WebContents* contents = web_ui()->GetWebContents(); | |
| 159 | |
| 160 if (contents) { | |
| 161 content::WebContentsDelegate* delegate = contents->GetDelegate(); | |
| 162 if (delegate) | |
| 163 delegate->CloseContents(contents); | |
| 164 } | |
| 165 } | |
| 166 | |
| 167 void SetAsDefaultBrowserHandler::OnDefaultBrowserWorkerFinished( | |
| 168 shell_integration::DefaultWebClientState state) { | |
| 169 // The callback is expected to be invoked once the procedure has completed. | |
| 170 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 171 if (state == shell_integration::NOT_DEFAULT) { | |
| 172 // The operation concluded, but Chrome is still not the default. This | |
| 173 // suggests the user has decided not to make Chrome the default. | |
| 174 ConcludeInteraction(MAKE_CHROME_DEFAULT_REGRETTED); | |
| 175 } else if (state == shell_integration::IS_DEFAULT) { | |
| 176 ConcludeInteraction(MAKE_CHROME_DEFAULT_ACCEPTED); | |
| 177 } | |
| 178 | |
| 179 // Otherwise, keep the dialog open since the user probably didn't make a | |
| 180 // choice. | |
| 181 } | |
| 182 | |
| 183 // A web dialog delegate implementation for when 'Make Chrome Metro' UI | |
| 184 // is displayed on a dialog. | |
| 185 class SetAsDefaultBrowserDialogImpl : public ui::WebDialogDelegate, | |
| 186 public ResponseDelegate, | |
| 187 public chrome::BrowserListObserver { | |
| 188 public: | |
| 189 SetAsDefaultBrowserDialogImpl(Profile* profile, Browser* browser); | |
| 190 ~SetAsDefaultBrowserDialogImpl() override; | |
| 191 // Show a modal web dialog with kChromeUIMetroFlowURL page. | |
| 192 void ShowDialog(); | |
| 193 | |
| 194 protected: | |
| 195 // Overridden from WebDialogDelegate: | |
| 196 ui::ModalType GetDialogModalType() const override; | |
| 197 base::string16 GetDialogTitle() const override; | |
| 198 GURL GetDialogContentURL() const override; | |
| 199 void GetWebUIMessageHandlers( | |
| 200 std::vector<WebUIMessageHandler*>* handlers) const override; | |
| 201 void GetDialogSize(gfx::Size* size) const override; | |
| 202 std::string GetDialogArgs() const override; | |
| 203 void OnDialogClosed(const std::string& json_retval) override; | |
| 204 void OnCloseContents(WebContents* source, bool* out_close_dialog) override; | |
| 205 bool ShouldShowDialogTitle() const override; | |
| 206 bool HandleContextMenu(const content::ContextMenuParams& params) override; | |
| 207 | |
| 208 // Overridden from ResponseDelegate: | |
| 209 void SetDialogInteractionResult(MakeChromeDefaultResult result) override; | |
| 210 | |
| 211 // Overridden from BrowserListObserver: | |
| 212 void OnBrowserRemoved(Browser* browser) override; | |
| 213 | |
| 214 private: | |
| 215 Profile* profile_; | |
| 216 Browser* browser_; | |
| 217 mutable bool owns_handler_; | |
| 218 base::WeakPtrFactory<ResponseDelegate> response_delegate_ptr_factory_; | |
| 219 SetAsDefaultBrowserHandler* handler_; | |
| 220 MakeChromeDefaultResult dialog_interaction_result_; | |
| 221 | |
| 222 DISALLOW_COPY_AND_ASSIGN(SetAsDefaultBrowserDialogImpl); | |
| 223 }; | |
| 224 | |
| 225 SetAsDefaultBrowserDialogImpl::SetAsDefaultBrowserDialogImpl(Profile* profile, | |
| 226 Browser* browser) | |
| 227 : profile_(profile), | |
| 228 browser_(browser), | |
| 229 owns_handler_(true), | |
| 230 response_delegate_ptr_factory_(this), | |
| 231 handler_(new SetAsDefaultBrowserHandler( | |
| 232 response_delegate_ptr_factory_.GetWeakPtr())), | |
| 233 dialog_interaction_result_(MAKE_CHROME_DEFAULT_DECLINED) { | |
| 234 BrowserList::AddObserver(this); | |
| 235 } | |
| 236 | |
| 237 SetAsDefaultBrowserDialogImpl::~SetAsDefaultBrowserDialogImpl() { | |
| 238 if (browser_) | |
| 239 BrowserList::RemoveObserver(this); | |
| 240 if (owns_handler_) | |
| 241 delete handler_; | |
| 242 } | |
| 243 | |
| 244 void SetAsDefaultBrowserDialogImpl::ShowDialog() { | |
| 245 // Use a NULL parent window to make sure that the dialog will have an item | |
| 246 // in the Windows task bar. The code below will make it highlight if the | |
| 247 // dialog is not in the foreground. | |
| 248 gfx::NativeWindow native_window = chrome::ShowWebDialog(NULL, profile_, this); | |
| 249 views::Widget* widget = views::Widget::GetWidgetForNativeWindow( | |
| 250 native_window); | |
| 251 widget->FlashFrame(true); | |
| 252 } | |
| 253 | |
| 254 ui::ModalType SetAsDefaultBrowserDialogImpl::GetDialogModalType() const { | |
| 255 return ui::MODAL_TYPE_SYSTEM; | |
| 256 } | |
| 257 | |
| 258 base::string16 SetAsDefaultBrowserDialogImpl::GetDialogTitle() const { | |
| 259 return l10n_util::GetStringUTF16(IDS_METRO_FLOW_TAB_TITLE); | |
| 260 } | |
| 261 | |
| 262 GURL SetAsDefaultBrowserDialogImpl::GetDialogContentURL() const { | |
| 263 std::string url_string(chrome::kChromeUIMetroFlowURL); | |
| 264 return GURL(url_string); | |
| 265 } | |
| 266 | |
| 267 void SetAsDefaultBrowserDialogImpl::GetWebUIMessageHandlers( | |
| 268 std::vector<WebUIMessageHandler*>* handlers) const { | |
| 269 handlers->push_back(handler_); | |
| 270 owns_handler_ = false; | |
| 271 } | |
| 272 | |
| 273 void SetAsDefaultBrowserDialogImpl::GetDialogSize(gfx::Size* size) const { | |
| 274 PrefService* prefs = profile_->GetPrefs(); | |
| 275 gfx::Font approximate_web_font( | |
| 276 prefs->GetString(prefs::kWebKitSansSerifFontFamily), | |
| 277 prefs->GetInteger(prefs::kWebKitDefaultFontSize)); | |
| 278 | |
| 279 *size = ui::GetLocalizedContentsSizeForFont( | |
| 280 IDS_METRO_FLOW_WIDTH_CHARS, IDS_METRO_FLOW_HEIGHT_LINES, | |
| 281 approximate_web_font); | |
| 282 } | |
| 283 | |
| 284 std::string SetAsDefaultBrowserDialogImpl::GetDialogArgs() const { | |
| 285 return "[]"; | |
| 286 } | |
| 287 | |
| 288 void SetAsDefaultBrowserDialogImpl::OnDialogClosed( | |
| 289 const std::string& json_retval) { | |
| 290 // Register the user's response in UMA. | |
| 291 UMA_HISTOGRAM_ENUMERATION(kSetAsDefaultBrowserHistogram, | |
| 292 dialog_interaction_result_, | |
| 293 MAKE_CHROME_DEFAULT_MAX); | |
| 294 | |
| 295 // Suppress showing the default browser infobar if the user explicitly elected | |
| 296 // *not to* make Chrome default. | |
| 297 if (dialog_interaction_result_ == MAKE_CHROME_DEFAULT_REGRETTED) | |
| 298 chrome::DefaultBrowserPromptDeclined(profile_); | |
| 299 | |
| 300 // Carry on with a normal chrome session. For the purpose of surfacing this | |
| 301 // dialog the actual browser window had to remain hidden. Now it's time to | |
| 302 // show it. | |
| 303 if (browser_) { | |
| 304 BrowserWindow* window = browser_->window(); | |
| 305 WebContents* contents = browser_->tab_strip_model()->GetActiveWebContents(); | |
| 306 window->Show(); | |
| 307 if (contents) | |
| 308 contents->SetInitialFocus(); | |
| 309 } | |
| 310 | |
| 311 delete this; | |
| 312 } | |
| 313 | |
| 314 void SetAsDefaultBrowserDialogImpl::OnCloseContents(WebContents* source, | |
| 315 bool* out_close_dialog) { | |
| 316 *out_close_dialog = true; | |
| 317 } | |
| 318 | |
| 319 bool SetAsDefaultBrowserDialogImpl::ShouldShowDialogTitle() const { | |
| 320 return true; | |
| 321 } | |
| 322 | |
| 323 bool SetAsDefaultBrowserDialogImpl::HandleContextMenu( | |
| 324 const content::ContextMenuParams& params) { | |
| 325 return true; | |
| 326 } | |
| 327 | |
| 328 void SetAsDefaultBrowserDialogImpl::SetDialogInteractionResult( | |
| 329 MakeChromeDefaultResult result) { | |
| 330 dialog_interaction_result_ = result; | |
| 331 } | |
| 332 | |
| 333 void SetAsDefaultBrowserDialogImpl::OnBrowserRemoved(Browser* browser) { | |
| 334 if (browser_ == browser) { | |
| 335 browser_ = NULL; | |
| 336 BrowserList::RemoveObserver(this); | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 } // namespace | |
| 341 | |
| 342 SetAsDefaultBrowserUI::SetAsDefaultBrowserUI(content::WebUI* web_ui) | |
| 343 : ui::WebDialogUI(web_ui) { | |
| 344 content::WebUIDataSource::Add( | |
| 345 Profile::FromWebUI(web_ui), CreateSetAsDefaultBrowserUIHTMLSource()); | |
| 346 } | |
| 347 | |
| 348 // static | |
| 349 void SetAsDefaultBrowserUI::Show(Profile* profile, Browser* browser) { | |
| 350 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 351 SetAsDefaultBrowserDialogImpl* dialog = | |
| 352 new SetAsDefaultBrowserDialogImpl(profile, browser); | |
| 353 dialog->ShowDialog(); | |
| 354 } | |
| OLD | NEW |