Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / set_as_default_browser_ui.cc
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 "base/bind.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 "base/win/win_util.h"
14 #include "chrome/browser/first_run/first_run.h"
15 #include "chrome/browser/lifetime/application_lifetime.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/shell_integration.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_dialogs.h"
20 #include "chrome/browser/ui/browser_finder.h"
21 #include "chrome/browser/ui/browser_list.h"
22 #include "chrome/browser/ui/browser_list_observer.h"
23 #include "chrome/browser/ui/browser_window.h"
24 #include "chrome/browser/ui/chrome_pages.h"
25 #include "chrome/browser/ui/singleton_tabs.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/installer/util/install_util.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/web_contents.h"
33 #include "content/public/browser/web_contents_delegate.h"
34 #include "content/public/browser/web_ui.h"
35 #include "content/public/browser/web_ui_data_source.h"
36 #include "content/public/browser/web_ui_message_handler.h"
37 #include "grit/browser_resources.h"
38 #include "grit/generated_resources.h"
39 #include "grit/locale_settings.h"
40 #include "ui/base/l10n/l10n_font_util.h"
41 #include "ui/base/l10n/l10n_util.h"
42 #include "ui/gfx/font.h"
43 #include "ui/views/widget/widget.h"
44 #include "ui/web_dialogs/web_dialog_delegate.h"
45
46 using content::BrowserThread;
47 using content::WebContents;
48 using content::WebUIMessageHandler;
49
50 namespace {
51
52 const char kSetAsDefaultBrowserHistogram[] = "DefaultBrowser.InteractionResult";
53
54 // The enum permits registering in UMA the three possible outcomes.
55 // ACCEPTED: user pressed Next and made Chrome default.
56 // DECLINED: user simply closed the dialog without making Chrome default.
57 // REGRETTED: user pressed Next but then elected a different default browser.
58 // ACCEPTED_IMMERSE: as above with a switch to metro mode.
59 enum MakeChromeDefaultResult {
60   MAKE_CHROME_DEFAULT_ACCEPTED,
61   MAKE_CHROME_DEFAULT_DECLINED,
62   MAKE_CHROME_DEFAULT_REGRETTED,
63   MAKE_CHROME_DEFAULT_ACCEPTED_IMMERSE,
64   MAKE_CHROME_DEFAULT_MAX
65 };
66
67 content::WebUIDataSource* CreateSetAsDefaultBrowserUIHTMLSource() {
68   content::WebUIDataSource* data_source = content::WebUIDataSource::Create(
69       chrome::kChromeUIMetroFlowHost);
70   data_source->AddLocalizedString("page-title", IDS_METRO_FLOW_TAB_TITLE);
71   data_source->AddLocalizedString("flowTitle", IDS_METRO_FLOW_TITLE_SHORT);
72   data_source->AddLocalizedString("flowDescription",
73                                   IDS_METRO_FLOW_DESCRIPTION);
74   data_source->AddLocalizedString("flowNext",
75                                   IDS_METRO_FLOW_SET_DEFAULT);
76   data_source->AddLocalizedString("chromeLogoString",
77                                   IDS_METRO_FLOW_LOGO_STRING_ALT);
78   data_source->SetJsonPath("strings.js");
79   data_source->AddResourcePath("set_as_default_browser.js",
80       IDR_SET_AS_DEFAULT_BROWSER_JS);
81   data_source->SetDefaultResource(IDR_SET_AS_DEFAULT_BROWSER_HTML);
82   return data_source;
83 }
84
85 // A simple class serving as a delegate for passing down the result of the
86 // interaction.
87 class ResponseDelegate {
88  public:
89   virtual void SetDialogInteractionResult(MakeChromeDefaultResult result) = 0;
90
91  protected:
92   virtual ~ResponseDelegate() { }
93 };
94
95 // Event handler for SetAsDefaultBrowserUI. Capable of setting Chrome as the
96 // default browser on button click, closing itself and triggering Chrome
97 // restart.
98 class SetAsDefaultBrowserHandler
99     : public WebUIMessageHandler,
100       public base::SupportsWeakPtr<SetAsDefaultBrowserHandler>,
101       public ShellIntegration::DefaultWebClientObserver {
102  public:
103   explicit SetAsDefaultBrowserHandler(
104       const base::WeakPtr<ResponseDelegate>& response_delegate);
105   virtual ~SetAsDefaultBrowserHandler();
106
107   // WebUIMessageHandler implementation.
108   virtual void RegisterMessages() OVERRIDE;
109
110   // ShellIntegration::DefaultWebClientObserver implementation.
111   virtual void SetDefaultWebClientUIState(
112       ShellIntegration::DefaultWebClientUIState state) OVERRIDE;
113   virtual void OnSetAsDefaultConcluded(bool close_chrome)  OVERRIDE;
114   virtual bool IsInteractiveSetDefaultPermitted() OVERRIDE;
115
116  private:
117   // Handler for the 'Next' (or 'make Chrome the Metro browser') button.
118   void HandleLaunchSetDefaultBrowserFlow(const base::ListValue* args);
119
120   // Close this web ui.
121   void ConcludeInteraction(MakeChromeDefaultResult interaction_result);
122
123   // Returns true if Chrome should be restarted in immersive mode upon being
124   // made the default browser.
125   bool ShouldAttemptImmersiveRestart();
126
127   scoped_refptr<ShellIntegration::DefaultBrowserWorker> default_browser_worker_;
128   bool set_default_returned_;
129   bool set_default_result_;
130   base::WeakPtr<ResponseDelegate> response_delegate_;
131
132   DISALLOW_COPY_AND_ASSIGN(SetAsDefaultBrowserHandler);
133 };
134
135 SetAsDefaultBrowserHandler::SetAsDefaultBrowserHandler(
136     const base::WeakPtr<ResponseDelegate>& response_delegate)
137     : default_browser_worker_(new ShellIntegration::DefaultBrowserWorker(this)),
138       set_default_returned_(false), set_default_result_(false),
139       response_delegate_(response_delegate) {
140 }
141
142 SetAsDefaultBrowserHandler::~SetAsDefaultBrowserHandler() {
143   default_browser_worker_->ObserverDestroyed();
144 }
145
146 void SetAsDefaultBrowserHandler::RegisterMessages() {
147   web_ui()->RegisterMessageCallback(
148       "SetAsDefaultBrowser:LaunchSetDefaultBrowserFlow",
149       base::Bind(&SetAsDefaultBrowserHandler::HandleLaunchSetDefaultBrowserFlow,
150                  base::Unretained(this)));
151 }
152
153 void SetAsDefaultBrowserHandler::SetDefaultWebClientUIState(
154     ShellIntegration::DefaultWebClientUIState state) {
155   // The callback is expected to be invoked once the procedure has completed.
156   DCHECK_CURRENTLY_ON(BrowserThread::UI);
157   if (!set_default_returned_)
158     return;
159
160   if (state == ShellIntegration::STATE_NOT_DEFAULT && set_default_result_) {
161     // The operation concluded, but Chrome is still not the default.
162     // If the call has succeeded, this suggests user has decided not to make
163     // chrome the default.
164     ConcludeInteraction(MAKE_CHROME_DEFAULT_REGRETTED);
165   } else if (state == ShellIntegration::STATE_IS_DEFAULT) {
166     ConcludeInteraction(ShouldAttemptImmersiveRestart() ?
167         MAKE_CHROME_DEFAULT_ACCEPTED_IMMERSE : MAKE_CHROME_DEFAULT_ACCEPTED);
168   }
169
170   // Otherwise, keep the dialog open since the user probably didn't make a
171   // choice.
172 }
173
174 void SetAsDefaultBrowserHandler::OnSetAsDefaultConcluded(bool call_result) {
175   set_default_returned_ = true;
176   set_default_result_ = call_result;
177 }
178
179 bool SetAsDefaultBrowserHandler::IsInteractiveSetDefaultPermitted() {
180   return true;
181 }
182
183 void SetAsDefaultBrowserHandler::HandleLaunchSetDefaultBrowserFlow(
184     const base::ListValue* args) {
185   set_default_returned_ = false;
186   set_default_result_ = false;
187   default_browser_worker_->StartSetAsDefault();
188 }
189
190 void SetAsDefaultBrowserHandler::ConcludeInteraction(
191     MakeChromeDefaultResult interaction_result) {
192   DCHECK_CURRENTLY_ON(BrowserThread::UI);
193
194   if (response_delegate_)
195     response_delegate_->SetDialogInteractionResult(interaction_result);
196
197   WebContents* contents = web_ui()->GetWebContents();
198
199   if (contents) {
200     content::WebContentsDelegate* delegate = contents->GetDelegate();
201     if (delegate)
202       delegate->CloseContents(contents);
203   }
204 }
205
206 bool SetAsDefaultBrowserHandler::ShouldAttemptImmersiveRestart() {
207   return (base::win::IsTouchEnabledDevice() &&
208           !Profile::FromWebUI(web_ui())->GetPrefs()->GetBoolean(
209               prefs::kSuppressSwitchToMetroModeOnSetDefault));
210 }
211
212 // A web dialog delegate implementation for when 'Make Chrome Metro' UI
213 // is displayed on a dialog.
214 class SetAsDefaultBrowserDialogImpl : public ui::WebDialogDelegate,
215                                       public ResponseDelegate,
216                                       public chrome::BrowserListObserver {
217  public:
218   SetAsDefaultBrowserDialogImpl(Profile* profile, Browser* browser);
219   virtual ~SetAsDefaultBrowserDialogImpl();
220   // Show a modal web dialog with kChromeUIMetroFlowURL page.
221   void ShowDialog();
222
223  protected:
224   // Overridden from WebDialogDelegate:
225   virtual ui::ModalType GetDialogModalType() const OVERRIDE;
226   virtual base::string16 GetDialogTitle() const OVERRIDE;
227   virtual GURL GetDialogContentURL() const OVERRIDE;
228   virtual void GetWebUIMessageHandlers(
229       std::vector<WebUIMessageHandler*>* handlers) const OVERRIDE;
230   virtual void GetDialogSize(gfx::Size* size) const OVERRIDE;
231   virtual std::string GetDialogArgs() const OVERRIDE;
232   virtual void OnDialogClosed(const std::string& json_retval) OVERRIDE;
233   virtual void OnCloseContents(WebContents* source,
234                                bool* out_close_dialog) OVERRIDE;
235   virtual bool ShouldShowDialogTitle() const OVERRIDE;
236   virtual bool HandleContextMenu(
237       const content::ContextMenuParams& params) OVERRIDE;
238
239   // Overridden from ResponseDelegate:
240   virtual void SetDialogInteractionResult(MakeChromeDefaultResult result);
241
242   // Overridden from BrowserListObserver:
243   virtual void OnBrowserRemoved(Browser* browser) OVERRIDE;
244
245  private:
246   // Reset the first-run sentinel file, so must be called on the FILE thread.
247   // This is needed if the browser should be restarted in immersive mode.
248   // The method is static because the dialog could be destroyed
249   // before the task arrives on the FILE thread.
250   static void AttemptImmersiveFirstRunRestartOnFileThread();
251
252   Profile* profile_;
253   Browser* browser_;
254   mutable bool owns_handler_;
255   base::WeakPtrFactory<ResponseDelegate> response_delegate_ptr_factory_;
256   SetAsDefaultBrowserHandler* handler_;
257   MakeChromeDefaultResult dialog_interaction_result_;
258
259   DISALLOW_COPY_AND_ASSIGN(SetAsDefaultBrowserDialogImpl);
260 };
261
262 SetAsDefaultBrowserDialogImpl::SetAsDefaultBrowserDialogImpl(Profile* profile,
263                                                              Browser* browser)
264     : profile_(profile),
265       browser_(browser),
266       owns_handler_(true),
267       response_delegate_ptr_factory_(this),
268       handler_(new SetAsDefaultBrowserHandler(
269           response_delegate_ptr_factory_.GetWeakPtr())),
270       dialog_interaction_result_(MAKE_CHROME_DEFAULT_DECLINED) {
271   BrowserList::AddObserver(this);
272 }
273
274 SetAsDefaultBrowserDialogImpl::~SetAsDefaultBrowserDialogImpl() {
275   if (browser_)
276     BrowserList::RemoveObserver(this);
277   if (owns_handler_)
278     delete handler_;
279 }
280
281 void SetAsDefaultBrowserDialogImpl::ShowDialog() {
282   // Use a NULL parent window to make sure that the dialog will have an item
283   // in the Windows task bar. The code below will make it highlight if the
284   // dialog is not in the foreground.
285   gfx::NativeWindow native_window = chrome::ShowWebDialog(NULL, profile_, this);
286   views::Widget* widget = views::Widget::GetWidgetForNativeWindow(
287       native_window);
288   widget->FlashFrame(true);
289 }
290
291 ui::ModalType SetAsDefaultBrowserDialogImpl::GetDialogModalType() const {
292   return ui::MODAL_TYPE_SYSTEM;
293 }
294
295 base::string16 SetAsDefaultBrowserDialogImpl::GetDialogTitle() const {
296   return l10n_util::GetStringUTF16(IDS_METRO_FLOW_TAB_TITLE);
297 }
298
299 GURL SetAsDefaultBrowserDialogImpl::GetDialogContentURL() const {
300   std::string url_string(chrome::kChromeUIMetroFlowURL);
301   return GURL(url_string);
302 }
303
304 void SetAsDefaultBrowserDialogImpl::GetWebUIMessageHandlers(
305     std::vector<WebUIMessageHandler*>* handlers) const {
306   handlers->push_back(handler_);
307   owns_handler_ = false;
308 }
309
310 void SetAsDefaultBrowserDialogImpl::GetDialogSize(gfx::Size* size) const {
311   PrefService* prefs = profile_->GetPrefs();
312   gfx::Font approximate_web_font(
313       prefs->GetString(prefs::kWebKitSansSerifFontFamily),
314       prefs->GetInteger(prefs::kWebKitDefaultFontSize));
315
316   *size = ui::GetLocalizedContentsSizeForFont(
317       IDS_METRO_FLOW_WIDTH_CHARS, IDS_METRO_FLOW_HEIGHT_LINES,
318       approximate_web_font);
319 }
320
321 std::string SetAsDefaultBrowserDialogImpl::GetDialogArgs() const {
322   return "[]";
323 }
324
325 void SetAsDefaultBrowserDialogImpl::OnDialogClosed(
326     const std::string& json_retval) {
327   // Register the user's response in UMA.
328   UMA_HISTOGRAM_ENUMERATION(kSetAsDefaultBrowserHistogram,
329                             dialog_interaction_result_,
330                             MAKE_CHROME_DEFAULT_MAX);
331
332   if (dialog_interaction_result_ == MAKE_CHROME_DEFAULT_ACCEPTED_IMMERSE) {
333     BrowserThread::PostTask(
334         BrowserThread::FILE, FROM_HERE,
335         base::Bind(&SetAsDefaultBrowserDialogImpl::
336             AttemptImmersiveFirstRunRestartOnFileThread));
337   } else {
338     // If the user explicitly elected *not to* make Chrome default, we won't
339     // ask again.
340     if (dialog_interaction_result_ == MAKE_CHROME_DEFAULT_REGRETTED) {
341       PrefService* prefs = profile_->GetPrefs();
342       prefs->SetBoolean(prefs::kCheckDefaultBrowser, false);
343     }
344
345     // Carry on with a normal chrome session. For the purpose of surfacing this
346     // dialog the actual browser window had to remain hidden. Now it's time to
347     // show it.
348     if (browser_) {
349       BrowserWindow* window = browser_->window();
350       WebContents* contents =
351           browser_->tab_strip_model()->GetActiveWebContents();
352       window->Show();
353       if (contents)
354         contents->SetInitialFocus();
355     }
356   }
357
358   delete this;
359 }
360
361 void SetAsDefaultBrowserDialogImpl::OnCloseContents(WebContents* source,
362                                                     bool* out_close_dialog) {
363   *out_close_dialog = true;
364 }
365
366 bool SetAsDefaultBrowserDialogImpl::ShouldShowDialogTitle() const {
367   return true;
368 }
369
370 bool SetAsDefaultBrowserDialogImpl::HandleContextMenu(
371     const content::ContextMenuParams& params) {
372   return true;
373 }
374
375 void SetAsDefaultBrowserDialogImpl::SetDialogInteractionResult(
376     MakeChromeDefaultResult result) {
377   dialog_interaction_result_ = result;
378 }
379
380 void SetAsDefaultBrowserDialogImpl::OnBrowserRemoved(Browser* browser) {
381   if (browser_ == browser) {
382     browser_ = NULL;
383     BrowserList::RemoveObserver(this);
384   }
385 }
386
387 void SetAsDefaultBrowserDialogImpl::
388     AttemptImmersiveFirstRunRestartOnFileThread() {
389   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
390
391   // If the sentinel was created for this launch, remove it before restarting
392   // in immersive mode so that the user is taken through the full first-run
393   // flow there.
394   if (first_run::IsChromeFirstRun())
395     first_run::RemoveSentinel();
396
397   // Do a straight-up restart rather than a mode-switch restart.
398   // delegate_execute.exe will choose an immersive launch on the basis of the
399   // same IsTouchEnabledDevice check, but will not store this as the user's
400   // choice.
401   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
402                           base::Bind(&chrome::AttemptRestart));
403 }
404
405 }  // namespace
406
407 SetAsDefaultBrowserUI::SetAsDefaultBrowserUI(content::WebUI* web_ui)
408     : ui::WebDialogUI(web_ui) {
409   content::WebUIDataSource::Add(
410       Profile::FromWebUI(web_ui), CreateSetAsDefaultBrowserUIHTMLSource());
411 }
412
413 // static
414 void SetAsDefaultBrowserUI::Show(Profile* profile, Browser* browser) {
415   DCHECK_CURRENTLY_ON(BrowserThread::UI);
416   SetAsDefaultBrowserDialogImpl* dialog =
417       new SetAsDefaultBrowserDialogImpl(profile, browser);
418   dialog->ShowDialog();
419 }