15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved.
25c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Use of this source code is governed by a BSD-style license that can be
35c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// found in the LICENSE file.
45c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
55c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/ui/cocoa/apps/quit_with_apps_controller_mac.h"
65c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/command_line.h"
85c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/i18n/number_formatting.h"
95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/prefs/pref_registry_simple.h"
105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/prefs/pref_service.h"
115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/strings/sys_string_conversions.h"
125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/strings/utf_string_conversions.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/apps/app_window_registry_util.h"
145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/browser_process.h"
155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/notifications/notification.h"
165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/notifications/notification_ui_manager.h"
175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/profiles/profile_manager.h"
185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/ui/browser_iterator.h"
195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/common/chrome_switches.h"
205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/common/pref_names.h"
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/grit/chromium_strings.h"
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/grit/generated_resources.h"
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/grit/google_chrome_strings.h"
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/app_window/app_window.h"
2503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "extensions/browser/app_window/native_app_window.h"
265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "extensions/common/extension.h"
2746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "grit/chrome_unscaled_resources.h"
285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/base/l10n/l10n_util.h"
295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/base/l10n/l10n_util_mac.h"
305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/base/resource/resource_bundle.h"
315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst char kQuitWithAppsOriginUrl[] = "chrome://quit-with-apps";
335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst int kQuitAllAppsButtonIndex = 0;
345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst int kDontShowAgainButtonIndex = 1;
355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst char QuitWithAppsController::kQuitWithAppsNotificationID[] =
375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    "quit-with-apps";
385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuQuitWithAppsController::QuitWithAppsController()
405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    : suppress_for_session_(false) {
415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // There is only ever one notification to replace, so use the same replace_id
445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // each time.
455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::string16 replace_id = base::UTF8ToUTF16(id());
465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  message_center::ButtonInfo quit_apps_button_info(
485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      l10n_util::GetStringUTF16(IDS_QUIT_WITH_APPS_QUIT_LABEL));
495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  message_center::ButtonInfo suppression_button_info(
505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      l10n_util::GetStringUTF16(IDS_QUIT_WITH_APPS_SUPPRESSION_LABEL));
515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  message_center::RichNotificationData rich_notification_data;
525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  rich_notification_data.buttons.push_back(quit_apps_button_info);
535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  rich_notification_data.buttons.push_back(suppression_button_info);
545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  notification_.reset(new Notification(
565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      message_center::NOTIFICATION_TYPE_SIMPLE,
575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      GURL(kQuitWithAppsOriginUrl),
585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      l10n_util::GetStringUTF16(IDS_QUIT_WITH_APPS_TITLE),
595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      l10n_util::GetStringUTF16(IDS_QUIT_WITH_APPS_EXPLANATION),
605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      ui::ResourceBundle::GetSharedInstance().GetImageNamed(
6146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          IDR_PRODUCT_LOGO_128),
625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      blink::WebTextDirectionDefault,
635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                 kQuitWithAppsNotificationID),
655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      l10n_util::GetStringUTF16(IDS_QUIT_WITH_APPS_NOTIFICATION_DISPLAY_SOURCE),
665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      replace_id,
675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      rich_notification_data,
685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      this));
695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuQuitWithAppsController::~QuitWithAppsController() {}
725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid QuitWithAppsController::Display() {}
745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid QuitWithAppsController::Error() {}
765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid QuitWithAppsController::Close(bool by_user) {
785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (by_user)
795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    suppress_for_session_ = true;
805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid QuitWithAppsController::Click() {
835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  g_browser_process->notification_ui_manager()->CancelById(id());
845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid QuitWithAppsController::ButtonClick(int button_index) {
875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  g_browser_process->notification_ui_manager()->CancelById(id());
885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (button_index == kQuitAllAppsButtonIndex) {
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    AppWindowRegistryUtil::CloseAllAppWindows();
905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  } else if (button_index == kDontShowAgainButtonIndex) {
915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    g_browser_process->local_state()->SetBoolean(
925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        prefs::kNotifyWhenAppsKeepChromeAlive, false);
935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liucontent::WebContents* QuitWithAppsController::GetWebContents() const {
975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return NULL;
985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liustd::string QuitWithAppsController::id() const {
1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return kQuitWithAppsNotificationID;
1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool QuitWithAppsController::ShouldQuit() {
1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Quit immediately if this is a test.
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType) &&
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      !CommandLine::ForCurrentProcess()->HasSwitch(
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          switches::kAppsKeepChromeAliveInTests)) {
1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return true;
1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Quit immediately if there are no windows or the confirmation has been
1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // suppressed.
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!AppWindowRegistryUtil::IsAppWindowRegisteredInAnyProfile(0))
1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return true;
1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // If there are browser windows, and this notification has been suppressed for
1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // this session or permanently, then just return false to prevent Chrome from
1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // quitting. If there are no browser windows, always show the notification.
1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  bool suppress_always = !g_browser_process->local_state()->GetBoolean(
1235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      prefs::kNotifyWhenAppsKeepChromeAlive);
1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!chrome::BrowserIterator().done() &&
1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      (suppress_for_session_ || suppress_always)) {
1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return false;
1275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ProfileManager* profile_manager = g_browser_process->profile_manager();
1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(profile_manager);
1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(profiles.size());
1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Delete any existing notification to ensure this one is shown.
1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  g_browser_process->notification_ui_manager()->CancelById(id());
1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  g_browser_process->notification_ui_manager()->Add(*notification_,
1385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                                    profiles[0]);
1395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Always return false, the notification UI can be used to quit all apps which
1415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // will cause Chrome to quit.
1425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return false;
1435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static
1465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid QuitWithAppsController::RegisterPrefs(PrefRegistrySimple* registry) {
1475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  registry->RegisterBooleanPref(prefs::kNotifyWhenAppsKeepChromeAlive, true);
1485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
149