mash: Remove shelf app menu item objects.

Remove ash::ShelfApplicationMenuItem subclasses.
Add command ids to the base class to identify menu items.
Add ShelfItemDelegate::ExecuteCommand for menu item selection.
Move app menu item object logic into shelf item delegates.

Cleanup:
-Make some BrowserShortcutLauncherItemController functions local.
-Rename ChromeLauncherController::GetAppMenuItemsForTest, nix unused param.
-Simplify ExtensionAppWindowLauncherItemController (icon, registry, etc.)

BUG=557406
TEST=Automated; no shelf app menu behavior changes.
R=jamescook@chromium.org

Review-Url: https://codereview.chromium.org/2716403005
Cr-Commit-Position: refs/heads/master@{#454340}
diff --git a/ash/common/shelf/app_list_shelf_item_delegate.cc b/ash/common/shelf/app_list_shelf_item_delegate.cc
index 218efd1..425ffecc 100644
--- a/ash/common/shelf/app_list_shelf_item_delegate.cc
+++ b/ash/common/shelf/app_list_shelf_item_delegate.cc
@@ -42,10 +42,16 @@
 
 ShelfAppMenuItemList AppListShelfItemDelegate::GetAppMenuItems(
     int event_flags) {
-  // AppList does not show an application menu.
+  // Return an empty item list to avoid showing an application menu.
   return ShelfAppMenuItemList();
 }
 
+void AppListShelfItemDelegate::ExecuteCommand(uint32_t command_id,
+                                              int event_flags) {
+  // This delegate does not support showing an application menu.
+  NOTIMPLEMENTED();
+}
+
 void AppListShelfItemDelegate::Close() {}
 
 }  // namespace ash
diff --git a/ash/common/shelf/app_list_shelf_item_delegate.h b/ash/common/shelf/app_list_shelf_item_delegate.h
index a7d56ff6..88f09d2 100644
--- a/ash/common/shelf/app_list_shelf_item_delegate.h
+++ b/ash/common/shelf/app_list_shelf_item_delegate.h
@@ -27,6 +27,7 @@
                            int64_t display_id,
                            ShelfLaunchSource source) override;
   ShelfAppMenuItemList GetAppMenuItems(int event_flags) override;
+  void ExecuteCommand(uint32_t command_id, int event_flags) override;
   void Close() override;
 
  private:
diff --git a/ash/common/shelf/shelf_application_menu_model.cc b/ash/common/shelf/shelf_application_menu_model.cc
index 331f0d5..7bf323c 100644
--- a/ash/common/shelf/shelf_application_menu_model.cc
+++ b/ash/common/shelf/shelf_application_menu_model.cc
@@ -9,6 +9,7 @@
 #include <limits>
 #include <utility>
 
+#include "ash/common/shelf/shelf_item_delegate.h"
 #include "ash/public/cpp/shelf_application_menu_item.h"
 #include "base/metrics/histogram_macros.h"
 
@@ -22,8 +23,9 @@
 
 ShelfApplicationMenuModel::ShelfApplicationMenuModel(
     const base::string16& title,
-    ShelfAppMenuItemList items)
-    : ui::SimpleMenuModel(this), items_(std::move(items)) {
+    ShelfAppMenuItemList items,
+    ShelfItemDelegate* delegate)
+    : ui::SimpleMenuModel(this), items_(std::move(items)), delegate_(delegate) {
   AddSeparator(ui::SPACING_SEPARATOR);
   AddItem(kInvalidCommandId, title);
   AddSeparator(ui::SPACING_SEPARATOR);
@@ -53,8 +55,10 @@
 
 void ShelfApplicationMenuModel::ExecuteCommand(int command_id,
                                                int event_flags) {
+  DCHECK(delegate_);
   DCHECK(IsCommandIdEnabled(command_id));
-  items_[command_id]->Execute(event_flags);
+  // Have the delegate execute its own custom command id for the given item.
+  delegate_->ExecuteCommand(items_[command_id]->command_id(), event_flags);
   RecordMenuItemSelectedMetrics(command_id, items_.size());
 }
 
diff --git a/ash/common/shelf/shelf_application_menu_model.h b/ash/common/shelf/shelf_application_menu_model.h
index ff865fe..7abe8b5 100644
--- a/ash/common/shelf/shelf_application_menu_model.h
+++ b/ash/common/shelf/shelf_application_menu_model.h
@@ -13,10 +13,11 @@
 #include "base/macros.h"
 #include "ui/base/models/simple_menu_model.h"
 
-class ShelfApplicationMenuModelTestAPI;
-
 namespace ash {
 
+class ShelfApplicationMenuModelTestAPI;
+class ShelfItemDelegate;
+
 // A menu model listing open applications associated with a shelf item. Layout:
 // +---------------------------+
 // |                           |
@@ -30,9 +31,11 @@
     : public ui::SimpleMenuModel,
       public ui::SimpleMenuModel::Delegate {
  public:
-  // Makes a menu with a |title|, separators, and the specified |items|.
+  // Makes a menu with a |title|, separators, and |items| for |delegate|.
+  // |delegate| may be null in unit tests that do not execute commands.
   ShelfApplicationMenuModel(const base::string16& title,
-                            ShelfAppMenuItemList items);
+                            ShelfAppMenuItemList items,
+                            ShelfItemDelegate* delegate);
   ~ShelfApplicationMenuModel() override;
 
   // ui::SimpleMenuModel::Delegate:
@@ -50,6 +53,9 @@
   // The list of menu items as returned from the shelf item's controller.
   ShelfAppMenuItemList items_;
 
+  // The shelf item delegate that created the menu and executes its commands.
+  ShelfItemDelegate* delegate_;
+
   DISALLOW_COPY_AND_ASSIGN(ShelfApplicationMenuModel);
 };
 
diff --git a/ash/common/shelf/shelf_application_menu_model_unittest.cc b/ash/common/shelf/shelf_application_menu_model_unittest.cc
index 704f473..aebee58 100644
--- a/ash/common/shelf/shelf_application_menu_model_unittest.cc
+++ b/ash/common/shelf/shelf_application_menu_model_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/common/test/test_shelf_item_delegate.h"
 #include "ash/public/cpp/shelf_application_menu_item.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
@@ -49,7 +50,7 @@
 // Verifies the menu contents given an empty item list.
 TEST(ShelfApplicationMenuModelTest, VerifyContentsWithNoMenuItems) {
   base::string16 title = base::ASCIIToUTF16("title");
-  ShelfApplicationMenuModel menu(title, ShelfAppMenuItemList());
+  ShelfApplicationMenuModel menu(title, ShelfAppMenuItemList(), nullptr);
   // Expect the title with separators.
   ASSERT_EQ(static_cast<int>(3), menu.GetItemCount());
   EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(0));
@@ -65,12 +66,12 @@
   base::string16 title1 = base::ASCIIToUTF16("title1");
   base::string16 title2 = base::ASCIIToUTF16("title2");
   base::string16 title3 = base::ASCIIToUTF16("title3");
-  items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(title1));
-  items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(title2));
-  items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(title3));
+  items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(0, title1));
+  items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(1, title2));
+  items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(2, title3));
 
   base::string16 title = base::ASCIIToUTF16("title");
-  ShelfApplicationMenuModel menu(title, std::move(items));
+  ShelfApplicationMenuModel menu(title, std::move(items), nullptr);
   ShelfApplicationMenuModelTestAPI menu_test_api(&menu);
 
   // Expect the title with separators, the enabled items, and another separator.
@@ -100,7 +101,8 @@
   base::HistogramTester histogram_tester;
 
   ShelfAppMenuItemList items;
-  ShelfApplicationMenuModel menu(base::ASCIIToUTF16("title"), std::move(items));
+  ShelfApplicationMenuModel menu(base::ASCIIToUTF16("title"), std::move(items),
+                                 nullptr);
   ShelfApplicationMenuModelTestAPI menu_test_api(&menu);
   menu_test_api.RecordMenuItemSelectedMetrics(kCommandId, kNumMenuItemsEnabled);
 
@@ -119,8 +121,9 @@
 
   ShelfAppMenuItemList items;
   base::string16 title = base::ASCIIToUTF16("title");
-  items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(title));
-  ShelfApplicationMenuModel menu(title, std::move(items));
+  items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(0, title));
+  test::TestShelfItemDelegate test_delegate(nullptr);
+  ShelfApplicationMenuModel menu(title, std::move(items), &test_delegate);
   menu.ExecuteCommand(0, 0);
 
   histogram_tester.ExpectTotalCount(kNumItemsEnabledHistogramName, 1);
diff --git a/ash/common/shelf/shelf_controller.cc b/ash/common/shelf/shelf_controller.cc
index 4e83673..5e5fc6e 100644
--- a/ash/common/shelf/shelf_controller.cc
+++ b/ash/common/shelf/shelf_controller.cc
@@ -71,12 +71,13 @@
   }
 
   ShelfAppMenuItemList GetAppMenuItems(int event_flags) override {
-    ShelfAppMenuItemList items;
-    for (const auto& window : window_id_to_title_) {
-      items.push_back(
-          base::MakeUnique<ShelfApplicationMenuItem>(window.second));
-    }
-    return items;
+    // Return an empty item list to avoid showing an application menu.
+    return ShelfAppMenuItemList();
+  }
+
+  void ExecuteCommand(uint32_t command_id, int event_flags) override {
+    // This delegate does not support showing an application menu.
+    NOTIMPLEMENTED();
   }
 
   void Close() override { NOTIMPLEMENTED(); }
diff --git a/ash/common/shelf/shelf_item_delegate.h b/ash/common/shelf/shelf_item_delegate.h
index ce7dd17..8ff4aed 100644
--- a/ash/common/shelf/shelf_item_delegate.h
+++ b/ash/common/shelf/shelf_item_delegate.h
@@ -5,6 +5,8 @@
 #ifndef ASH_COMMON_SHELF_SHELF_ITEM_DELEGATE_H_
 #define ASH_COMMON_SHELF_SHELF_ITEM_DELEGATE_H_
 
+#include <stdint.h>
+
 #include "ash/ash_export.h"
 #include "ash/public/cpp/shelf_application_menu_item.h"
 #include "ash/public/cpp/shelf_types.h"
@@ -35,6 +37,9 @@
   // |event_flags| specifies the flags of the event which triggered this menu.
   virtual ShelfAppMenuItemList GetAppMenuItems(int event_flags) = 0;
 
+  // Called on invocation of a shelf item's application menu command.
+  virtual void ExecuteCommand(uint32_t command_id, int event_flags) = 0;
+
   // Closes all windows associated with this item.
   virtual void Close() = 0;
 
diff --git a/ash/common/shelf/shelf_view.cc b/ash/common/shelf/shelf_view.cc
index 0965d43b..b3ca0adf 100644
--- a/ash/common/shelf/shelf_view.cc
+++ b/ash/common/shelf/shelf_view.cc
@@ -1615,19 +1615,18 @@
                                     const ui::Event& event,
                                     views::InkDrop* ink_drop) {
   ShelfItemDelegate* item_delegate = model_->GetShelfItemDelegate(item.id);
-  ShelfAppMenuItemList menu_items =
-      item_delegate->GetAppMenuItems(event.flags());
+  ShelfAppMenuItemList items = item_delegate->GetAppMenuItems(event.flags());
 
   // The application list menu should only show for two or more items; return
   // false here to ensure that other behavior is triggered (eg. activating or
   // minimizing a single associated window, or launching a pinned shelf item).
-  if (menu_items.size() < 2)
+  if (items.size() < 2)
     return false;
 
   ink_drop->AnimateToState(views::InkDropState::ACTIVATED);
   context_menu_id_ = item.id;
-  ShowMenu(base::MakeUnique<ShelfApplicationMenuModel>(item.title,
-                                                       std::move(menu_items)),
+  ShowMenu(base::MakeUnique<ShelfApplicationMenuModel>(
+               item.title, std::move(items), item_delegate),
            source, gfx::Point(), false, ui::GetMenuSourceTypeForEvent(event),
            ink_drop);
   return true;
diff --git a/ash/common/shelf/shelf_window_watcher_item_delegate.cc b/ash/common/shelf/shelf_window_watcher_item_delegate.cc
index 2b56a38..262e606d 100644
--- a/ash/common/shelf/shelf_window_watcher_item_delegate.cc
+++ b/ash/common/shelf/shelf_window_watcher_item_delegate.cc
@@ -65,6 +65,12 @@
   return ShelfAppMenuItemList();
 }
 
+void ShelfWindowWatcherItemDelegate::ExecuteCommand(uint32_t command_id,
+                                                    int event_flags) {
+  // This delegate does not support showing an application menu.
+  NOTIMPLEMENTED();
+}
+
 void ShelfWindowWatcherItemDelegate::Close() {
   window_->CloseWidget();
 }
diff --git a/ash/common/shelf/shelf_window_watcher_item_delegate.h b/ash/common/shelf/shelf_window_watcher_item_delegate.h
index 17651e5..fd61f439 100644
--- a/ash/common/shelf/shelf_window_watcher_item_delegate.h
+++ b/ash/common/shelf/shelf_window_watcher_item_delegate.h
@@ -26,6 +26,7 @@
                            int64_t display_id,
                            ShelfLaunchSource source) override;
   ShelfAppMenuItemList GetAppMenuItems(int event_flags) override;
+  void ExecuteCommand(uint32_t command_id, int event_flags) override;
   void Close() override;
 
   ShelfID id_;
diff --git a/ash/common/test/test_shelf_item_delegate.cc b/ash/common/test/test_shelf_item_delegate.cc
index 2d0faeb..31e22c8 100644
--- a/ash/common/test/test_shelf_item_delegate.cc
+++ b/ash/common/test/test_shelf_item_delegate.cc
@@ -34,6 +34,12 @@
   return ShelfAppMenuItemList();
 }
 
+void TestShelfItemDelegate::ExecuteCommand(uint32_t command_id,
+                                           int event_flags) {
+  // This delegate does not support showing an application menu.
+  NOTIMPLEMENTED();
+}
+
 void TestShelfItemDelegate::Close() {}
 
 }  // namespace test
diff --git a/ash/common/test/test_shelf_item_delegate.h b/ash/common/test/test_shelf_item_delegate.h
index f1a259f..6e2f8b5 100644
--- a/ash/common/test/test_shelf_item_delegate.h
+++ b/ash/common/test/test_shelf_item_delegate.h
@@ -26,6 +26,7 @@
                            int64_t display_id,
                            ShelfLaunchSource source) override;
   ShelfAppMenuItemList GetAppMenuItems(int event_flags) override;
+  void ExecuteCommand(uint32_t command_id, int event_flags) override;
   void Close() override;
 
  private:
diff --git a/ash/public/cpp/shelf_application_menu_item.cc b/ash/public/cpp/shelf_application_menu_item.cc
index 77550c9..76191eb 100644
--- a/ash/public/cpp/shelf_application_menu_item.cc
+++ b/ash/public/cpp/shelf_application_menu_item.cc
@@ -6,12 +6,13 @@
 
 namespace ash {
 
-ShelfApplicationMenuItem::ShelfApplicationMenuItem(const base::string16 title,
+ShelfApplicationMenuItem::ShelfApplicationMenuItem(uint32_t command_id,
+                                                   const base::string16& title,
                                                    const gfx::Image* icon)
-    : title_(title), icon_(icon ? gfx::Image(*icon) : gfx::Image()) {}
+    : command_id_(command_id),
+      title_(title),
+      icon_(icon ? gfx::Image(*icon) : gfx::Image()) {}
 
 ShelfApplicationMenuItem::~ShelfApplicationMenuItem() {}
 
-void ShelfApplicationMenuItem::Execute(int event_flags) {}
-
 }  // namespace ash
diff --git a/ash/public/cpp/shelf_application_menu_item.h b/ash/public/cpp/shelf_application_menu_item.h
index f2d7e53..0f19b73 100644
--- a/ash/public/cpp/shelf_application_menu_item.h
+++ b/ash/public/cpp/shelf_application_menu_item.h
@@ -15,23 +15,23 @@
 
 namespace ash {
 
-// The title, icon, and execute function for shelf application menu items.
+// The command id, title, and icon for shelf application menu items.
 class ASH_PUBLIC_EXPORT ShelfApplicationMenuItem {
  public:
-  // Creates an item with a |title| and optional |icon| (pass nullptr for none).
-  explicit ShelfApplicationMenuItem(const base::string16 title,
-                                    const gfx::Image* icon = nullptr);
-  virtual ~ShelfApplicationMenuItem();
+  // Creates an item with a client-specific |command_id|, a |title|, and an
+  // optional |icon| (pass nullptr for no icon).
+  ShelfApplicationMenuItem(uint32_t command_id,
+                           const base::string16& title,
+                           const gfx::Image* icon = nullptr);
+  ~ShelfApplicationMenuItem();
 
   // The title and icon for this menu item.
+  uint32_t command_id() const { return command_id_; }
   const base::string16& title() const { return title_; }
   const gfx::Image& icon() const { return icon_; }
 
-  // Executes the menu item; |event_flags| can be used to check additional
-  // keyboard modifiers from the event that issued this command.
-  virtual void Execute(int event_flags);
-
  private:
+  const uint32_t command_id_;
   const base::string16 title_;
   const gfx::Image icon_;
 
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index 7a1a46e..3810895 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -1983,8 +1983,8 @@
   ShelfAppMenuItemList GetAppMenuItems(int event_flags) override {
     ShelfAppMenuItemList items;
     base::string16 title = base::ASCIIToUTF16("title");
-    items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(title));
-    items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(title));
+    items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(0, title));
+    items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(1, title));
     return items;
   }
 
diff --git a/ash/shell/window_watcher_shelf_item_delegate.cc b/ash/shell/window_watcher_shelf_item_delegate.cc
index 99d69ec..d7cd242 100644
--- a/ash/shell/window_watcher_shelf_item_delegate.cc
+++ b/ash/shell/window_watcher_shelf_item_delegate.cc
@@ -40,6 +40,12 @@
   return ShelfAppMenuItemList();
 }
 
+void WindowWatcherShelfItemDelegate::ExecuteCommand(uint32_t command_id,
+                                                    int event_flags) {
+  // This delegate does not support showing an application menu.
+  NOTIMPLEMENTED();
+}
+
 void WindowWatcherShelfItemDelegate::Close() {}
 
 }  // namespace shell
diff --git a/ash/shell/window_watcher_shelf_item_delegate.h b/ash/shell/window_watcher_shelf_item_delegate.h
index 8e63893..73bb422 100644
--- a/ash/shell/window_watcher_shelf_item_delegate.h
+++ b/ash/shell/window_watcher_shelf_item_delegate.h
@@ -27,6 +27,7 @@
                            int64_t display_id,
                            ShelfLaunchSource source) override;
   ShelfAppMenuItemList GetAppMenuItems(int event_flags) override;
+  void ExecuteCommand(uint32_t command_id, int event_flags) override;
   void Close() override;
 
  private:
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index acf41fd..b0c301b 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1323,12 +1323,6 @@
       "ash/launcher/browser_shortcut_launcher_item_controller.h",
       "ash/launcher/browser_status_monitor.cc",
       "ash/launcher/browser_status_monitor.h",
-      "ash/launcher/chrome_launcher_app_menu_item_browser.cc",
-      "ash/launcher/chrome_launcher_app_menu_item_browser.h",
-      "ash/launcher/chrome_launcher_app_menu_item_tab.cc",
-      "ash/launcher/chrome_launcher_app_menu_item_tab.h",
-      "ash/launcher/chrome_launcher_app_menu_item_v2app.cc",
-      "ash/launcher/chrome_launcher_app_menu_item_v2app.h",
       "ash/launcher/chrome_launcher_controller.cc",
       "ash/launcher/chrome_launcher_controller.h",
       "ash/launcher/chrome_launcher_controller_impl.cc",
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
index b42150b0..ef9ff8e 100644
--- a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
@@ -13,7 +13,6 @@
 #include "chrome/browser/extensions/launch_util.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/ash/launcher/arc_playstore_shortcut_launcher_item_controller.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h"
 #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
@@ -126,17 +125,46 @@
 ash::ShelfAppMenuItemList AppShortcutLauncherItemController::GetAppMenuItems(
     int event_flags) {
   ash::ShelfAppMenuItemList items;
-  std::vector<content::WebContents*> content_list = GetRunningApplications();
-  for (size_t i = 0; i < content_list.size(); i++) {
-    content::WebContents* web_contents = content_list[i];
-    gfx::Image app_icon = launcher_controller()->GetAppListIcon(web_contents);
+  app_menu_items_ = GetRunningApplications();
+  for (size_t i = 0; i < app_menu_items_.size(); i++) {
+    content::WebContents* web_contents = app_menu_items_[i];
+    gfx::Image icon = launcher_controller()->GetAppListIcon(web_contents);
     base::string16 title = launcher_controller()->GetAppListTitle(web_contents);
-    items.push_back(base::MakeUnique<ChromeLauncherAppMenuItemTab>(
-        title, &app_icon, web_contents));
+    items.push_back(base::MakeUnique<ash::ShelfApplicationMenuItem>(
+        base::checked_cast<uint32_t>(i), title, &icon));
   }
   return items;
 }
 
+void AppShortcutLauncherItemController::ExecuteCommand(uint32_t command_id,
+                                                       int event_flags) {
+  if (static_cast<size_t>(command_id) >= app_menu_items_.size()) {
+    app_menu_items_.clear();
+    return;
+  }
+
+  // If the web contents was destroyed while the menu was open, then the invalid
+  // pointer cached in |app_menu_items_| should yield a null browser or kNoTab.
+  content::WebContents* web_contents = app_menu_items_[command_id];
+  Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
+  TabStripModel* tab_strip = browser ? browser->tab_strip_model() : nullptr;
+  const int index = tab_strip ? tab_strip->GetIndexOfWebContents(web_contents)
+                              : TabStripModel::kNoTab;
+  if (index != TabStripModel::kNoTab) {
+    if (event_flags & (ui::EF_SHIFT_DOWN | ui::EF_MIDDLE_MOUSE_BUTTON)) {
+      tab_strip->CloseWebContentsAt(index, TabStripModel::CLOSE_USER_GESTURE);
+    } else {
+      multi_user_util::MoveWindowToCurrentDesktop(
+          browser->window()->GetNativeWindow());
+      tab_strip->ActivateTabAt(index, false);
+      browser->window()->Show();
+      browser->window()->Activate();
+    }
+  }
+
+  app_menu_items_.clear();
+}
+
 void AppShortcutLauncherItemController::Close() {
   // Close all running 'programs' of this type.
   std::vector<content::WebContents*> content =
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
index 73a1909..a21a5f42 100644
--- a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
@@ -46,6 +46,7 @@
                                 int64_t display_id,
                                 ash::ShelfLaunchSource source) override;
   ash::ShelfAppMenuItemList GetAppMenuItems(int event_flags) override;
+  void ExecuteCommand(uint32_t command_id, int event_flags) override;
   void Close() override;
 
   // Get the refocus url pattern, which can be used to identify this application
@@ -97,6 +98,9 @@
 
   ChromeLauncherController* chrome_launcher_controller_;
 
+  // The cached list of open app web contents shown in an application menu.
+  std::vector<content::WebContents*> app_menu_items_;
+
   DISALLOW_COPY_AND_ASSIGN(AppShortcutLauncherItemController);
 };
 
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc
index 631e530..36ac6a8b 100644
--- a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc
@@ -96,9 +96,16 @@
 
 ash::ShelfAppMenuItemList AppWindowLauncherItemController::GetAppMenuItems(
     int event_flags) {
+  // Return an empty item list to avoid showing an application menu.
   return ash::ShelfAppMenuItemList();
 }
 
+void AppWindowLauncherItemController::ExecuteCommand(uint32_t command_id,
+                                                     int event_flags) {
+  // This delegate does not support showing an application menu.
+  NOTIMPLEMENTED();
+}
+
 void AppWindowLauncherItemController::Close() {
   // Note: Closing windows may affect the contents of app_windows_.
   WindowList windows_to_close = windows_;
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h
index b7581f7..9b5f9243 100644
--- a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h
@@ -23,10 +23,10 @@
 
 class ChromeLauncherController;
 
-// This is a LauncherItemController for abstract app windows. There is one
-// instance per app, per launcher id. For apps with multiple windows, each item
-// controller keeps track of all windows associated with the app and their
-// activation order. Instances are owned by ash::ShelfModel.
+// This is a LauncherItemController for abstract app windows (extension or ARC).
+// There is one instance per app, per launcher id. For apps with multiple
+// windows, each item controller keeps track of all windows associated with the
+// app and their activation order. Instances are owned by ash::ShelfModel.
 //
 // Tests are in chrome_launcher_controller_impl_browsertest.cc
 class AppWindowLauncherItemController : public LauncherItemController,
@@ -49,6 +49,7 @@
                                 int64_t display_id,
                                 ash::ShelfLaunchSource source) override;
   ash::ShelfAppMenuItemList GetAppMenuItems(int event_flags) override;
+  void ExecuteCommand(uint32_t command_id, int event_flags) override;
   void Close() override;
 
   // aura::WindowObserver overrides:
diff --git a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc
index aa55e1e..47ab491 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc
@@ -42,9 +42,16 @@
 
 ash::ShelfAppMenuItemList ArcAppDeferredLauncherItemController::GetAppMenuItems(
     int event_flags) {
+  // Return an empty item list to avoid showing an application menu.
   return ash::ShelfAppMenuItemList();
 }
 
+void ArcAppDeferredLauncherItemController::ExecuteCommand(uint32_t command_id,
+                                                          int event_flags) {
+  // This delegate does not support showing an application menu.
+  NOTIMPLEMENTED();
+}
+
 void ArcAppDeferredLauncherItemController::Close() {
   if (host_)
     host_->Close(app_id());
diff --git a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h
index afe255d..bcebea5 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h
@@ -38,6 +38,7 @@
                                 int64_t display_id,
                                 ash::ShelfLaunchSource source) override;
   ash::ShelfAppMenuItemList GetAppMenuItems(int event_flags) override;
+  void ExecuteCommand(uint32_t command_id, int event_flags) override;
   void Close() override;
 
  private:
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc
index a5dea34..e84941fc 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc
@@ -10,7 +10,6 @@
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/launcher_controller_helper.h"
 #include "ui/aura/window.h"
@@ -63,10 +62,11 @@
     size_t i = std::distance(windows().begin(), it);
     gfx::Image image;
     aura::Window* window = (*it)->GetNativeWindow();
-    items.push_back(base::MakeUnique<ChromeLauncherAppMenuItemV2App>(
+    items.push_back(base::MakeUnique<ash::ShelfApplicationMenuItem>(
+        base::checked_cast<uint32_t>(i),
         ((window && !window->GetTitle().empty()) ? window->GetTitle()
                                                  : app_title),
-        &image, app_id(), launcher_controller(), i));
+        &image));
   }
   return items;
 }
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.h
index c07897f..b83629c 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.h
@@ -13,6 +13,7 @@
 
 class ChromeLauncherController;
 
+// Shelf item delegate for ARC app windows.
 class ArcAppWindowLauncherItemController
     : public AppWindowLauncherItemController {
  public:
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
index 4efb236..a1612bed 100644
--- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h"
 
+#include <limits>
 #include <vector>
 
 #include "ash/common/shelf/shelf_delegate.h"
@@ -15,12 +16,12 @@
 #include "ash/resources/grit/ash_resources.h"
 #include "ash/wm/window_util.h"
 #include "base/memory/ptr_util.h"
+#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h"
 #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
+#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -33,17 +34,24 @@
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/strings/grit/components_strings.h"
+#include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/url_constants.h"
 #include "ui/aura/window.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/events/event.h"
+#include "ui/events/event_constants.h"
 #include "ui/gfx/image/image.h"
 #include "ui/wm/core/window_animations.h"
 
 namespace {
 
+// The maximum number of browser or tab items supported in the application menu.
+constexpr uint16_t kMaxItems = std::numeric_limits<uint16_t>::max();
+// The tab-index flag for browser window menu items that do not specify a tab.
+constexpr uint16_t kNoTab = std::numeric_limits<uint16_t>::max();
+
 bool IsSettingsBrowser(Browser* browser) {
   // Normally this test is sufficient. TODO(stevenjb): Replace this with a
   // better mechanism (Settings WebUI or Browser type).
@@ -58,6 +66,44 @@
   return false;
 }
 
+// Returns a 32-bit command id from 16-bit browser and web-contents indices.
+uint32_t GetCommandId(uint16_t browser_index, uint16_t web_contents_index) {
+  return (browser_index << 16) | web_contents_index;
+}
+
+// Get the 16-bit browser index from a 32-bit command id.
+uint16_t GetBrowserIndex(uint32_t command_id) {
+  return base::checked_cast<uint16_t>((command_id >> 16) & 0xFFFF);
+}
+
+// Get the 16-bit web-contents index from a 32-bit command id.
+uint16_t GetWebContentsIndex(uint32_t command_id) {
+  return base::checked_cast<uint16_t>(command_id & 0xFFFF);
+}
+
+// Check if the given |web_contents| is in incognito mode.
+bool IsIncognito(content::WebContents* web_contents) {
+  const Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  return profile->IsOffTheRecord() && !profile->IsGuestSession();
+}
+
+// Get the favicon for the browser list entry for |web_contents|.
+// Note that for incognito windows the incognito icon will be returned.
+gfx::Image GetBrowserListIcon(content::WebContents* web_contents) {
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  return rb.GetImageNamed(IsIncognito(web_contents)
+                              ? IDR_ASH_SHELF_LIST_INCOGNITO_BROWSER
+                              : IDR_ASH_SHELF_LIST_BROWSER);
+}
+
+// Get the title for the browser list entry for |web_contents|.
+// If |web_contents| has not loaded, returns "New Tab".
+base::string16 GetBrowserListTitle(content::WebContents* web_contents) {
+  const base::string16& title = web_contents->GetTitle();
+  return title.empty() ? l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE) : title;
+}
+
 }  // namespace
 
 BrowserShortcutLauncherItemController::BrowserShortcutLauncherItemController(
@@ -167,41 +213,79 @@
 
 ash::ShelfAppMenuItemList
 BrowserShortcutLauncherItemController::GetAppMenuItems(int event_flags) {
+  browser_menu_items_.clear();
+  registrar_.RemoveAll();
+
   ash::ShelfAppMenuItemList items;
   bool found_tabbed_browser = false;
   for (auto* browser : GetListOfActiveBrowsers()) {
+    if (browser_menu_items_.size() >= kMaxItems)
+      break;
     TabStripModel* tab_strip = browser->tab_strip_model();
-    if (tab_strip->active_index() == -1)
+    const int tab_index = tab_strip->active_index();
+    if (tab_index < 0 || tab_index >= kMaxItems)
       continue;
     if (browser->is_type_tabbed())
       found_tabbed_browser = true;
     if (!(event_flags & ui::EF_SHIFT_DOWN)) {
-      content::WebContents* web_contents =
-          tab_strip->GetWebContentsAt(tab_strip->active_index());
-      gfx::Image app_icon = GetBrowserListIcon(web_contents);
-      base::string16 title = GetBrowserListTitle(web_contents);
-      items.push_back(base::MakeUnique<ChromeLauncherAppMenuItemBrowser>(
-          title, &app_icon, browser));
+      content::WebContents* tab = tab_strip->GetWebContentsAt(tab_index);
+      gfx::Image icon = GetBrowserListIcon(tab);
+      base::string16 title = GetBrowserListTitle(tab);
+      items.push_back(base::MakeUnique<ash::ShelfApplicationMenuItem>(
+          GetCommandId(browser_menu_items_.size(), kNoTab), title, &icon));
     } else {
-      for (int index = 0; index  < tab_strip->count(); ++index) {
-        content::WebContents* web_contents =
-            tab_strip->GetWebContentsAt(index);
-        gfx::Image app_icon =
-            launcher_controller()->GetAppListIcon(web_contents);
-        base::string16 title =
-            launcher_controller()->GetAppListTitle(web_contents);
-        items.push_back(base::MakeUnique<ChromeLauncherAppMenuItemTab>(
-            title, &app_icon, web_contents));
+      for (uint16_t i = 0; i < tab_strip->count() && i < kMaxItems; ++i) {
+        content::WebContents* tab = tab_strip->GetWebContentsAt(i);
+        gfx::Image icon = launcher_controller()->GetAppListIcon(tab);
+        base::string16 title = launcher_controller()->GetAppListTitle(tab);
+        items.push_back(base::MakeUnique<ash::ShelfApplicationMenuItem>(
+            GetCommandId(browser_menu_items_.size(), i), title, &icon));
       }
     }
+    browser_menu_items_.push_back(browser);
+    registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSING,
+                   content::Source<Browser>(browser));
   }
   // If only windowed applications are open, we return an empty list to
   // enforce the creation of a new browser.
-  if (!found_tabbed_browser)
+  if (!found_tabbed_browser) {
     items.clear();
+    browser_menu_items_.clear();
+    registrar_.RemoveAll();
+  }
   return items;
 }
 
+void BrowserShortcutLauncherItemController::ExecuteCommand(uint32_t command_id,
+                                                           int event_flags) {
+  const uint16_t browser_index = GetBrowserIndex(command_id);
+  // Check that the index is valid and the browser has not been closed.
+  if (browser_index < browser_menu_items_.size() &&
+      browser_menu_items_[browser_index]) {
+    Browser* browser = browser_menu_items_[browser_index];
+    TabStripModel* tab_strip = browser->tab_strip_model();
+    const uint16_t tab_index = GetWebContentsIndex(command_id);
+    if (event_flags & (ui::EF_SHIFT_DOWN | ui::EF_MIDDLE_MOUSE_BUTTON)) {
+      if (tab_index == kNoTab) {
+        tab_strip->CloseAllTabs();
+      } else if (tab_strip->ContainsIndex(tab_index)) {
+        tab_strip->CloseWebContentsAt(tab_index,
+                                      TabStripModel::CLOSE_USER_GESTURE);
+      }
+    } else {
+      multi_user_util::MoveWindowToCurrentDesktop(
+          browser->window()->GetNativeWindow());
+      if (tab_index != kNoTab && tab_strip->ContainsIndex(tab_index))
+        tab_strip->ActivateTabAt(tab_index, false);
+      browser->window()->Show();
+      browser->window()->Activate();
+    }
+  }
+
+  browser_menu_items_.clear();
+  registrar_.RemoveAll();
+}
+
 void BrowserShortcutLauncherItemController::Close() {
   for (auto* browser : GetListOfActiveBrowsers())
     browser->window()->Close();
@@ -211,29 +295,6 @@
   return GetListOfActiveBrowsers().empty();
 }
 
-gfx::Image BrowserShortcutLauncherItemController::GetBrowserListIcon(
-    content::WebContents* web_contents) const {
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  return rb.GetImageNamed(IsIncognito(web_contents) ?
-      IDR_ASH_SHELF_LIST_INCOGNITO_BROWSER :
-      IDR_ASH_SHELF_LIST_BROWSER);
-}
-
-base::string16 BrowserShortcutLauncherItemController::GetBrowserListTitle(
-    content::WebContents* web_contents) const {
-  base::string16 title = web_contents->GetTitle();
-  if (!title.empty())
-    return title;
-  return l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
-}
-
-bool BrowserShortcutLauncherItemController::IsIncognito(
-    content::WebContents* web_contents) const {
-  const Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
-  return profile->IsOffTheRecord() && !profile->IsGuestSession();
-}
-
 ash::ShelfAction
 BrowserShortcutLauncherItemController::ActivateOrAdvanceToNextBrowser() {
   // Create a list of all suitable running browsers.
@@ -323,3 +384,19 @@
   }
   return active_browsers;
 }
+
+void BrowserShortcutLauncherItemController::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  DCHECK_EQ(chrome::NOTIFICATION_BROWSER_CLOSING, type);
+  Browser* browser = content::Source<Browser>(source).ptr();
+  DCHECK(browser);
+  BrowserList::BrowserVector::iterator item = std::find(
+      browser_menu_items_.begin(), browser_menu_items_.end(), browser);
+  DCHECK(item != browser_menu_items_.end());
+  // Clear the entry for the closed browser and leave other indices intact.
+  *item = nullptr;
+  registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_CLOSING,
+                    content::Source<Browser>(browser));
+}
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h
index 8c41068..987b540 100644
--- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h
@@ -8,6 +8,8 @@
 #include "base/macros.h"
 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
 #include "chrome/browser/ui/browser_list.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 
 namespace ash {
 class ShelfModel;
@@ -17,15 +19,13 @@
 class WebContents;
 }
 
-namespace gfx {
-class Image;
-}
-
-class Browser;
 class ChromeLauncherController;
 
-// Item controller for an browser shortcut.
-class BrowserShortcutLauncherItemController : public LauncherItemController {
+// Shelf item delegate for a browser shortcut; only one such item should exist.
+// This item shows an application menu that lists open browser windows or tabs.
+class BrowserShortcutLauncherItemController
+    : public LauncherItemController,
+      public content::NotificationObserver {
  public:
   BrowserShortcutLauncherItemController(ChromeLauncherController* controller,
                                         ash::ShelfModel* shelf_model);
@@ -48,20 +48,10 @@
                                 int64_t display_id,
                                 ash::ShelfLaunchSource source) override;
   ash::ShelfAppMenuItemList GetAppMenuItems(int event_flags) override;
+  void ExecuteCommand(uint32_t command_id, int event_flags) override;
   void Close() override;
 
  private:
-  // Get the favicon for the browser list entry for |web_contents|.
-  // Note that for incognito windows the incognito icon will be returned.
-  gfx::Image GetBrowserListIcon(content::WebContents* web_contents) const;
-
-  // Get the title for the browser list entry for |web_contents|.
-  // If |web_contents| has not loaded, returns "Net Tab".
-  base::string16 GetBrowserListTitle(content::WebContents* web_contents) const;
-
-  // Check if the given |web_contents| is in incognito mode.
-  bool IsIncognito(content::WebContents* web_contents) const;
-
   // Activate a browser - or advance to the next one on the list.
   // Returns the action performed. Should be one of SHELF_ACTION_NONE,
   // SHELF_ACTION_WINDOW_ACTIVATED, or SHELF_ACTION_NEW_WINDOW_CREATED.
@@ -74,8 +64,19 @@
   // Get a list of active browsers.
   BrowserList::BrowserVector GetListOfActiveBrowsers();
 
+  // content::NotificationObserver:
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
+
   ash::ShelfModel* shelf_model_;
 
+  // The cached list of open browser windows shown in an application menu.
+  BrowserList::BrowserVector browser_menu_items_;
+
+  // Registers for notifications of closing browser windows.
+  content::NotificationRegistrar registrar_;
+
   DISALLOW_COPY_AND_ASSIGN(BrowserShortcutLauncherItemController);
 };
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc
deleted file mode 100644
index c217f9c..0000000
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h"
-
-#include "ash/wm/window_util.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "content/public/browser/notification_service.h"
-#include "ui/events/event_constants.h"
-
-ChromeLauncherAppMenuItemBrowser::ChromeLauncherAppMenuItemBrowser(
-    const base::string16 title,
-    const gfx::Image* icon,
-    Browser* browser)
-    : ash::ShelfApplicationMenuItem(title, icon), browser_(browser) {
-  DCHECK(browser);
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_BROWSER_CLOSING,
-                 content::Source<Browser>(browser));
-}
-
-ChromeLauncherAppMenuItemBrowser::~ChromeLauncherAppMenuItemBrowser() {}
-
-void ChromeLauncherAppMenuItemBrowser::Execute(int event_flags) {
-  if (browser_) {
-    if (event_flags & (ui::EF_SHIFT_DOWN | ui::EF_MIDDLE_MOUSE_BUTTON)) {
-      TabStripModel* tab_strip = browser_->tab_strip_model();
-      tab_strip->CloseAllTabs();
-    } else {
-      // In ChromeOS multiprofile scenario we might need to teleport the window
-      // back to the current user desktop.
-      multi_user_util::MoveWindowToCurrentDesktop(
-          browser_->window()->GetNativeWindow());
-      browser_->window()->Show();
-      ash::wm::ActivateWindow(browser_->window()->GetNativeWindow());
-    }
-  }
-}
-
-void ChromeLauncherAppMenuItemBrowser::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_BROWSER_CLOSING, type);
-  DCHECK_EQ(browser_, content::Source<Browser>(source).ptr());
-  registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_CLOSING,
-                    content::Source<Browser>(browser_));
-  browser_ = nullptr;
-}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h
deleted file mode 100644
index f1d70786..0000000
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_BROWSER_H_
-#define CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_BROWSER_H_
-
-#include "ash/public/cpp/shelf_application_menu_item.h"
-#include "base/macros.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-
-class Browser;
-
-// A shelf application menu item for a running browser.
-class ChromeLauncherAppMenuItemBrowser : public ash::ShelfApplicationMenuItem,
-                                         public content::NotificationObserver {
- public:
-  ChromeLauncherAppMenuItemBrowser(const base::string16 title,
-                                   const gfx::Image* icon,
-                                   Browser* browser);
-  ~ChromeLauncherAppMenuItemBrowser() override;
-
-  // ash::ShelfApplicationMenuItem:
-  void Execute(int event_flags) override;
-
- private:
-  // content::NotificationObserver.
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
-  // The browser which is associated which this item.
-  Browser* browser_;
-
-  content::NotificationRegistrar registrar_;
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeLauncherAppMenuItemBrowser);
-};
-
-#endif  // CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_BROWSER_H_
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc
deleted file mode 100644
index 956b621..0000000
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h"
-
-#include "ash/wm/window_util.h"
-#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "ui/events/event_constants.h"
-
-ChromeLauncherAppMenuItemTab::ChromeLauncherAppMenuItemTab(
-    const base::string16 title,
-    const gfx::Image* icon,
-    content::WebContents* content)
-    : ash::ShelfApplicationMenuItem(title, icon),
-      content::WebContentsObserver(content) {}
-
-void ChromeLauncherAppMenuItemTab::Execute(int event_flags) {
-  if (!web_contents())
-    return;
-  Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
-  if (!browser)
-    return;
-  TabStripModel* tab_strip = browser->tab_strip_model();
-  int index = tab_strip->GetIndexOfWebContents(web_contents());
-  DCHECK_NE(index, TabStripModel::kNoTab);
-  if (event_flags & (ui::EF_SHIFT_DOWN | ui::EF_MIDDLE_MOUSE_BUTTON)) {
-    tab_strip->CloseWebContentsAt(index, TabStripModel::CLOSE_USER_GESTURE);
-  } else {
-    // In ChromeOS multiprofile scenario we might need to teleport the window
-    // back to the current user desktop.
-    multi_user_util::MoveWindowToCurrentDesktop(
-        browser->window()->GetNativeWindow());
-    tab_strip->ActivateTabAt(index, false);
-    browser->window()->Show();
-    // Need this check to prevent unit tests from crashing.
-    if (browser->window()->GetNativeWindow())
-      ash::wm::ActivateWindow(browser->window()->GetNativeWindow());
-  }
-}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h
deleted file mode 100644
index 00e8336..0000000
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_TAB_H_
-#define CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_TAB_H_
-
-#include "ash/public/cpp/shelf_application_menu_item.h"
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "content/public/browser/web_contents_observer.h"
-
-namespace content{
-class WebContents;
-}
-
-// A shelf application menu item for a running browser tab.
-class ChromeLauncherAppMenuItemTab : public ash::ShelfApplicationMenuItem,
-                                     public content::WebContentsObserver {
- public:
-  ChromeLauncherAppMenuItemTab(const base::string16 title,
-                               const gfx::Image* icon,
-                               content::WebContents* content);
-
-  // ash::ShelfApplicationMenuItem:
-  void Execute(int event_flags) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ChromeLauncherAppMenuItemTab);
-};
-
-#endif  // CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_TAB_H_
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc
deleted file mode 100644
index bfa30180..0000000
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h"
-
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
-
-ChromeLauncherAppMenuItemV2App::ChromeLauncherAppMenuItemV2App(
-    const base::string16 title,
-    const gfx::Image* icon,
-    const std::string& app_id,
-    ChromeLauncherController* launcher_controller,
-    int app_index)
-    : ash::ShelfApplicationMenuItem(title, icon),
-      launcher_controller_(launcher_controller),
-      app_id_(app_id),
-      app_index_(app_index) {}
-
-ChromeLauncherAppMenuItemV2App::~ChromeLauncherAppMenuItemV2App() {}
-
-void ChromeLauncherAppMenuItemV2App::Execute(int event_flags) {
-  // Note: At this time there is only a single app running at any point. as
-  // such we will never come here with usable |event_flags|. If that ever
-  // changes we should add some special close code here.
-  // Note: If the application item did go away since the menu was created,
-  // The controller will take care of it.
-  launcher_controller_->ActivateShellApp(app_id_, app_index_);
-}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h
deleted file mode 100644
index 82f2a82..0000000
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_V2APP_H_
-#define CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_V2APP_H_
-
-#include <string>
-
-#include "ash/public/cpp/shelf_application_menu_item.h"
-#include "base/macros.h"
-
-class ChromeLauncherController;
-
-// A shelf application menu item for a running V2 application.
-class ChromeLauncherAppMenuItemV2App : public ash::ShelfApplicationMenuItem {
- public:
-  ChromeLauncherAppMenuItemV2App(const base::string16 title,
-                                 const gfx::Image* icon,
-                                 const std::string& app_id,
-                                 ChromeLauncherController* launcher_controller,
-                                 int app_index);
-  ~ChromeLauncherAppMenuItemV2App() override;
-
-  // ash::ShelfApplicationMenuItem:
-  void Execute(int event_flags) override;
-
- private:
-  // The owning class which can be used to validate the controller.
-  ChromeLauncherController* launcher_controller_;
-
-  // The application ID.
-  const std::string app_id_;
-
-  // The index for the given application.
-  const int app_index_;
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeLauncherAppMenuItemV2App);
-};
-
-#endif  // CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_V2APP_H_
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
index 9bba9a4..fb29db9 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -180,10 +180,8 @@
   virtual void AdditionalUserAddedToSession(Profile* profile) = 0;
 
   // Get the list of all running incarnations of this item.
-  // |event_flags| specifies the flags which were set by the event which
-  // triggered this menu generation. It can be used to generate different lists.
-  virtual ash::ShelfAppMenuItemList GetAppMenuItems(const ash::ShelfItem& item,
-                                                    int event_flags) = 0;
+  virtual ash::ShelfAppMenuItemList GetAppMenuItemsForTesting(
+      const ash::ShelfItem& item) = 0;
 
   // Get the list of all tabs which belong to a certain application type.
   virtual std::vector<content::WebContents*> GetV1ApplicationsFromAppId(
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc
index 37a4800..fa29d04 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc
@@ -48,8 +48,6 @@
 #include "chrome/browser/ui/ash/launcher/arc_app_window_launcher_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_browser.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h"
 #include "chrome/browser/ui/ash/launcher/launcher_arc_app_updater.h"
 #include "chrome/browser/ui/ash/launcher/launcher_controller_helper.h"
@@ -617,11 +615,11 @@
     controller->AdditionalUserAddedToSession(profile);
 }
 
-ash::ShelfAppMenuItemList ChromeLauncherControllerImpl::GetAppMenuItems(
-    const ash::ShelfItem& item,
-    int event_flags) {
+ash::ShelfAppMenuItemList
+ChromeLauncherControllerImpl::GetAppMenuItemsForTesting(
+    const ash::ShelfItem& item) {
   LauncherItemController* controller = GetLauncherItemController(item.id);
-  return controller ? controller->GetAppMenuItems(event_flags)
+  return controller ? controller->GetAppMenuItems(ui::EF_NONE)
                     : ash::ShelfAppMenuItemList();
 }
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h
index 148f3141..037a222 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h
@@ -95,8 +95,8 @@
       bool allow_minimize) override;
   void ActiveUserChanged(const std::string& user_email) override;
   void AdditionalUserAddedToSession(Profile* profile) override;
-  ash::ShelfAppMenuItemList GetAppMenuItems(const ash::ShelfItem& item,
-                                            int event_flags) override;
+  ash::ShelfAppMenuItemList GetAppMenuItemsForTesting(
+      const ash::ShelfItem& item) override;
   std::vector<content::WebContents*> GetV1ApplicationsFromAppId(
       const std::string& app_id) override;
   void ActivateShellApp(const std::string& app_id, int window_index) override;
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
index 8f7d0e4..f77b2af 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
@@ -552,21 +552,21 @@
   ash::ShelfID item_id = item1.id;
   EXPECT_EQ(ash::TYPE_APP, item1.type);
   EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
-  EXPECT_EQ(1u, controller_->GetAppMenuItems(item1, 0).size());  // 1 window
+  EXPECT_EQ(1u, controller_->GetAppMenuItemsForTesting(item1).size());
 
   // Add a second window; confirm the shelf item stays; check the app menu.
   AppWindow* window2 = CreateAppWindow(browser()->profile(), extension);
   ASSERT_EQ(item_count + 1, shelf_model()->item_count());
   const ash::ShelfItem& item2 = *shelf_model()->ItemByID(item_id);
   EXPECT_EQ(ash::STATUS_ACTIVE, item2.status);
-  EXPECT_EQ(2u, controller_->GetAppMenuItems(item2, 0).size());  // 2 windows
+  EXPECT_EQ(2u, controller_->GetAppMenuItemsForTesting(item2).size());
 
   // Close the second window; confirm the shelf item stays; check the app menu.
   CloseAppWindow(window2);
   ASSERT_EQ(item_count + 1, shelf_model()->item_count());
   const ash::ShelfItem& item3 = *shelf_model()->ItemByID(item_id);
   EXPECT_EQ(ash::STATUS_ACTIVE, item3.status);
-  EXPECT_EQ(1u, controller_->GetAppMenuItems(item3, 0).size());  // 1 window
+  EXPECT_EQ(1u, controller_->GetAppMenuItemsForTesting(item3).size());
 
   // Close the first window; the shelf item should be removed.
   CloseAppWindow(window1);
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
index 600263f..4b5b8ad5 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
@@ -270,11 +270,12 @@
   ash::ShelfAppMenuItemList GetAppMenuItems(int event_flags) override {
     ash::ShelfAppMenuItemList items;
     items.push_back(
-        base::MakeUnique<ash::ShelfApplicationMenuItem>(base::string16()));
+        base::MakeUnique<ash::ShelfApplicationMenuItem>(0, base::string16()));
     items.push_back(
-        base::MakeUnique<ash::ShelfApplicationMenuItem>(base::string16()));
+        base::MakeUnique<ash::ShelfApplicationMenuItem>(1, base::string16()));
     return items;
   }
+  void ExecuteCommand(uint32_t command_id, int event_flags) override {}
   void Close() override {}
 
  private:
@@ -2812,7 +2813,7 @@
                   const ash::ShelfItem& item,
                   size_t expected_item_count,
                   base::string16 expected_item_titles[]) {
-  ash::ShelfAppMenuItemList items = controller->GetAppMenuItems(item, 0);
+  ash::ShelfAppMenuItemList items = controller->GetAppMenuItemsForTesting(item);
   ASSERT_EQ(expected_item_count, items.size());
   for (size_t i = 0; i < expected_item_count; i++)
     EXPECT_EQ(expected_item_titles[i], items[i]->title());
@@ -3264,12 +3265,17 @@
   item_gmail.id = gmail_id;
   base::string16 two_menu_items[] = {title1, title2};
   CheckAppMenu(launcher_controller_.get(), item_gmail, 2, two_menu_items);
+  LauncherItemController* item_controller =
+      launcher_controller_->GetLauncherItemController(gmail_id);
+  ASSERT_TRUE(item_controller);
   EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
   // Execute the second item in the menu, after the title and two separators,
   // this shouldn't do anything since that item is already the active tab.
   {
     ash::ShelfApplicationMenuModel menu(
-        base::string16(), launcher_controller_->GetAppMenuItems(item_gmail, 0));
+        base::string16(),
+        launcher_controller_->GetAppMenuItemsForTesting(item_gmail),
+        item_controller);
     menu.ActivatedAt(4);
   }
   EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
@@ -3278,7 +3284,9 @@
   // this should activate the other tab.
   {
     ash::ShelfApplicationMenuModel menu(
-        base::string16(), launcher_controller_->GetAppMenuItems(item_gmail, 0));
+        base::string16(),
+        launcher_controller_->GetAppMenuItemsForTesting(item_gmail),
+        item_controller);
     menu.ActivatedAt(3);
   }
   EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
@@ -3306,20 +3314,23 @@
   base::string16 two_menu_items[] = {title1, title2};
   CheckAppMenu(launcher_controller_.get(), item_gmail, 2, two_menu_items);
 
+  LauncherItemController* item_controller =
+      launcher_controller_->GetLauncherItemController(gmail_id);
+  ASSERT_TRUE(item_controller);
   int tabs = browser()->tab_strip_model()->count();
   // Activate the proper tab through the menu item.
   {
     ash::ShelfAppMenuItemList items =
-        launcher_controller_->GetAppMenuItems(item_gmail, 0);
-    items[1]->Execute(0);
+        launcher_controller_->GetAppMenuItemsForTesting(item_gmail);
+    item_controller->ExecuteCommand(items[1]->command_id(), ui::EF_NONE);
     EXPECT_EQ(tabs, browser()->tab_strip_model()->count());
   }
 
   // Delete one tab through the menu item.
   {
     ash::ShelfAppMenuItemList items =
-        launcher_controller_->GetAppMenuItems(item_gmail, 0);
-    items[1]->Execute(ui::EF_SHIFT_DOWN);
+        launcher_controller_->GetAppMenuItemsForTesting(item_gmail);
+    item_controller->ExecuteCommand(items[1]->command_id(), ui::EF_SHIFT_DOWN);
     EXPECT_EQ(--tabs, browser()->tab_strip_model()->count());
   }
 }
@@ -3397,7 +3408,8 @@
   ash::ShelfItem item_gmail;
   item_gmail.type = ash::TYPE_APP_SHORTCUT;
   item_gmail.id = gmail_id;
-  EXPECT_EQ(1U, launcher_controller_->GetAppMenuItems(item_gmail, 0).size());
+  EXPECT_EQ(1U,
+            launcher_controller_->GetAppMenuItemsForTesting(item_gmail).size());
 }
 
 // Tests that the Gmail extension does not match the offline verison.
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc
index 6ecbd4de..0136890f 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc
@@ -38,7 +38,7 @@
     controller_->LaunchApp(ash::AppLauncherId(app_id_),
                            ash::LAUNCH_FROM_UNKNOWN, ui::EF_NONE);
   }
-  void ExecuteCommand(uint32_t command_id, int32_t event_flags) override {
+  void ExecuteCommand(uint32_t command_id, int event_flags) override {
     NOTIMPLEMENTED();
   }
   void ItemPinned() override { NOTIMPLEMENTED(); }
@@ -182,9 +182,9 @@
   NOTIMPLEMENTED();
 }
 
-ash::ShelfAppMenuItemList ChromeLauncherControllerMus::GetAppMenuItems(
-    const ash::ShelfItem& item,
-    int event_flags) {
+ash::ShelfAppMenuItemList
+ChromeLauncherControllerMus::GetAppMenuItemsForTesting(
+    const ash::ShelfItem& item) {
   NOTIMPLEMENTED();
   return ash::ShelfAppMenuItemList();
 }
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h
index 9f1f248..c36de2b 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h
@@ -54,8 +54,8 @@
       bool allow_minimize) override;
   void ActiveUserChanged(const std::string& user_email) override;
   void AdditionalUserAddedToSession(Profile* profile) override;
-  ash::ShelfAppMenuItemList GetAppMenuItems(const ash::ShelfItem& item,
-                                            int event_flags) override;
+  ash::ShelfAppMenuItemList GetAppMenuItemsForTesting(
+      const ash::ShelfItem& item) override;
   std::vector<content::WebContents*> GetV1ApplicationsFromAppId(
       const std::string& app_id) override;
   void ActivateShellApp(const std::string& app_id, int window_index) override;
diff --git a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc
index c783d8f..e885823a 100644
--- a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc
@@ -8,45 +8,21 @@
 #include "ash/wm/window_state_aura.h"
 #include "ash/wm/window_util.h"
 #include "base/memory/ptr_util.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
 #include "components/favicon/content/content_favicon_driver.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/app_window/app_window.h"
+#include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/browser/app_window/native_app_window.h"
-#include "skia/ext/image_operations.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/events/event.h"
-#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image.h"
 #include "ui/wm/core/window_animations.h"
 
-namespace {
-
-// Size of the icon in the shelf launcher in display-independent pixels.
-const int kAppListIconSize = 24;
-
-// This will return a slightly smaller icon than the app icon to be used in
-// the application list menu.
-gfx::Image GetAppListIcon(extensions::AppWindow* app_window) {
-  // TODO(skuhne): We instead might want to use LoadImages in
-  // AppWindow::UpdateExtensionAppIcon() to let the extension give us
-  // pre-defined icons in the launcher and the launcher list sizes. Since there
-  // is no mock yet, doing this now seems a bit premature and we scale for the
-  // time being.
-  if (app_window->app_icon().IsEmpty())
-    return gfx::Image();
-
-  SkBitmap bmp = skia::ImageOperations::Resize(
-      *app_window->app_icon().ToSkBitmap(), skia::ImageOperations::RESIZE_BEST,
-      kAppListIconSize, kAppListIconSize);
-  return gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(bmp));
-}
-
-}  // namespace
-
 ExtensionAppWindowLauncherItemController::
     ExtensionAppWindowLauncherItemController(
         const std::string& app_id,
@@ -60,45 +36,39 @@
 void ExtensionAppWindowLauncherItemController::AddAppWindow(
     extensions::AppWindow* app_window) {
   DCHECK(!app_window->window_type_is_panel());
-  DCHECK(window_to_app_window_.find(app_window->GetBaseWindow()) ==
-         window_to_app_window_.end());
   AddWindow(app_window->GetBaseWindow());
-  window_to_app_window_[app_window->GetBaseWindow()] = app_window;
 }
 
 ash::ShelfAppMenuItemList
 ExtensionAppWindowLauncherItemController::GetAppMenuItems(int event_flags) {
   ash::ShelfAppMenuItemList items;
-  int index = 0;
-  for (const auto* window : windows()) {
-    extensions::AppWindow* app_window = window_to_app_window_[window];
+  extensions::AppWindowRegistry* app_window_registry =
+      extensions::AppWindowRegistry::Get(launcher_controller()->profile());
+
+  uint32_t window_index = 0;
+  for (const ui::BaseWindow* window : windows()) {
+    extensions::AppWindow* app_window =
+        app_window_registry->GetAppWindowForNativeWindow(
+            window->GetNativeWindow());
     DCHECK(app_window);
 
-    // If the app's web contents provides a favicon, use it. Otherwise, use a
-    // scaled down app icon.
+    // Use the app's web contents favicon, or the app window's icon.
     favicon::FaviconDriver* favicon_driver =
         favicon::ContentFaviconDriver::FromWebContents(
             app_window->web_contents());
-    gfx::Image result = favicon_driver->GetFavicon();
-    if (result.IsEmpty())
-      result = GetAppListIcon(app_window);
+    gfx::Image icon = favicon_driver->GetFavicon();
+    if (icon.IsEmpty())
+      icon = app_window->app_icon();
 
-    items.push_back(base::MakeUnique<ChromeLauncherAppMenuItemV2App>(
-        app_window->GetTitle(),
-        &result,  // Will be copied
-        app_id(), launcher_controller(), index));
-    ++index;
+    items.push_back(base::MakeUnique<ash::ShelfApplicationMenuItem>(
+        window_index, app_window->GetTitle(), &icon));
+    ++window_index;
   }
   return items;
 }
 
-void ExtensionAppWindowLauncherItemController::OnWindowRemoved(
-    ui::BaseWindow* window) {
-  WindowToAppWindow::iterator it = window_to_app_window_.find(window);
-  if (it == window_to_app_window_.end()) {
-    NOTREACHED();
-    return;
-  }
-
-  window_to_app_window_.erase(it);
+void ExtensionAppWindowLauncherItemController::ExecuteCommand(
+    uint32_t command_id,
+    int event_flags) {
+  launcher_controller()->ActivateShellApp(app_id(), command_id);
 }
diff --git a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.h
index 514dbf3..c8085f1 100644
--- a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_ASH_LAUNCHER_EXTENSION_APP_WINDOW_LAUNCHER_ITEM_CONTROLLER_H_
 #define CHROME_BROWSER_UI_ASH_LAUNCHER_EXTENSION_APP_WINDOW_LAUNCHER_ITEM_CONTROLLER_H_
 
-#include <map>
 #include <string>
 
 #include "base/macros.h"
@@ -17,6 +16,7 @@
 
 class ChromeLauncherController;
 
+// Shelf item delegate for extension app windows.
 class ExtensionAppWindowLauncherItemController
     : public AppWindowLauncherItemController {
  public:
@@ -29,19 +29,11 @@
 
   void AddAppWindow(extensions::AppWindow* app_window);
 
-  // LauncherItemController overrides:
-  ash::ShelfAppMenuItemList GetAppMenuItems(int event_flags) override;
-
- protected:
   // AppWindowLauncherItemController:
-  void OnWindowRemoved(ui::BaseWindow* window) override;
+  ash::ShelfAppMenuItemList GetAppMenuItems(int event_flags) override;
+  void ExecuteCommand(uint32_t command_id, int event_flags) override;
 
  private:
-  using WindowToAppWindow =
-      std::map<const ui::BaseWindow*, extensions::AppWindow*>;
-
-  WindowToAppWindow window_to_app_window_;
-
   DISALLOW_COPY_AND_ASSIGN(ExtensionAppWindowLauncherItemController);
 };