Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / ash / launcher / chrome_launcher_controller.cc
index 73fac1f..86ef0d2 100644 (file)
 #include "base/command_line.h"
 #include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/extensions/app_icon_loader_impl.h"
-#include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/launch_util.h"
 #include "chrome/browser/favicon/favicon_tab_helper.h"
@@ -38,6 +38,8 @@
 #include "chrome/browser/ui/ash/app_sync_ui_state.h"
 #include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
 #include "chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h"
+#include "chrome/browser/ui/ash/launcher/app_window_launcher_controller.h"
+#include "chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h"
 #include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h"
 #include "chrome/browser/ui/ash/launcher/browser_status_monitor.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
@@ -46,8 +48,6 @@
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_types.h"
 #include "chrome/browser/ui/ash/launcher/launcher_app_tab_helper.h"
 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
-#include "chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h"
-#include "chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
-#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
+#include "chrome/grit/generated_resources.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
+#include "extensions/browser/extension_util.h"
+#include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_resource.h"
+#include "extensions/common/manifest_handlers/icons_handler.h"
 #include "extensions/common/url_pattern.h"
 #include "grit/ash_resources.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
-#include "grit/ui_resources.h"
 #include "net/base/url_util.h"
-#include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/views/corewm/window_animations.h"
+#include "ui/keyboard/keyboard_util.h"
+#include "ui/resources/grit/ui_resources.h"
+#include "ui/wm/core/window_animations.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/ui/ash/chrome_shell_delegate.h"
+#include "chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.h"
-#include "chrome/browser/ui/ash/launcher/multi_profile_shell_window_launcher_controller.h"
+#include "components/user_manager/user_manager.h"
 #endif
 
 using extensions::Extension;
@@ -194,6 +198,48 @@ std::string GetPrefForRootWindow(PrefService* pref_service,
   return default_string;
 }
 
+// Gets the shelf auto hide behavior from prefs for a root window.
+ash::ShelfAutoHideBehavior GetShelfAutoHideBehaviorFromPrefs(
+    Profile* profile,
+    aura::Window* root_window) {
+  // Don't show the shelf in app mode.
+  if (chrome::IsRunningInAppMode())
+    return ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN;
+
+  // See comment in |kShelfAlignment| as to why we consider two prefs.
+  const std::string behavior_value(
+      GetPrefForRootWindow(profile->GetPrefs(),
+                           root_window,
+                           prefs::kShelfAutoHideBehaviorLocal,
+                           prefs::kShelfAutoHideBehavior));
+
+  // Note: To maintain sync compatibility with old images of chrome/chromeos
+  // the set of values that may be encountered includes the now-extinct
+  // "Default" as well as "Never" and "Always", "Default" should now
+  // be treated as "Never" (http://crbug.com/146773).
+  if (behavior_value == ash::kShelfAutoHideBehaviorAlways)
+    return ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
+  return ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER;
+}
+
+// Gets the shelf alignment from prefs for a root window.
+ash::ShelfAlignment GetShelfAlignmentFromPrefs(Profile* profile,
+                                               aura::Window* root_window) {
+  // See comment in |kShelfAlignment| as to why we consider two prefs.
+  const std::string alignment_value(
+      GetPrefForRootWindow(profile->GetPrefs(),
+                           root_window,
+                           prefs::kShelfAlignmentLocal,
+                           prefs::kShelfAlignment));
+  if (alignment_value == ash::kShelfAlignmentLeft)
+    return ash::SHELF_ALIGNMENT_LEFT;
+  else if (alignment_value == ash::kShelfAlignmentRight)
+    return ash::SHELF_ALIGNMENT_RIGHT;
+  else if (alignment_value == ash::kShelfAlignmentTop)
+    return ash::SHELF_ALIGNMENT_TOP;
+  return ash::SHELF_ALIGNMENT_BOTTOM;
+}
+
 // If prefs have synced and no user-set value exists at |local_path|, the value
 // from |synced_path| is copied to |local_path|.
 void MaybePropagatePrefToLocal(PrefServiceSyncable* pref_service,
@@ -223,14 +269,14 @@ std::string GetSourceFromAppListSource(ash::LaunchSource source) {
 // A class to get events from ChromeOS when a user gets changed or added.
 class ChromeLauncherControllerUserSwitchObserverChromeOS
     : public ChromeLauncherControllerUserSwitchObserver,
-      public chromeos::UserManager::UserSessionStateObserver,
+      public user_manager::UserManager::UserSessionStateObserver,
       content::NotificationObserver {
  public:
   ChromeLauncherControllerUserSwitchObserverChromeOS(
       ChromeLauncherController* controller)
       : controller_(controller) {
-    DCHECK(chromeos::UserManager::IsInitialized());
-    chromeos::UserManager::Get()->AddSessionStateObserver(this);
+    DCHECK(user_manager::UserManager::IsInitialized());
+    user_manager::UserManager::Get()->AddSessionStateObserver(this);
     // A UserAddedToSession notification can be sent before a profile is loaded.
     // Since our observers require that we have already a profile, we might have
     // to postpone the notification until the ProfileManager lets us know that
@@ -239,16 +285,17 @@ class ChromeLauncherControllerUserSwitchObserverChromeOS
                    content::NotificationService::AllSources());
   }
   virtual ~ChromeLauncherControllerUserSwitchObserverChromeOS() {
-    chromeos::UserManager::Get()->RemoveSessionStateObserver(this);
+    user_manager::UserManager::Get()->RemoveSessionStateObserver(this);
   }
 
-  // chromeos::UserManager::UserSessionStateObserver overrides:
-  virtual void UserAddedToSession(const chromeos::User* added_user) OVERRIDE;
+  // user_manager::UserManager::UserSessionStateObserver overrides:
+  virtual void UserAddedToSession(
+      const user_manager::User* added_user) override;
 
   // content::NotificationObserver overrides:
   virtual void Observe(int type,
                const content::NotificationSource& source,
-               const content::NotificationDetails& details) OVERRIDE;
+               const content::NotificationDetails& details) override;
 
  private:
   // Add a user to the session.
@@ -269,7 +316,7 @@ class ChromeLauncherControllerUserSwitchObserverChromeOS
 };
 
 void ChromeLauncherControllerUserSwitchObserverChromeOS::UserAddedToSession(
-    const chromeos::User* active_user) {
+    const user_manager::User* active_user) {
   Profile* profile = multi_user_util::GetProfileFromUserID(
       active_user->email());
   // If we do not have a profile yet, we postpone forwarding the notification
@@ -355,19 +402,19 @@ ChromeLauncherController::ChromeLauncherController(Profile* profile,
     // If running in separated destkop mode, we create the multi profile version
     // of status monitor.
     browser_status_monitor_.reset(new MultiProfileBrowserStatusMonitor(this));
-    shell_window_controller_.reset(
-        new MultiProfileShellWindowLauncherController(this));
+    app_window_controller_.reset(
+        new MultiProfileAppWindowLauncherController(this));
   } else {
     // Create our v1/v2 application / browser monitors which will inform the
     // launcher of status changes.
     browser_status_monitor_.reset(new BrowserStatusMonitor(this));
-    shell_window_controller_.reset(new ShellWindowLauncherController(this));
+    app_window_controller_.reset(new AppWindowLauncherController(this));
   }
 #else
   // Create our v1/v2 application / browser monitors which will inform the
   // launcher of status changes.
   browser_status_monitor_.reset(new BrowserStatusMonitor(this));
-  shell_window_controller_.reset(new ShellWindowLauncherController(this));
+  app_window_controller_.reset(new AppWindowLauncherController(this));
 #endif
 
   // Right now ash::Shell isn't created for tests.
@@ -377,21 +424,14 @@ ChromeLauncherController::ChromeLauncherController(Profile* profile,
     item_delegate_manager_ =
         ash::Shell::GetInstance()->shelf_item_delegate_manager();
   }
-
-  notification_registrar_.Add(this,
-                              chrome::NOTIFICATION_EXTENSION_LOADED,
-                              content::Source<Profile>(profile_));
-  notification_registrar_.Add(this,
-                              chrome::NOTIFICATION_EXTENSION_UNLOADED,
-                              content::Source<Profile>(profile_));
 }
 
 ChromeLauncherController::~ChromeLauncherController() {
   // Reset the BrowserStatusMonitor as it has a weak pointer to this.
   browser_status_monitor_.reset();
 
-  // Reset the shell window controller here since it has a weak pointer to this.
-  shell_window_controller_.reset();
+  // Reset the app window controller here since it has a weak pointer to this.
+  app_window_controller_.reset();
 
   for (std::set<ash::Shelf*>::iterator iter = shelves_.begin();
        iter != shelves_.end();
@@ -442,6 +482,9 @@ void ChromeLauncherController::Init() {
   if (ash::Shell::HasInstance()) {
     SetShelfAutoHideBehaviorFromPrefs();
     SetShelfAlignmentFromPrefs();
+#if defined(OS_CHROMEOS)
+    SetVirtualKeyboardBehaviorFromPrefs();
+#endif  // defined(OS_CHROMEOS)
     PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_);
     if (!prefs->FindPreference(prefs::kShelfAlignmentLocal)->HasUserSetting() ||
         !prefs->FindPreference(prefs::kShelfAutoHideBehaviorLocal)->
@@ -576,6 +619,34 @@ bool ChromeLauncherController::IsPinnable(ash::ShelfID id) const {
           CanPin());
 }
 
+void ChromeLauncherController::Install(ash::ShelfID id) {
+  if (!HasItemController(id))
+    return;
+
+  std::string app_id = GetAppIDForShelfID(id);
+  if (extensions::util::IsExtensionInstalledPermanently(app_id, profile_))
+    return;
+
+  LauncherItemController* controller = id_to_item_controller_map_[id];
+  if (controller->type() == LauncherItemController::TYPE_APP) {
+    AppWindowLauncherItemController* app_window_controller =
+        static_cast<AppWindowLauncherItemController*>(controller);
+    app_window_controller->InstallApp();
+  }
+}
+
+bool ChromeLauncherController::CanInstall(ash::ShelfID id) {
+  int index = model_->ItemIndexByID(id);
+  if (index == -1)
+    return false;
+
+  ash::ShelfItemType type = model_->items()[index].type;
+  if (type != ash::TYPE_PLATFORM_APP)
+    return false;
+
+  return extensions::util::IsEphemeralApp(GetAppIDForShelfID(id), profile_);
+}
+
 void ChromeLauncherController::LockV1AppWithID(
     const std::string& app_id) {
   ash::ShelfID id = GetShelfIDForAppID(app_id);
@@ -647,8 +718,10 @@ void ChromeLauncherController::LaunchApp(const std::string& app_id,
     return;
   }
 
+#if defined(OS_WIN)
   if (LaunchedInNativeDesktop(app_id))
     return;
+#endif
 
   // The app will be created for the currently active profile.
   AppLaunchParams params(profile_,
@@ -656,7 +729,7 @@ void ChromeLauncherController::LaunchApp(const std::string& app_id,
                          event_flags,
                          chrome::HOST_DESKTOP_TYPE_ASH);
   if (source != ash::LAUNCH_FROM_UNKNOWN &&
-      app_id == extension_misc::kWebStoreAppId) {
+      app_id == extensions::kWebStoreAppId) {
     // Get the corresponding source string.
     std::string source_value = GetSourceFromAppListSource(source);
 
@@ -666,6 +739,10 @@ void ChromeLauncherController::LaunchApp(const std::string& app_id,
         extension_url, extension_urls::kWebstoreSourceField, source_value);
   }
 
+  params.source = (source == ash::LAUNCH_FROM_UNKNOWN)
+                      ? extensions::SOURCE_UNTRACKED
+                      : extensions::SOURCE_APP_LAUNCHER;
+
   OpenApplication(params);
 }
 
@@ -701,9 +778,8 @@ extensions::LaunchType ChromeLauncherController::GetLaunchType(
   if (!extension)
     return extensions::LAUNCH_TYPE_DEFAULT;
 
-  return extensions::GetLaunchType(
-      profile_->GetExtensionService()->extension_prefs(),
-      extension);
+  return extensions::GetLaunchType(extensions::ExtensionPrefs::Get(profile_),
+                                   extension);
 }
 
 ash::ShelfID ChromeLauncherController::GetShelfIDForAppID(
@@ -802,9 +878,10 @@ void ChromeLauncherController::SetLaunchType(
   if (!HasItemController(id))
     return;
 
-  extensions::SetLaunchType(profile_->GetExtensionService(),
-                            id_to_item_controller_map_[id]->app_id(),
-                            launch_type);
+  extensions::SetLaunchType(
+      extensions::ExtensionSystem::Get(profile_)->extension_service(),
+      id_to_item_controller_map_[id]->app_id(),
+      launch_type);
 }
 
 void ChromeLauncherController::UnpinAppWithID(const std::string& app_id) {
@@ -881,24 +958,7 @@ Profile* ChromeLauncherController::profile() {
 
 ash::ShelfAutoHideBehavior ChromeLauncherController::GetShelfAutoHideBehavior(
     aura::Window* root_window) const {
-  // Don't show the shelf in app mode.
-  if (chrome::IsRunningInAppMode())
-    return ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN;
-
-  // See comment in |kShelfAlignment| as to why we consider two prefs.
-  const std::string behavior_value(
-      GetPrefForRootWindow(profile_->GetPrefs(),
-                           root_window,
-                           prefs::kShelfAutoHideBehaviorLocal,
-                           prefs::kShelfAutoHideBehavior));
-
-  // Note: To maintain sync compatibility with old images of chrome/chromeos
-  // the set of values that may be encountered includes the now-extinct
-  // "Default" as well as "Never" and "Always", "Default" should now
-  // be treated as "Never" (http://crbug.com/146773).
-  if (behavior_value == ash::kShelfAutoHideBehaviorAlways)
-    return ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
-  return ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER;
+  return GetShelfAutoHideBehaviorFromPrefs(profile_, root_window);
 }
 
 bool ChromeLauncherController::CanUserModifyShelfAutoHideBehavior(
@@ -917,31 +977,6 @@ void ChromeLauncherController::ToggleShelfAutoHideBehavior(
   return;
 }
 
-void ChromeLauncherController::RemoveTabFromRunningApp(
-    WebContents* tab,
-    const std::string& app_id) {
-  web_contents_to_app_id_.erase(tab);
-  // BrowserShortcutLauncherItemController::UpdateBrowserItemState() will update
-  // the state when no application is associated with the tab.
-  if (app_id.empty())
-    return;
-
-  AppIDToWebContentsListMap::iterator i_app_id =
-      app_id_to_web_contents_list_.find(app_id);
-  if (i_app_id != app_id_to_web_contents_list_.end()) {
-    WebContentsList* tab_list = &i_app_id->second;
-    tab_list->remove(tab);
-    ash::ShelfItemStatus status = ash::STATUS_RUNNING;
-    if (tab_list->empty()) {
-      app_id_to_web_contents_list_.erase(i_app_id);
-      status = ash::STATUS_CLOSED;
-    }
-    ash::ShelfID id = GetShelfIDForAppID(app_id);
-    if (id)
-      SetItemStatus(id, status);
-  }
-}
-
 void ChromeLauncherController::UpdateAppState(content::WebContents* contents,
                                               AppState app_state) {
   std::string app_id = app_tab_helper_->GetAppID(contents);
@@ -955,42 +990,27 @@ void ChromeLauncherController::UpdateAppState(content::WebContents* contents,
   // remove it from the previous app.
   if (web_contents_to_app_id_.find(contents) != web_contents_to_app_id_.end()) {
     std::string last_app_id = web_contents_to_app_id_[contents];
-    if (last_app_id != app_id)
-      RemoveTabFromRunningApp(contents, last_app_id);
-  }
-
-  web_contents_to_app_id_[contents] = app_id;
-
-  if (app_state == APP_STATE_REMOVED) {
-    // The tab has gone away.
-    RemoveTabFromRunningApp(contents, app_id);
-  } else if (!app_id.empty()) {
-    WebContentsList& tab_list(app_id_to_web_contents_list_[app_id]);
-    WebContentsList::const_iterator i_tab =
-        std::find(tab_list.begin(), tab_list.end(), contents);
-
-    if (i_tab == tab_list.end())
-      tab_list.push_back(contents);
-
-    if (app_state == APP_STATE_INACTIVE || app_state == APP_STATE_ACTIVE) {
-      if (i_tab != tab_list.begin()) {
-        // Going to running state, but wasn't the front tab, indicating that a
-        // new tab has already become active.
-        return;
+    if (last_app_id != app_id) {
+      ash::ShelfID id = GetShelfIDForAppID(last_app_id);
+      if (id) {
+        // Since GetAppState() will use |web_contents_to_app_id_| we remove
+        // the connection before calling it.
+        web_contents_to_app_id_.erase(contents);
+        SetItemStatus(id, GetAppState(last_app_id));
       }
     }
+  }
 
-    if (app_state == APP_STATE_ACTIVE || app_state == APP_STATE_WINDOW_ACTIVE) {
-      tab_list.remove(contents);
-      tab_list.push_front(contents);
-    }
+  if (app_state == APP_STATE_REMOVED)
+    web_contents_to_app_id_.erase(contents);
+  else
+    web_contents_to_app_id_[contents] = app_id;
 
-    ash::ShelfID id = GetShelfIDForAppID(app_id);
-    if (id) {
-      // If the window is active, mark the app as active.
-      SetItemStatus(id, app_state == APP_STATE_WINDOW_ACTIVE ?
-          ash::STATUS_ACTIVE : ash::STATUS_RUNNING);
-    }
+  ash::ShelfID id = GetShelfIDForAppID(app_id);
+  if (id) {
+    SetItemStatus(id, (app_state == APP_STATE_WINDOW_ACTIVE ||
+                       app_state == APP_STATE_ACTIVE) ? ash::STATUS_ACTIVE :
+                                                        GetAppState(app_id));
   }
 }
 
@@ -1036,9 +1056,8 @@ void ChromeLauncherController::SetRefocusURLPatternForTest(ash::ShelfID id,
 
 const Extension* ChromeLauncherController::GetExtensionForAppID(
     const std::string& app_id) const {
-  // Some unit tests do not have a real extension.
-  return (profile_->GetExtensionService()) ?
-      profile_->GetExtensionService()->GetInstalledExtension(app_id) : NULL;
+  return extensions::ExtensionRegistry::Get(profile_)->GetExtensionById(
+      app_id, extensions::ExtensionRegistry::EVERYTHING);
 }
 
 void ChromeLauncherController::ActivateWindowOrMinimizeIfActive(
@@ -1066,7 +1085,7 @@ void ChromeLauncherController::ActivateWindowOrMinimizeIfActive(
     if (CommandLine::ForCurrentProcess()->HasSwitch(
             switches::kDisableMinimizeOnSecondLauncherItemClick)) {
       AnimateWindow(window->GetNativeWindow(),
-                    views::corewm::WINDOW_ANIMATION_TYPE_BOUNCE);
+                    wm::WINDOW_ANIMATION_TYPE_BOUNCE);
     } else {
       window->Minimize();
     }
@@ -1091,8 +1110,7 @@ void ChromeLauncherController::ShelfItemAdded(int index) {
   // The app list launcher can get added to the shelf after we applied the
   // preferences. In that case the item might be at the wrong spot. As such we
   // call the function again.
-  if (model_->items()[index].type == ash::TYPE_APP_LIST &&
-      ash::switches::UseAlternateShelfLayout())
+  if (model_->items()[index].type == ash::TYPE_APP_LIST)
     UpdateAppLaunchersFromPref();
 }
 
@@ -1105,8 +1123,7 @@ void ChromeLauncherController::ShelfItemMoved(int start_index,
   // We remember the moved item position if it is either pinnable or
   // it is the app list with the alternate shelf layout.
   if ((HasItemController(item.id) && IsPinned(item.id)) ||
-      (ash::switches::UseAlternateShelfLayout() &&
-       item.type == ash::TYPE_APP_LIST))
+       item.type == ash::TYPE_APP_LIST)
     PersistPinnedState();
 }
 
@@ -1131,64 +1148,65 @@ void ChromeLauncherController::ActiveUserChanged(
   // Update the V1 applications.
   browser_status_monitor_->ActiveUserChanged(user_email);
   // Switch the running applications to the new user.
-  shell_window_controller_->ActiveUserChanged(user_email);
+  app_window_controller_->ActiveUserChanged(user_email);
   // Update the user specific shell properties from the new user profile.
   UpdateAppLaunchersFromPref();
   SetShelfAlignmentFromPrefs();
   SetShelfAutoHideBehaviorFromPrefs();
   SetShelfBehaviorsFromPrefs();
+#if defined(OS_CHROMEOS)
+  SetVirtualKeyboardBehaviorFromPrefs();
+#endif  // defined(OS_CHROMEOS)
   // Restore the order of running, but unpinned applications for the activated
   // user.
   RestoreUnpinnedRunningApplicationOrder(user_email);
   // Inform the system tray of the change.
   ash::Shell::GetInstance()->system_tray_delegate()->ActiveUserWasChanged();
+  // Force on-screen keyboard to reset.
+  if (keyboard::IsKeyboardEnabled())
+    ash::Shell::GetInstance()->CreateKeyboard();
 }
 
 void ChromeLauncherController::AdditionalUserAddedToSession(Profile* profile) {
   // Switch the running applications to the new user.
-  shell_window_controller_->AdditionalUserAddedToSession(profile);
+  app_window_controller_->AdditionalUserAddedToSession(profile);
 }
 
-void ChromeLauncherController::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  switch (type) {
-    case chrome::NOTIFICATION_EXTENSION_LOADED: {
-      const Extension* extension =
-          content::Details<const Extension>(details).ptr();
-      if (IsAppPinned(extension->id())) {
-        // Clear and re-fetch to ensure icon is up-to-date.
-        app_icon_loader_->ClearImage(extension->id());
-        app_icon_loader_->FetchImage(extension->id());
-      }
+void ChromeLauncherController::OnExtensionLoaded(
+    content::BrowserContext* browser_context,
+    const Extension* extension) {
+  if (IsAppPinned(extension->id())) {
+    // Clear and re-fetch to ensure icon is up-to-date.
+    app_icon_loader_->ClearImage(extension->id());
+    app_icon_loader_->FetchImage(extension->id());
+  }
 
-      UpdateAppLaunchersFromPref();
-      break;
-    }
-    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
-      const content::Details<UnloadedExtensionInfo>& unload_info(details);
-      const Extension* extension = unload_info->extension;
-      const std::string& id = extension->id();
-      // Since we might have windowed apps of this type which might have
-      // outstanding locks which needs to be removed.
-      if (GetShelfIDForAppID(id) &&
-          unload_info->reason == UnloadedExtensionInfo::REASON_UNINSTALL) {
-        CloseWindowedAppsFromRemovedExtension(id);
-      }
+  UpdateAppLaunchersFromPref();
+}
 
-      if (IsAppPinned(id)) {
-        if (unload_info->reason == UnloadedExtensionInfo::REASON_UNINSTALL) {
-          DoUnpinAppWithID(id);
-          app_icon_loader_->ClearImage(id);
-        } else {
-          app_icon_loader_->UpdateImage(id);
-        }
+void ChromeLauncherController::OnExtensionUnloaded(
+    content::BrowserContext* browser_context,
+    const Extension* extension,
+    UnloadedExtensionInfo::Reason reason) {
+  const std::string& id = extension->id();
+  const Profile* profile = Profile::FromBrowserContext(browser_context);
+
+  // Since we might have windowed apps of this type which might have
+  // outstanding locks which needs to be removed.
+  if (GetShelfIDForAppID(id) &&
+      reason == UnloadedExtensionInfo::REASON_UNINSTALL) {
+    CloseWindowedAppsFromRemovedExtension(id, profile);
+  }
+
+  if (IsAppPinned(id)) {
+    if (reason == UnloadedExtensionInfo::REASON_UNINSTALL) {
+      if (profile == profile_) {
+        DoUnpinAppWithID(id);
       }
-      break;
+      app_icon_loader_->ClearImage(id);
+    } else {
+      app_icon_loader_->UpdateImage(id);
     }
-    default:
-      NOTREACHED() << "Unexpected notification type=" << type;
   }
 }
 
@@ -1219,9 +1237,6 @@ void ChromeLauncherController::OnShelfAlignmentChanged(
   }
 }
 
-void ChromeLauncherController::OnDisplayConfigurationChanging() {
-}
-
 void ChromeLauncherController::OnDisplayConfigurationChanged() {
   SetShelfBehaviorsFromPrefs();
 }
@@ -1286,9 +1301,9 @@ void ChromeLauncherController::ActivateShellApp(const std::string& app_id,
   if (id) {
     LauncherItemController* controller = id_to_item_controller_map_[id];
     if (controller->type() == LauncherItemController::TYPE_APP) {
-      ShellWindowLauncherItemController* shell_window_controller =
-          static_cast<ShellWindowLauncherItemController*>(controller);
-      shell_window_controller->ActivateIndexedApp(index);
+      AppWindowLauncherItemController* app_window_controller =
+          static_cast<AppWindowLauncherItemController*>(controller);
+      app_window_controller->ActivateIndexedApp(index);
     }
   }
 }
@@ -1322,9 +1337,9 @@ bool ChromeLauncherController::ContentCanBeHandledByGmailApp(
 
 gfx::Image ChromeLauncherController::GetAppListIcon(
     content::WebContents* web_contents) const {
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   if (IsIncognito(web_contents))
-    return rb.GetImageNamed(IDR_AURA_LAUNCHER_LIST_INCOGNITO_BROWSER);
+    return rb.GetImageNamed(IDR_ASH_SHELF_LIST_INCOGNITO_BROWSER);
   FaviconTabHelper* favicon_tab_helper =
       FaviconTabHelper::FromWebContents(web_contents);
   gfx::Image result = favicon_tab_helper->GetFavicon();
@@ -1439,6 +1454,25 @@ bool ChromeLauncherController::IsBrowserFromActiveUser(Browser* browser) {
   return multi_user_util::IsProfileFromActiveUser(browser->profile());
 }
 
+bool ChromeLauncherController::ShelfBoundsChangesProbablyWithUser(
+    aura::Window* root_window,
+    const std::string& user_id) const {
+  Profile* other_profile = multi_user_util::GetProfileFromUserID(user_id);
+  DCHECK_NE(other_profile, profile_);
+
+  // Note: The Auto hide state from preferences is not the same as the actual
+  // visibility of the shelf. Depending on all the various states (full screen,
+  // no window on desktop, multi user, ..) the shelf could be shown - or not.
+  bool currently_shown = ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER ==
+      GetShelfAutoHideBehaviorFromPrefs(profile_, root_window);
+  bool other_shown = ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER ==
+      GetShelfAutoHideBehaviorFromPrefs(other_profile, root_window);
+
+  return currently_shown != other_shown ||
+         GetShelfAlignmentFromPrefs(profile_, root_window) !=
+             GetShelfAlignmentFromPrefs(other_profile, root_window);
+}
+
 void ChromeLauncherController::LauncherItemClosed(ash::ShelfID id) {
   IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
   CHECK(iter != id_to_item_controller_map_.end());
@@ -1697,20 +1731,8 @@ void ChromeLauncherController::SetShelfAlignmentFromPrefs() {
 
   for (aura::Window::Windows::const_iterator iter = root_windows.begin();
        iter != root_windows.end(); ++iter) {
-    // See comment in |kShelfAlignment| as to why we consider two prefs.
-    const std::string alignment_value(
-        GetPrefForRootWindow(profile_->GetPrefs(),
-                             *iter,
-                             prefs::kShelfAlignmentLocal,
-                             prefs::kShelfAlignment));
-    ash::ShelfAlignment alignment = ash::SHELF_ALIGNMENT_BOTTOM;
-    if (alignment_value == ash::kShelfAlignmentLeft)
-      alignment = ash::SHELF_ALIGNMENT_LEFT;
-    else if (alignment_value == ash::kShelfAlignmentRight)
-      alignment = ash::SHELF_ALIGNMENT_RIGHT;
-    else if (alignment_value == ash::kShelfAlignmentTop)
-      alignment = ash::SHELF_ALIGNMENT_TOP;
-    ash::Shell::GetInstance()->SetShelfAlignment(alignment, *iter);
+    ash::Shell::GetInstance()->SetShelfAlignment(
+        GetShelfAlignmentFromPrefs(profile_, *iter), *iter);
   }
 }
 
@@ -1719,35 +1741,49 @@ void ChromeLauncherController::SetShelfBehaviorsFromPrefs() {
   SetShelfAlignmentFromPrefs();
 }
 
-WebContents* ChromeLauncherController::GetLastActiveWebContents(
-    const std::string& app_id) {
-  AppIDToWebContentsListMap::iterator i =
-      app_id_to_web_contents_list_.find(app_id);
-  if (i == app_id_to_web_contents_list_.end())
-    return NULL;
+#if defined(OS_CHROMEOS)
+void ChromeLauncherController::SetVirtualKeyboardBehaviorFromPrefs() {
+  const PrefService* service = profile_->GetPrefs();
+  const bool was_enabled = keyboard::IsKeyboardEnabled();
+  if (!service->HasPrefPath(prefs::kTouchVirtualKeyboardEnabled)) {
+    keyboard::SetKeyboardShowOverride(keyboard::KEYBOARD_SHOW_OVERRIDE_NONE);
+  } else {
+    const bool enable = service->GetBoolean(
+        prefs::kTouchVirtualKeyboardEnabled);
+    keyboard::SetKeyboardShowOverride(
+        enable ? keyboard::KEYBOARD_SHOW_OVERRIDE_ENABLED
+                : keyboard::KEYBOARD_SHOW_OVERRIDE_DISABLED);
+  }
+  const bool is_enabled = keyboard::IsKeyboardEnabled();
+  if (was_enabled && !is_enabled)
+    ash::Shell::GetInstance()->DeactivateKeyboard();
+  else if (is_enabled && !was_enabled)
+    ash::Shell::GetInstance()->CreateKeyboard();
+}
+#endif  // defined(OS_CHROMEOS)
 
-  // There are many crash records (crbug.com/341250) which indicate that the
-  // app_id_to_web_contents_list_ contains deleted content entries - so there
-  // must be a way that the content does not get properly updated. To fix
-  // M33 and M34 we filter out the invalid items here, but this should be
-  // addressed by a later patch correctly. Looking at the code however, the
-  // real culprit is possibly BrowserStatusMonitor::UpdateAppItemState which
-  // does not call "UpdateAppState(.., APP_STATE_REMOVED)" because due to a
-  // Browser::SwapTabContent operation it isn't able to get the browser. I
-  // think that the real patch is to call anyway when APP_STATE_REMOVED is
-  // requested, but for a backport that seems risky.
-  WebContentsList* list = &i->second;
-  while (!list->empty()) {
-    WebContents* contents = *list->begin();
-    if (chrome::FindBrowserWithWebContents(contents))
-      return contents;
-    list->erase(list->begin());
-    // This might not be necessary, but since we do not know why the lists
-    // diverged we also erase it since it cannot be correct either.
-    web_contents_to_app_id_.erase(contents);
+ash::ShelfItemStatus ChromeLauncherController::GetAppState(
+    const std::string& app_id) {
+  ash::ShelfItemStatus status = ash::STATUS_CLOSED;
+  for (WebContentsToAppIDMap::iterator it = web_contents_to_app_id_.begin();
+       it != web_contents_to_app_id_.end();
+       ++it) {
+    if (it->second == app_id) {
+      Browser* browser = chrome::FindBrowserWithWebContents(it->first);
+      // Usually there should never be an item in our |web_contents_to_app_id_|
+      // list which got deleted already. However - in some situations e.g.
+      // Browser::SwapTabContent there is temporarily no associated browser.
+      if (!browser)
+        continue;
+      if (browser->window()->IsActive()) {
+        return browser->tab_strip_model()->GetActiveWebContents() == it->first ?
+            ash::STATUS_ACTIVE : ash::STATUS_RUNNING;
+      } else {
+        status = ash::STATUS_RUNNING;
+      }
+    }
   }
-  app_id_to_web_contents_list_.erase(app_id);
-  return NULL;
+  return status;
 }
 
 ash::ShelfID ChromeLauncherController::InsertAppLauncherItem(
@@ -1764,17 +1800,12 @@ ash::ShelfID ChromeLauncherController::InsertAppLauncherItem(
 
   ash::ShelfItem item;
   item.type = shelf_item_type;
-  item.image = extensions::IconsInfo::GetDefaultAppIcon();
-
-  WebContents* active_tab = GetLastActiveWebContents(app_id);
-  if (active_tab) {
-    Browser* browser = chrome::FindBrowserWithWebContents(active_tab);
-    DCHECK(browser);
-    if (browser->window()->IsActive())
-      status = ash::STATUS_ACTIVE;
-    else
-      status = ash::STATUS_RUNNING;
-  }
+  item.image = extensions::util::GetDefaultAppIcon();
+
+  ash::ShelfItemStatus new_state = GetAppState(app_id);
+  if (new_state != ash::STATUS_CLOSED)
+    status = new_state;
+
   item.status = status;
 
   model_->AddAt(index, item);
@@ -1869,21 +1900,20 @@ void ChromeLauncherController::MoveChromeOrApplistToFinalPosition(
 }
 
 int ChromeLauncherController::FindInsertionPoint(bool is_app_list) {
-  bool alternate = ash::switches::UseAlternateShelfLayout();
   // Keeping this change small to backport to M33&32 (see crbug.com/329597).
   // TODO(skuhne): With the removal of the legacy shelf layout we should remove
   // the ability to move the app list item since this was never used. We should
   // instead ask the ShelfModel::ValidateInsertionIndex or similir for an index.
-  if (is_app_list && alternate)
+  if (is_app_list)
     return 0;
 
   for (int i = model_->item_count() - 1; i > 0; --i) {
     ash::ShelfItemType type = model_->items()[i].type;
     if (type == ash::TYPE_APP_SHORTCUT ||
-        ((is_app_list || alternate) && type == ash::TYPE_APP_LIST) ||
-        type == ash::TYPE_BROWSER_SHORTCUT ||
-        type == ash::TYPE_WINDOWED_APP)
+        (is_app_list && type == ash::TYPE_APP_LIST) ||
+        type == ash::TYPE_BROWSER_SHORTCUT) {
       return i;
+    }
   }
   return 0;
 }
@@ -1970,10 +2000,7 @@ ChromeLauncherController::GetListOfPinnedAppsAndBrowser() {
   // If not added yet, add the app list item either at the end or at the
   // beginning - depending on the shelf layout.
   if (!app_list_icon_added) {
-    if (ash::switches::UseAlternateShelfLayout())
-      pinned_apps.insert(pinned_apps.begin(), kAppShelfIdPlaceholder);
-    else
-      pinned_apps.push_back(kAppShelfIdPlaceholder);
+    pinned_apps.insert(pinned_apps.begin(), kAppShelfIdPlaceholder);
   }
   return pinned_apps;
 }
@@ -1986,7 +2013,8 @@ bool ChromeLauncherController::IsIncognito(
 }
 
 void ChromeLauncherController::CloseWindowedAppsFromRemovedExtension(
-    const std::string& app_id) {
+    const std::string& app_id,
+    const Profile* profile) {
   // This function cannot rely on the controller's enumeration functionality
   // since the extension has already be unloaded.
   const BrowserList* ash_browser_list =
@@ -1996,11 +2024,11 @@ void ChromeLauncherController::CloseWindowedAppsFromRemovedExtension(
            it = ash_browser_list->begin_last_active();
        it != ash_browser_list->end_last_active(); ++it) {
     Browser* browser = *it;
-    if (!browser->is_type_tabbed() &&
-        browser->is_type_popup() &&
+    if (!browser->is_type_tabbed() && browser->is_type_popup() &&
         browser->is_app() &&
-        app_id == web_app::GetExtensionIdFromApplicationName(
-            browser->app_name())) {
+        app_id ==
+            web_app::GetExtensionIdFromApplicationName(browser->app_name()) &&
+        profile == browser->profile()) {
       browser_to_close.push_back(browser);
     }
   }
@@ -2055,12 +2083,22 @@ void ChromeLauncherController::AttachProfile(Profile* profile) {
       prefs::kShelfPreferences,
       base::Bind(&ChromeLauncherController::SetShelfBehaviorsFromPrefs,
                  base::Unretained(this)));
+#if defined(OS_CHROMEOS)
+  pref_change_registrar_.Add(
+      prefs::kTouchVirtualKeyboardEnabled,
+      base::Bind(&ChromeLauncherController::SetVirtualKeyboardBehaviorFromPrefs,
+                 base::Unretained(this)));
+#endif  // defined(OS_CHROMEOS)
+
+  extensions::ExtensionRegistry::Get(profile_)->AddObserver(this);
 }
 
 void ChromeLauncherController::ReleaseProfile() {
   if (app_sync_ui_state_)
     app_sync_ui_state_->RemoveObserver(this);
 
+  extensions::ExtensionRegistry::Get(profile_)->RemoveObserver(this);
+
   PrefServiceSyncable::FromProfile(profile_)->RemoveObserver(this);
 
   pref_change_registrar_.RemoveAll();