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.
5 #include "chrome/browser/ui/webui/set_as_default_browser_ui.h"
8 #include "base/bind_helpers.h"
9 #include "base/memory/weak_ptr.h"
10 #include "base/metrics/histogram.h"
11 #include "base/path_service.h"
12 #include "base/prefs/pref_service.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/shell_integration.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/browser_dialogs.h"
17 #include "chrome/browser/ui/browser_finder.h"
18 #include "chrome/browser/ui/browser_list.h"
19 #include "chrome/browser/ui/browser_list_observer.h"
20 #include "chrome/browser/ui/browser_window.h"
21 #include "chrome/browser/ui/chrome_pages.h"
22 #include "chrome/browser/ui/singleton_tabs.h"
23 #include "chrome/browser/ui/sync/sync_promo_ui.h"
24 #include "chrome/browser/ui/tabs/tab_strip_model.h"
25 #include "chrome/common/pref_names.h"
26 #include "chrome/common/url_constants.h"
27 #include "chrome/grit/generated_resources.h"
28 #include "chrome/grit/locale_settings.h"
29 #include "chrome/installer/util/install_util.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "content/public/browser/web_contents.h"
32 #include "content/public/browser/web_contents_delegate.h"
33 #include "content/public/browser/web_ui.h"
34 #include "content/public/browser/web_ui_data_source.h"
35 #include "content/public/browser/web_ui_message_handler.h"
36 #include "grit/browser_resources.h"
37 #include "ui/base/l10n/l10n_font_util.h"
38 #include "ui/base/l10n/l10n_util.h"
39 #include "ui/gfx/font.h"
40 #include "ui/views/widget/widget.h"
41 #include "ui/web_dialogs/web_dialog_delegate.h"
43 using content::BrowserThread
;
44 using content::WebContents
;
45 using content::WebUIMessageHandler
;
49 const char kSetAsDefaultBrowserHistogram
[] = "DefaultBrowser.InteractionResult";
51 // The enum permits registering in UMA the three possible outcomes (do not
53 // ACCEPTED: user pressed Next and made Chrome default.
54 // DECLINED: user simply closed the dialog without making Chrome default.
55 // REGRETTED: user pressed Next but then elected a different default browser.
56 enum MakeChromeDefaultResult
{
57 MAKE_CHROME_DEFAULT_ACCEPTED
= 0,
58 MAKE_CHROME_DEFAULT_DECLINED
= 1,
59 MAKE_CHROME_DEFAULT_REGRETTED
= 2,
60 // MAKE_CHROME_DEFAULT_ACCEPTED_IMMERSE = 3, // Deprecated.
61 MAKE_CHROME_DEFAULT_MAX
64 content::WebUIDataSource
* CreateSetAsDefaultBrowserUIHTMLSource() {
65 content::WebUIDataSource
* data_source
= content::WebUIDataSource::Create(
66 chrome::kChromeUIMetroFlowHost
);
67 data_source
->AddLocalizedString("page-title", IDS_METRO_FLOW_TAB_TITLE
);
68 data_source
->AddLocalizedString("flowTitle", IDS_METRO_FLOW_TITLE_SHORT
);
69 data_source
->AddLocalizedString("flowDescription",
70 IDS_METRO_FLOW_DESCRIPTION
);
71 data_source
->AddLocalizedString("flowNext",
72 IDS_METRO_FLOW_SET_DEFAULT
);
73 data_source
->AddLocalizedString("chromeLogoString",
74 IDS_METRO_FLOW_LOGO_STRING_ALT
);
75 data_source
->SetJsonPath("strings.js");
76 data_source
->AddResourcePath("set_as_default_browser.js",
77 IDR_SET_AS_DEFAULT_BROWSER_JS
);
78 data_source
->SetDefaultResource(IDR_SET_AS_DEFAULT_BROWSER_HTML
);
82 // A simple class serving as a delegate for passing down the result of the
84 class ResponseDelegate
{
86 virtual void SetDialogInteractionResult(MakeChromeDefaultResult result
) = 0;
89 virtual ~ResponseDelegate() { }
92 // Event handler for SetAsDefaultBrowserUI. Capable of setting Chrome as the
93 // default browser on button click, closing itself and triggering Chrome
95 class SetAsDefaultBrowserHandler
96 : public WebUIMessageHandler
,
97 public base::SupportsWeakPtr
<SetAsDefaultBrowserHandler
>,
98 public ShellIntegration::DefaultWebClientObserver
{
100 explicit SetAsDefaultBrowserHandler(
101 const base::WeakPtr
<ResponseDelegate
>& response_delegate
);
102 virtual ~SetAsDefaultBrowserHandler();
104 // WebUIMessageHandler implementation.
105 virtual void RegisterMessages() override
;
107 // ShellIntegration::DefaultWebClientObserver implementation.
108 virtual void SetDefaultWebClientUIState(
109 ShellIntegration::DefaultWebClientUIState state
) override
;
110 virtual void OnSetAsDefaultConcluded(bool close_chrome
) override
;
111 virtual bool IsInteractiveSetDefaultPermitted() override
;
114 // Handler for the 'Next' (or 'make Chrome the Metro browser') button.
115 void HandleLaunchSetDefaultBrowserFlow(const base::ListValue
* args
);
117 // Close this web ui.
118 void ConcludeInteraction(MakeChromeDefaultResult interaction_result
);
120 scoped_refptr
<ShellIntegration::DefaultBrowserWorker
> default_browser_worker_
;
121 bool set_default_returned_
;
122 bool set_default_result_
;
123 base::WeakPtr
<ResponseDelegate
> response_delegate_
;
125 DISALLOW_COPY_AND_ASSIGN(SetAsDefaultBrowserHandler
);
128 SetAsDefaultBrowserHandler::SetAsDefaultBrowserHandler(
129 const base::WeakPtr
<ResponseDelegate
>& response_delegate
)
130 : default_browser_worker_(new ShellIntegration::DefaultBrowserWorker(this)),
131 set_default_returned_(false), set_default_result_(false),
132 response_delegate_(response_delegate
) {
135 SetAsDefaultBrowserHandler::~SetAsDefaultBrowserHandler() {
136 default_browser_worker_
->ObserverDestroyed();
139 void SetAsDefaultBrowserHandler::RegisterMessages() {
140 web_ui()->RegisterMessageCallback(
141 "SetAsDefaultBrowser:LaunchSetDefaultBrowserFlow",
142 base::Bind(&SetAsDefaultBrowserHandler::HandleLaunchSetDefaultBrowserFlow
,
143 base::Unretained(this)));
146 void SetAsDefaultBrowserHandler::SetDefaultWebClientUIState(
147 ShellIntegration::DefaultWebClientUIState state
) {
148 // The callback is expected to be invoked once the procedure has completed.
149 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
150 if (!set_default_returned_
)
153 if (state
== ShellIntegration::STATE_NOT_DEFAULT
&& set_default_result_
) {
154 // The operation concluded, but Chrome is still not the default.
155 // If the call has succeeded, this suggests user has decided not to make
156 // chrome the default.
157 ConcludeInteraction(MAKE_CHROME_DEFAULT_REGRETTED
);
158 } else if (state
== ShellIntegration::STATE_IS_DEFAULT
) {
159 ConcludeInteraction(MAKE_CHROME_DEFAULT_ACCEPTED
);
162 // Otherwise, keep the dialog open since the user probably didn't make a
166 void SetAsDefaultBrowserHandler::OnSetAsDefaultConcluded(bool call_result
) {
167 set_default_returned_
= true;
168 set_default_result_
= call_result
;
171 bool SetAsDefaultBrowserHandler::IsInteractiveSetDefaultPermitted() {
175 void SetAsDefaultBrowserHandler::HandleLaunchSetDefaultBrowserFlow(
176 const base::ListValue
* args
) {
177 set_default_returned_
= false;
178 set_default_result_
= false;
179 default_browser_worker_
->StartSetAsDefault();
182 void SetAsDefaultBrowserHandler::ConcludeInteraction(
183 MakeChromeDefaultResult interaction_result
) {
184 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
186 if (response_delegate_
)
187 response_delegate_
->SetDialogInteractionResult(interaction_result
);
189 WebContents
* contents
= web_ui()->GetWebContents();
192 content::WebContentsDelegate
* delegate
= contents
->GetDelegate();
194 delegate
->CloseContents(contents
);
198 // A web dialog delegate implementation for when 'Make Chrome Metro' UI
199 // is displayed on a dialog.
200 class SetAsDefaultBrowserDialogImpl
: public ui::WebDialogDelegate
,
201 public ResponseDelegate
,
202 public chrome::BrowserListObserver
{
204 SetAsDefaultBrowserDialogImpl(Profile
* profile
, Browser
* browser
);
205 virtual ~SetAsDefaultBrowserDialogImpl();
206 // Show a modal web dialog with kChromeUIMetroFlowURL page.
210 // Overridden from WebDialogDelegate:
211 virtual ui::ModalType
GetDialogModalType() const override
;
212 virtual base::string16
GetDialogTitle() const override
;
213 virtual GURL
GetDialogContentURL() const override
;
214 virtual void GetWebUIMessageHandlers(
215 std::vector
<WebUIMessageHandler
*>* handlers
) const override
;
216 virtual void GetDialogSize(gfx::Size
* size
) const override
;
217 virtual std::string
GetDialogArgs() const override
;
218 virtual void OnDialogClosed(const std::string
& json_retval
) override
;
219 virtual void OnCloseContents(WebContents
* source
,
220 bool* out_close_dialog
) override
;
221 virtual bool ShouldShowDialogTitle() const override
;
222 virtual bool HandleContextMenu(
223 const content::ContextMenuParams
& params
) override
;
225 // Overridden from ResponseDelegate:
226 virtual void SetDialogInteractionResult(MakeChromeDefaultResult result
);
228 // Overridden from BrowserListObserver:
229 virtual void OnBrowserRemoved(Browser
* browser
) override
;
234 mutable bool owns_handler_
;
235 base::WeakPtrFactory
<ResponseDelegate
> response_delegate_ptr_factory_
;
236 SetAsDefaultBrowserHandler
* handler_
;
237 MakeChromeDefaultResult dialog_interaction_result_
;
239 DISALLOW_COPY_AND_ASSIGN(SetAsDefaultBrowserDialogImpl
);
242 SetAsDefaultBrowserDialogImpl::SetAsDefaultBrowserDialogImpl(Profile
* profile
,
247 response_delegate_ptr_factory_(this),
248 handler_(new SetAsDefaultBrowserHandler(
249 response_delegate_ptr_factory_
.GetWeakPtr())),
250 dialog_interaction_result_(MAKE_CHROME_DEFAULT_DECLINED
) {
251 BrowserList::AddObserver(this);
254 SetAsDefaultBrowserDialogImpl::~SetAsDefaultBrowserDialogImpl() {
256 BrowserList::RemoveObserver(this);
261 void SetAsDefaultBrowserDialogImpl::ShowDialog() {
262 // Use a NULL parent window to make sure that the dialog will have an item
263 // in the Windows task bar. The code below will make it highlight if the
264 // dialog is not in the foreground.
265 gfx::NativeWindow native_window
= chrome::ShowWebDialog(NULL
, profile_
, this);
266 views::Widget
* widget
= views::Widget::GetWidgetForNativeWindow(
268 widget
->FlashFrame(true);
271 ui::ModalType
SetAsDefaultBrowserDialogImpl::GetDialogModalType() const {
272 return ui::MODAL_TYPE_SYSTEM
;
275 base::string16
SetAsDefaultBrowserDialogImpl::GetDialogTitle() const {
276 return l10n_util::GetStringUTF16(IDS_METRO_FLOW_TAB_TITLE
);
279 GURL
SetAsDefaultBrowserDialogImpl::GetDialogContentURL() const {
280 std::string
url_string(chrome::kChromeUIMetroFlowURL
);
281 return GURL(url_string
);
284 void SetAsDefaultBrowserDialogImpl::GetWebUIMessageHandlers(
285 std::vector
<WebUIMessageHandler
*>* handlers
) const {
286 handlers
->push_back(handler_
);
287 owns_handler_
= false;
290 void SetAsDefaultBrowserDialogImpl::GetDialogSize(gfx::Size
* size
) const {
291 PrefService
* prefs
= profile_
->GetPrefs();
292 gfx::Font
approximate_web_font(
293 prefs
->GetString(prefs::kWebKitSansSerifFontFamily
),
294 prefs
->GetInteger(prefs::kWebKitDefaultFontSize
));
296 *size
= ui::GetLocalizedContentsSizeForFont(
297 IDS_METRO_FLOW_WIDTH_CHARS
, IDS_METRO_FLOW_HEIGHT_LINES
,
298 approximate_web_font
);
301 std::string
SetAsDefaultBrowserDialogImpl::GetDialogArgs() const {
305 void SetAsDefaultBrowserDialogImpl::OnDialogClosed(
306 const std::string
& json_retval
) {
307 // Register the user's response in UMA.
308 UMA_HISTOGRAM_ENUMERATION(kSetAsDefaultBrowserHistogram
,
309 dialog_interaction_result_
,
310 MAKE_CHROME_DEFAULT_MAX
);
312 // If the user explicitly elected *not to* make Chrome default, we won't
314 if (dialog_interaction_result_
== MAKE_CHROME_DEFAULT_REGRETTED
) {
315 PrefService
* prefs
= profile_
->GetPrefs();
316 prefs
->SetBoolean(prefs::kCheckDefaultBrowser
, false);
319 // Carry on with a normal chrome session. For the purpose of surfacing this
320 // dialog the actual browser window had to remain hidden. Now it's time to
323 BrowserWindow
* window
= browser_
->window();
324 WebContents
* contents
= browser_
->tab_strip_model()->GetActiveWebContents();
327 contents
->SetInitialFocus();
333 void SetAsDefaultBrowserDialogImpl::OnCloseContents(WebContents
* source
,
334 bool* out_close_dialog
) {
335 *out_close_dialog
= true;
338 bool SetAsDefaultBrowserDialogImpl::ShouldShowDialogTitle() const {
342 bool SetAsDefaultBrowserDialogImpl::HandleContextMenu(
343 const content::ContextMenuParams
& params
) {
347 void SetAsDefaultBrowserDialogImpl::SetDialogInteractionResult(
348 MakeChromeDefaultResult result
) {
349 dialog_interaction_result_
= result
;
352 void SetAsDefaultBrowserDialogImpl::OnBrowserRemoved(Browser
* browser
) {
353 if (browser_
== browser
) {
355 BrowserList::RemoveObserver(this);
361 SetAsDefaultBrowserUI::SetAsDefaultBrowserUI(content::WebUI
* web_ui
)
362 : ui::WebDialogUI(web_ui
) {
363 content::WebUIDataSource::Add(
364 Profile::FromWebUI(web_ui
), CreateSetAsDefaultBrowserUIHTMLSource());
368 void SetAsDefaultBrowserUI::Show(Profile
* profile
, Browser
* browser
) {
369 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
370 SetAsDefaultBrowserDialogImpl
* dialog
=
371 new SetAsDefaultBrowserDialogImpl(profile
, browser
);
372 dialog
->ShowDialog();