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