Upstream version 10.38.208.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / app_controller_mac.mm
index 87b473e..6c5f2bb 100644 (file)
@@ -4,7 +4,6 @@
 
 #import "chrome/browser/app_controller_mac.h"
 
-#include "apps/app_shim/app_shim_mac.h"
 #include "apps/app_shim/extension_app_shim_handler_mac.h"
 #include "apps/app_window_registry.h"
 #include "base/auto_reset.h"
@@ -13,6 +12,7 @@
 #include "base/files/file_path.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/mac_util.h"
+#include "base/mac/sdk_forward_declarations.h"
 #include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
@@ -30,6 +30,7 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/first_run/first_run.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/mac/mac_startup_profiler.h"
 #include "chrome/browser/profiles/profile_info_cache_observer.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profiles_state.h"
@@ -38,7 +39,6 @@
 #include "chrome/browser/sessions/session_service_factory.h"
 #include "chrome/browser/sessions/tab_restore_service.h"
 #include "chrome/browser/sessions/tab_restore_service_factory.h"
-#include "chrome/browser/signin/signin_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/signin/signin_promo.h"
 #include "chrome/browser/sync/profile_sync_service.h"
@@ -53,6 +53,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #import "chrome/browser/ui/cocoa/apps/app_shim_menu_controller_mac.h"
+#include "chrome/browser/ui/cocoa/apps/quit_with_apps_controller_mac.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
 #import "chrome/browser/ui/cocoa/browser_window_cocoa.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
@@ -61,7 +62,7 @@
 #import "chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.h"
 #import "chrome/browser/ui/cocoa/history_menu_bridge.h"
 #include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h"
-#import "chrome/browser/ui/cocoa/profile_menu_controller.h"
+#import "chrome/browser/ui/cocoa/profiles/profile_menu_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_window_controller.h"
 #include "chrome/browser/ui/cocoa/task_manager_mac.h"
@@ -75,8 +76,9 @@
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/mac/app_mode_common.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/common/profile_management_switches.h"
 #include "chrome/common/url_constants.h"
+#include "components/signin/core/common/profile_management_switches.h"
+#include "components/signin/core/browser/signin_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/download_manager.h"
 #include "content/public/browser/notification_service.h"
@@ -86,7 +88,7 @@
 #include "extensions/browser/extension_system.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
-#include "net/base/net_util.h"
+#include "net/base/filename_util.h"
 #include "ui/base/cocoa/focus_window_set.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
@@ -121,7 +123,8 @@ bool g_is_opening_new_window = false;
 // not possible. If the last active browser is minimized (in particular, if
 // there are only minimized windows), it will unminimize it.
 Browser* ActivateBrowser(Profile* profile) {
-  Browser* browser = chrome::FindLastActiveWithProfile(profile,
+  Browser* browser = chrome::FindLastActiveWithProfile(
+      profile->IsGuestSession() ? profile->GetOffTheRecordProfile() : profile,
       chrome::HOST_DESKTOP_TYPE_NATIVE);
   if (browser)
     browser->window()->Activate();
@@ -207,6 +210,7 @@ bool IsProfileSignedOut(Profile* profile) {
 - (void)initMenuState;
 - (void)initProfileMenu;
 - (void)updateConfirmToQuitPrefMenuItem:(NSMenuItem*)item;
+- (void)updateDisplayMessageCenterPrefMenuItem:(NSMenuItem*)item;
 - (void)registerServicesMenuTypesTo:(NSApplication*)app;
 - (void)openUrls:(const std::vector<GURL>&)urls;
 - (void)getUrl:(NSAppleEventDescriptor*)event
@@ -279,6 +283,8 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
 // the profile is loaded or any preferences have been registered). Defer any
 // user-data initialization until -applicationDidFinishLaunching:.
 - (void)awakeFromNib {
+  MacStartupProfiler::GetInstance()->Profile(
+      MacStartupProfiler::AWAKE_FROM_NIB);
   // We need to register the handlers early to catch events fired on launch.
   NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager];
   [em setEventHandler:self
@@ -358,7 +364,12 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
 // (NSApplicationDelegate protocol) This is the Apple-approved place to override
 // the default handlers.
 - (void)applicationWillFinishLaunching:(NSNotification*)notification {
-  // Nothing here right now.
+  MacStartupProfiler::GetInstance()->Profile(
+      MacStartupProfiler::WILL_FINISH_LAUNCHING);
+}
+
+- (void)applicationWillHide:(NSNotification*)notification {
+  apps::ExtensionAppShimHandler::OnChromeWillHide();
 }
 
 - (BOOL)tryToTerminateApplication:(NSApplication*)app {
@@ -380,6 +391,19 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
       [self applicationShouldTerminate:app] != NSTerminateNow)
     return NO;
 
+  // Check for active apps. If quitting is prevented, only close browsers and
+  // sessions.
+  if (!browser_shutdown::IsTryingToQuit() &&
+      quitWithAppsController_ && !quitWithAppsController_->ShouldQuit()) {
+    content::NotificationService::current()->Notify(
+        chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
+        content::NotificationService::AllSources(),
+        content::NotificationService::NoDetails());
+    // This will close all browser sessions.
+    chrome::CloseAllBrowsers();
+    return NO;
+  }
+
   size_t num_browsers = chrome::GetTotalBrowserCount();
 
   // Initiate a shutdown (via chrome::CloseAllBrowsersAndQuit()) if we aren't
@@ -599,7 +623,7 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
     browserWindows.insert(browser->window()->GetNativeWindow());
   }
   if (!browserWindows.empty()) {
-    ui::FocusWindowSet(browserWindows, false);
+    ui::FocusWindowSetOnCurrentSpace(browserWindows);
   }
 }
 
@@ -681,9 +705,48 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
 #endif
 }
 
+- (void)openStartupUrls {
+  // On Mac, the URLs are passed in via Cocoa, not command line. The Chrome
+  // NSApplication is created in MainMessageLoop, and then the shortcut urls
+  // are passed in via Apple events. At this point, the first browser is
+  // already loaded in PreMainMessageLoop. If we initialize NSApplication
+  // before PreMainMessageLoop to capture shortcut URL events, it may cause
+  // more problems because it relies on things created in PreMainMessageLoop
+  // and may break existing message loop design.
+  if (startupUrls_.empty())
+    return;
+
+  // If there's only 1 tab and the tab is NTP, close this NTP tab and open all
+  // startup urls in new tabs, because the omnibox will stay focused if we
+  // load url in NTP tab.
+  Browser* browser = chrome::GetLastActiveBrowser();
+  int startupIndex = TabStripModel::kNoTab;
+  content::WebContents* startupContent = NULL;
+
+  if (browser && browser->tab_strip_model()->count() == 1) {
+    startupIndex = browser->tab_strip_model()->active_index();
+    startupContent = browser->tab_strip_model()->GetActiveWebContents();
+  }
+
+  if (startupUrls_.size()) {
+    [self openUrls:startupUrls_];
+    startupUrls_.clear();
+  }
+
+  if (startupIndex != TabStripModel::kNoTab &&
+      startupContent->GetVisibleURL() == GURL(chrome::kChromeUINewTabURL)) {
+    browser->tab_strip_model()->CloseWebContentsAt(startupIndex,
+        TabStripModel::CLOSE_NONE);
+  }
+}
+
 // This is called after profiles have been loaded and preferences registered.
 // It is safe to access the default profile here.
 - (void)applicationDidFinishLaunching:(NSNotification*)notify {
+  MacStartupProfiler::GetInstance()->Profile(
+      MacStartupProfiler::DID_FINISH_LAUNCHING);
+  MacStartupProfiler::GetInstance()->RecordMetrics();
+
   // Notify BrowserList to keep the application running so it doesn't go away
   // when all the browser windows get closed.
   chrome::IncrementKeepAliveCount();
@@ -694,6 +757,10 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
   // main menu item titles are not yet initialized in awakeFromNib.
   [self initAppShimMenuController];
 
+  // If enabled, keep Chrome alive when apps are open instead of quitting all
+  // apps.
+  quitWithAppsController_ = new QuitWithAppsController();
+
   // Build up the encoding menu, the order of the items differs based on the
   // current locale (see http://crbug.com/7647 for details).
   // We need a valid g_browser_process to get the profile which is why we can't
@@ -725,13 +792,7 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
 
   startupComplete_ = YES;
 
-  // TODO(viettrungluu): This is very temporary, since this should be done "in"
-  // |BrowserMain()|, i.e., this list of startup URLs should be appended to the
-  // (probably-empty) list of URLs from the command line.
-  if (startupUrls_.size()) {
-    [self openUrls:startupUrls_];
-    [self clearStartupUrls];
-  }
+  [self openStartupUrls];
 
   PrefService* localState = g_browser_process->local_state();
   if (localState) {
@@ -943,6 +1004,10 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
   } else if (action == @selector(toggleConfirmToQuit:)) {
     [self updateConfirmToQuitPrefMenuItem:static_cast<NSMenuItem*>(item)];
     enable = YES;
+  } else if (action == @selector(toggleDisplayMessageCenter:)) {
+    NSMenuItem* menuItem = static_cast<NSMenuItem*>(item);
+    [self updateDisplayMessageCenterPrefMenuItem:menuItem];
+    enable = YES;
   } else if (action == @selector(executeApplication:)) {
     enable = YES;
   }
@@ -955,7 +1020,7 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
 // check, otherwise it should have been disabled in the UI in
 // |-validateUserInterfaceItem:|.
 - (void)commandDispatch:(id)sender {
-  Profile* lastProfile = [self lastProfile];
+  Profile* lastProfile = [self safeLastProfileForNewWindows];
 
   // Handle the case where we're dispatching a command from a sender that's in a
   // browser window. This means that the command came from a background window
@@ -1149,7 +1214,7 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
         // See http://crbug.com/309656.
         reopenTime_ = base::TimeTicks::Now();
       } else {
-        ui::FocusWindowSet(browserWindows, false);
+        ui::FocusWindowSetOnCurrentSpace(browserWindows);
       }
       // Return NO; we've done (or soon will do) the deminiaturize, so
       // AppKit shouldn't do anything.
@@ -1163,37 +1228,17 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
   // Normally, it'd just open a new empty page.
   {
     static BOOL doneOnce = NO;
-    if (!doneOnce) {
-      doneOnce = YES;
-      if (base::mac::WasLaunchedAsHiddenLoginItem()) {
-        SessionService* sessionService =
-            SessionServiceFactory::GetForProfileForSessionRestore(
-                [self lastProfile]);
-        if (sessionService &&
-            sessionService->RestoreIfNecessary(std::vector<GURL>()))
-          return NO;
-      }
-    }
-  }
-
-  // Platform apps don't use browser windows so don't do anything if there are
-  // visible windows, otherwise, launch the browser with the same command line
-  // which should launch the app again.
-  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kAppId)) {
-    if (hasVisibleWindows)
-      return YES;
-
-    {
-      base::AutoReset<bool> auto_reset_in_run(&g_is_opening_new_window, true);
-      int return_code;
-      StartupBrowserCreator browser_creator;
-      browser_creator.LaunchBrowser(
-          command_line, [self lastProfile], base::FilePath(),
-          chrome::startup::IS_NOT_PROCESS_STARTUP,
-          chrome::startup::IS_NOT_FIRST_RUN, &return_code);
+    BOOL attemptRestore = apps::AppShimHandler::ShouldRestoreSession() ||
+        (!doneOnce && base::mac::WasLaunchedAsHiddenLoginItem());
+    doneOnce = YES;
+    if (attemptRestore) {
+      SessionService* sessionService =
+          SessionServiceFactory::GetForProfileForSessionRestore(
+              [self lastProfile]);
+      if (sessionService &&
+          sessionService->RestoreIfNecessary(std::vector<GURL>()))
+        return NO;
     }
-    return NO;
   }
 
   // Otherwise open a new window.
@@ -1267,6 +1312,14 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
   [item setState:enabled ? NSOnState : NSOffState];
 }
 
+- (void)updateDisplayMessageCenterPrefMenuItem:(NSMenuItem*)item {
+  const PrefService* prefService = g_browser_process->local_state();
+  bool enabled = prefService->GetBoolean(prefs::kMessageCenterShowIcon);
+  // The item should be checked if "show icon" is false, since the text reads
+  // "Hide notification center icon."
+  [item setState:enabled ? NSOffState : NSOnState];
+}
+
 - (void)registerServicesMenuTypesTo:(NSApplication*)app {
   // Note that RenderWidgetHostViewCocoa implements NSServicesRequests which
   // handles requests from services.
@@ -1290,6 +1343,16 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
       *CommandLine::ForCurrentProcess()));
 }
 
+- (Profile*)safeLastProfileForNewWindows {
+  Profile* profile = [self lastProfile];
+
+  // Guest sessions must always be OffTheRecord. Use that when opening windows.
+  if (profile->IsGuestSession())
+    return profile->GetOffTheRecordProfile();
+
+  return profile;
+}
+
 // Various methods to open URLs that we get in a native fashion. We use
 // StartupBrowserCreator here because on the other platforms, URLs to open come
 // through the ProcessSingleton, and it calls StartupBrowserCreator. It's best
@@ -1353,7 +1416,7 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
     chrome::ShowSettings(browser);
   } else {
     // No browser window, so create one for the options tab.
-    chrome::OpenOptionsWindow([self lastProfile]);
+    chrome::OpenOptionsWindow([self safeLastProfileForNewWindows]);
   }
 }
 
@@ -1362,7 +1425,7 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
     chrome::ShowAboutChrome(browser);
   } else {
     // No browser window, so create one for the about tab.
-    chrome::OpenAboutWindow([self lastProfile]);
+    chrome::OpenAboutWindow([self safeLastProfileForNewWindows]);
   }
 }
 
@@ -1372,6 +1435,12 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
   prefService->SetBoolean(prefs::kConfirmToQuitEnabled, !enabled);
 }
 
+- (IBAction)toggleDisplayMessageCenter:(id)sender {
+  PrefService* prefService = g_browser_process->local_state();
+  bool enabled = prefService->GetBoolean(prefs::kMessageCenterShowIcon);
+  prefService->SetBoolean(prefs::kMessageCenterShowIcon, !enabled);
+}
+
 // Explicitly bring to the foreground when creating new windows from the dock.
 - (void)commandFromDock:(id)sender {
   [NSApp activateIgnoringOtherApps:YES];
@@ -1399,7 +1468,7 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
   [dockMenu addItem:item];
 
   // |profile| can be NULL during unit tests.
-  if (!profile || !profile->IsManaged()) {
+  if (!profile || !profile->IsSupervised()) {
     titleStr = l10n_util::GetNSStringWithFixup(IDS_NEW_INCOGNITO_WINDOW_MAC);
     item.reset(
         [[NSMenuItem alloc] initWithTitle:titleStr
@@ -1448,10 +1517,6 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
   return startupUrls_;
 }
 
-- (void)clearStartupUrls {
-  startupUrls_.clear();
-}
-
 - (BookmarkMenuBridge*)bookmarkMenuBridge {
   return bookmarkMenuBridge_.get();
 }
@@ -1481,6 +1546,36 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
       WorkAreaChanged());
 }
 
+- (BOOL)application:(NSApplication*)application
+    willContinueUserActivityWithType:(NSString*)userActivityType {
+  return [userActivityType isEqualToString:NSUserActivityTypeBrowsingWeb];
+}
+
+- (BOOL)application:(NSApplication*)application
+    continueUserActivity:(NSUserActivity*)userActivity
+      restorationHandler:(void (^)(NSArray*))restorationHandler {
+  if (![userActivity.activityType
+          isEqualToString:NSUserActivityTypeBrowsingWeb]) {
+    return NO;
+  }
+
+  NSURL* url = userActivity.webPageURL;
+  if (!url)
+    return NO;
+
+  GURL gurl(base::SysNSStringToUTF8([url absoluteString]));
+  std::vector<GURL> gurlVector;
+  gurlVector.push_back(gurl);
+
+  [self openUrls:gurlVector];
+  return YES;
+}
+
+- (void)application:(NSApplication*)application
+    didFailToContinueUserActivityWithType:(NSString*)userActivityType
+                                    error:(NSError*)error {
+}
+
 @end  // @implementation AppController
 
 //---------------------------------------------------------------------------