Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / ash / launcher / chrome_launcher_controller.cc
index 9cf51ae..f6b4379 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"
@@ -63,7 +63,6 @@
 #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 "content/public/browser/navigation_entry.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/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 "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/keyboard/keyboard_util.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 "components/user_manager/user_manager.h"
 #endif
 
 using extensions::Extension;
@@ -195,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,
@@ -224,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
@@ -240,11 +285,12 @@ 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,
@@ -270,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
@@ -381,11 +427,11 @@ ChromeLauncherController::ChromeLauncherController(Profile* profile,
 
   notification_registrar_.Add(
       this,
-      chrome::NOTIFICATION_EXTENSION_LOADED,
+      extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
       content::Source<Profile>(profile_));
   notification_registrar_.Add(
       this,
-      chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
+      extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
       content::Source<Profile>(profile_));
 }
 
@@ -445,6 +491,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)->
@@ -579,6 +628,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);
@@ -650,8 +727,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_,
@@ -804,9 +883,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) {
@@ -883,31 +963,13 @@ 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(
     aura::Window* root_window) const {
-  return !ash::Shell::GetInstance()->IsMaximizeModeWindowManagerEnabled() &&
-      profile_->GetPrefs()->FindPreference(
-          prefs::kShelfAutoHideBehaviorLocal)->IsUserModifiable();
+  return profile_->GetPrefs()->
+      FindPreference(prefs::kShelfAutoHideBehaviorLocal)->IsUserModifiable();
 }
 
 void ChromeLauncherController::ToggleShelfAutoHideBehavior(
@@ -920,31 +982,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);
@@ -958,42 +995,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));
   }
 }
 
@@ -1039,9 +1061,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(
@@ -1094,8 +1115,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();
 }
 
@@ -1108,8 +1128,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();
 }
 
@@ -1140,11 +1159,17 @@ void ChromeLauncherController::ActiveUserChanged(
   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) {
@@ -1157,7 +1182,7 @@ void ChromeLauncherController::Observe(
     const content::NotificationSource& source,
     const content::NotificationDetails& details) {
   switch (type) {
-    case chrome::NOTIFICATION_EXTENSION_LOADED: {
+    case extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: {
       const Extension* extension =
           content::Details<const Extension>(details).ptr();
       if (IsAppPinned(extension->id())) {
@@ -1169,7 +1194,7 @@ void ChromeLauncherController::Observe(
       UpdateAppLaunchersFromPref();
       break;
     }
-    case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
+    case extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
       const content::Details<UnloadedExtensionInfo>& unload_info(details);
       const Extension* extension = unload_info->extension;
       const std::string& id = extension->id();
@@ -1322,9 +1347,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 +1464,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 +1741,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 +1751,43 @@ 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();
+  if (!service->HasPrefPath(prefs::kTouchVirtualKeyboardEnabled)) {
+    keyboard::SetKeyboardShowOverride(keyboard::KEYBOARD_SHOW_OVERRIDE_NONE);
+  } else {
+    const bool enabled = service->GetBoolean(
+        prefs::kTouchVirtualKeyboardEnabled);
+    keyboard::SetKeyboardShowOverride(
+        enabled ? keyboard::KEYBOARD_SHOW_OVERRIDE_ENABLED
+                : keyboard::KEYBOARD_SHOW_OVERRIDE_DISABLED);
+  }
+}
+#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 +1804,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,18 +1904,17 @@ 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) ||
+        (is_app_list && type == ash::TYPE_APP_LIST) ||
         type == ash::TYPE_BROWSER_SHORTCUT) {
       return i;
     }
@@ -1970,10 +2004,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;
 }
@@ -2055,6 +2086,12 @@ 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)
 }
 
 void ChromeLauncherController::ReleaseProfile() {